From 3b5149abffed62b00d67467928b34042b87b03f4 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Mon, 17 Jun 2024 18:09:30 -0400 Subject: [PATCH] Environmental Variable & Logging Refactor --- launcher/CMakeLists.txt | 4 +- launcher/src/bootstrap.cpp | 45 ++--- launcher/src/client/cache.cpp | 12 +- launcher/src/client/configuration.cpp | 26 ++- .../src/{crash-report.c => crash-report.cpp} | 168 +++++++++--------- launcher/src/crash-report.h | 1 - launcher/src/main.cpp | 94 ++++------ launcher/src/mods.cpp | 5 +- launcher/src/options/option-list.h | 2 +- launcher/src/options/parser.cpp | 11 +- launcher/src/patchelf.cpp | 12 +- launcher/src/sdk.cpp | 2 +- launcher/src/util.c | 39 ---- launcher/src/util.cpp | 41 +++++ launcher/src/util.h | 13 +- libreborn/CMakeLists.txt | 16 +- libreborn/include/libreborn/env.h | 16 ++ libreborn/include/libreborn/env_list.h | 24 +++ libreborn/include/libreborn/exec.h | 5 - libreborn/include/libreborn/libreborn.h | 1 + libreborn/include/libreborn/log.h | 5 +- libreborn/include/libreborn/util.h | 6 +- libreborn/src/util/env.c | 20 +++ libreborn/src/util/exec.c | 45 +---- libreborn/src/util/log.c | 23 +-- libreborn/src/util/util.c | 25 ++- media-layer/extras/src/SDL.c | 6 - mods/include/mods/init/init.h | 1 + mods/src/benchmark/benchmark.cpp | 2 +- mods/src/compat/compat.cpp | 5 +- mods/src/feature/feature.cpp | 2 +- mods/src/home/home.cpp | 13 +- mods/src/init/init.cpp | 1 + mods/src/misc/misc.cpp | 6 +- mods/src/options/options.cpp | 4 +- mods/src/override/override.cpp | 20 ++- mods/src/screenshot/screenshot.cpp | 24 +-- mods/src/server/server.cpp | 8 +- mods/src/skin/loader.cpp | 2 +- 39 files changed, 382 insertions(+), 373 deletions(-) rename launcher/src/{crash-report.c => crash-report.cpp} (61%) delete mode 100644 launcher/src/util.c create mode 100644 launcher/src/util.cpp create mode 100644 libreborn/include/libreborn/env.h create mode 100644 libreborn/include/libreborn/env_list.h create mode 100644 libreborn/src/util/env.c diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index f2946033..d06e7355 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -4,8 +4,8 @@ project(launcher) add_executable(launcher src/bootstrap.cpp src/patchelf.cpp - src/util.c - src/crash-report.c + src/util.cpp + src/crash-report.cpp src/sdk.cpp src/mods.cpp src/options/parser.cpp diff --git a/launcher/src/bootstrap.cpp b/launcher/src/bootstrap.cpp index d529c3b3..ea428c53 100644 --- a/launcher/src/bootstrap.cpp +++ b/launcher/src/bootstrap.cpp @@ -41,14 +41,17 @@ static void print_debug_information() { DEBUG("Reborn Version: v%s", MCPI_VERSION); // Architecture - const char *arch = "Unknown"; + const char *arch = #ifdef __x86_64__ - arch = "AMD64"; + "AMD64" #elif defined(__aarch64__) - arch = "ARM64"; + "ARM64" #elif defined(__arm__) - arch = "ARM32"; + "ARM32" +#else + "Unknown" #endif + ; DEBUG("Reborn Target Architecture: %s", arch); } @@ -66,9 +69,7 @@ void bootstrap() { #endif // Get Binary Directory - char *binary_directory_raw = get_binary_directory(); - const std::string binary_directory = binary_directory_raw; - free(binary_directory_raw); + const std::string binary_directory = get_binary_directory(); DEBUG("Binary Directory: %s", binary_directory.c_str()); // Copy SDK @@ -78,24 +79,21 @@ void bootstrap() { // Set MCPI_REBORN_ASSETS_PATH { - char *assets_path = realpath("/proc/self/exe", nullptr); - ALLOC_CHECK(assets_path); - chop_last_component(&assets_path); - string_append(&assets_path, "/data"); - set_and_print_env("MCPI_REBORN_ASSETS_PATH", assets_path); - free(assets_path); + std::string assets_path = safe_realpath("/proc/self/exe"); + chop_last_component(assets_path); + assets_path += "/data"; + set_and_print_env(_MCPI_REBORN_ASSETS_PATH_ENV, assets_path.c_str()); } // Resolve Binary Path & Set MCPI_DIRECTORY - char *resolved_path = nullptr; + std::string game_binary; { // Log DEBUG("Resolving File Paths..."); // Resolve Full Binary Path const std::string full_path = binary_directory + ("/" MCPI_BINARY); - resolved_path = realpath(full_path.c_str(), nullptr); - ALLOC_CHECK(resolved_path); + game_binary = safe_realpath(full_path); } // Fix MCPI Dependencies @@ -113,7 +111,7 @@ void bootstrap() { #endif // Patch - patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path); + patch_mcpi_elf_dependencies(game_binary.c_str(), new_mcpi_exe_path); // Verify if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) { @@ -123,17 +121,12 @@ void bootstrap() { // Set MCPI_VANILLA_ASSETS_PATH { - char *assets_path = strdup(resolved_path); - ALLOC_CHECK(assets_path); - chop_last_component(&assets_path); - string_append(&assets_path, "/data"); - set_and_print_env("MCPI_VANILLA_ASSETS_PATH", assets_path); - free(assets_path); + std::string assets_path = game_binary; + chop_last_component(assets_path); + assets_path += "/data"; + set_and_print_env(_MCPI_VANILLA_ASSETS_PATH_ENV, assets_path.c_str()); } - // Free Resolved Path - free(resolved_path); - // Configure Library Search Path std::string mcpi_ld_path = ""; { diff --git a/launcher/src/client/cache.cpp b/launcher/src/client/cache.cpp index a81259fa..9d028de5 100644 --- a/launcher/src/client/cache.cpp +++ b/launcher/src/client/cache.cpp @@ -13,7 +13,7 @@ // Get Cache Path static std::string get_cache_path() { - const char *home = getenv("HOME"); + const char *home = getenv(_MCPI_HOME_ENV); if (home == nullptr) { IMPOSSIBLE(); } @@ -120,18 +120,18 @@ void save_cache() { stream.write((const char *) &cache_version, 1); // Save Username And Render Distance - write_env_to_stream(stream, "MCPI_USERNAME"); - write_env_to_stream(stream, "MCPI_RENDER_DISTANCE"); + write_env_to_stream(stream, MCPI_USERNAME_ENV); + write_env_to_stream(stream, MCPI_RENDER_DISTANCE_ENV); // Save Feature Flags std::unordered_map flags; load_available_feature_flags([&flags](std::string flag) { - std::string stripped_flag = strip_feature_flag_default(flag, NULL); + std::string stripped_flag = strip_feature_flag_default(flag, nullptr); flags[stripped_flag] = false; }); { - const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS"); - if (enabled_flags == NULL) { + const char *enabled_flags = getenv(MCPI_FEATURE_FLAGS_ENV); + if (enabled_flags == nullptr) { IMPOSSIBLE(); } std::istringstream enabled_flags_stream(enabled_flags); diff --git a/launcher/src/client/configuration.cpp b/launcher/src/client/configuration.cpp index d40e33b7..bd6578b3 100644 --- a/launcher/src/client/configuration.cpp +++ b/launcher/src/client/configuration.cpp @@ -41,12 +41,8 @@ std::string strip_feature_flag_default(const std::string &flag, bool *default_re extern unsigned char available_feature_flags[]; extern size_t available_feature_flags_len; void load_available_feature_flags(const std::function &callback) { - // Get Path - char *binary_directory = get_binary_directory(); - std::string path = std::string(binary_directory) + "/available-feature-flags"; - free(binary_directory); - // Load File - std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len); + // Load Data + const std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len); std::stringstream stream(data); // Store Lines std::vector lines; @@ -68,8 +64,8 @@ void load_available_feature_flags(const std::function &callba // Sort std::sort(lines.begin(), lines.end(), [](const std::string &a, const std::string &b) { // Strip Defaults - std::string stripped_a = strip_feature_flag_default(a, nullptr); - std::string stripped_b = strip_feature_flag_default(b, nullptr); + const std::string stripped_a = strip_feature_flag_default(a, nullptr); + const std::string stripped_b = strip_feature_flag_default(b, nullptr); // Sort return stripped_a < stripped_b; }); @@ -90,7 +86,7 @@ static void run_command_and_set_env(const char *env_name, const char *command[]) char *output = run_command(command, &return_code, nullptr); if (output != nullptr) { // Trim - int length = strlen(output); + const size_t length = strlen(output); if (output[length - 1] == '\n') { output[length - 1] = '\0'; } @@ -164,7 +160,7 @@ void configure_client(const options_t &options) { // --default if (options.use_default) { // Use Default Feature Flags - set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() { + set_env_if_unset(MCPI_FEATURE_FLAGS_ENV, [&cache]() { std::string feature_flags = ""; load_available_feature_flags([&feature_flags, &cache](const std::string &flag) { bool value; @@ -185,10 +181,10 @@ void configure_client(const options_t &options) { } return feature_flags; }); - set_env_if_unset("MCPI_RENDER_DISTANCE", [&cache]() { + set_env_if_unset(MCPI_RENDER_DISTANCE_ENV, [&cache]() { return cache.render_distance; }); - set_env_if_unset("MCPI_USERNAME", [&cache]() { + set_env_if_unset(MCPI_USERNAME_ENV, [&cache]() { return cache.username; }); } @@ -226,7 +222,7 @@ void configure_client(const options_t &options) { command.push_back(stripped_flag); }); // Run - run_zenity_and_set_env("MCPI_FEATURE_FLAGS", command); + run_zenity_and_set_env(MCPI_FEATURE_FLAGS_ENV, command); } // Setup MCPI_RENDER_DISTANCE { @@ -249,7 +245,7 @@ void configure_client(const options_t &options) { command.push_back(render_distance); } // Run - run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command); + run_zenity_and_set_env(MCPI_RENDER_DISTANCE_ENV, command); } // Setup MCPI_USERNAME { @@ -260,7 +256,7 @@ void configure_client(const options_t &options) { command.push_back("--entry-text"); command.push_back(cache.username); // Run - run_zenity_and_set_env("MCPI_USERNAME", command); + run_zenity_and_set_env(MCPI_USERNAME_ENV, command); } // Save Cache diff --git a/launcher/src/crash-report.c b/launcher/src/crash-report.cpp similarity index 61% rename from launcher/src/crash-report.c rename to launcher/src/crash-report.cpp index 85020894..87cb6f6d 100644 --- a/launcher/src/crash-report.c +++ b/launcher/src/crash-report.cpp @@ -1,14 +1,16 @@ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include #include @@ -47,39 +49,67 @@ static void show_report(const char *log_filename) { } // Exit Handler +static pid_t child_pid = -1; static void exit_handler(__attribute__((unused)) int signal) { // Murder - murder_children(); + kill(child_pid, SIGTERM); +} + +// Log File +static std::string log_filename; +static int log_fd; +static void setup_log_file() { + // Get Log Directory + const std::string home = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data(); + ensure_directory(home.c_str()); + const std::string logs = home + "/logs"; + ensure_directory(logs.c_str()); + + // Get Timestamp + time_t raw_time; + time(&raw_time); + tm *time_info = localtime(&raw_time); + char time[512]; + strftime(time, 512, "%Y-%m-%d", time_info); + + // Get Log Filename + std::string file; + int num = 1; + do { + file = std::string(time) + '-' + std::to_string(num) + ".log"; + log_filename = logs + '/' + file; + num++; + } while (access(log_filename.c_str(), F_OK) != -1); + + // Create latest.log Symlink + const std::string latest_log = logs + "/latest.log"; + unlink(latest_log.c_str()); + if (symlink(file.c_str(), latest_log.c_str()) != 0) { + WARN("Unable To Create Latest Log Symlink: %s", strerror(errno)); + } + + // Create File + log_fd = open(log_filename.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (log_fd == -1) { + ERR("Unable To Create Log File: %s", strerror(errno)); + } + reborn_set_log(log_fd); } // Setup #define PIPE_READ 0 #define PIPE_WRITE 1 -#define MCPI_LOGS_DIR "/tmp/.minecraft-pi-logs" -static char log_filename[] = MCPI_LOGS_DIR "/XXXXXX"; -void setup_log_file() { - // Ensure Temporary Directory - { - // Check If It Exists - struct stat tmp_stat; - int exists = stat(MCPI_LOGS_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode); - if (!exists) { - // Doesn't Exist - if (mkdir(MCPI_LOGS_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) { - ERR("Unable To Create Temporary Folder: %s", strerror(errno)); - } - } +#define BUFFER_SIZE 1024 +static void safe_write(int fd, const void *buf, size_t size) { + const ssize_t bytes_written = write(fd, buf, size); + if (bytes_written < 0) { + ERR("Unable To Write Data: %s", strerror(errno)); } - - // Create Temporary File - int log_file_fd = mkstemp(log_filename); - if (log_file_fd == -1) { - ERR("Unable To Create Log File: %s", strerror(errno)); - } - close(log_file_fd); - reborn_set_log(log_filename); } void setup_crash_report() { + // Setup Logging + setup_log_file(); + // Store Output int output_pipe[2]; safe_pipe2(output_pipe, 0); @@ -114,19 +144,16 @@ void setup_crash_report() { // Continue Execution } else { - // Parent Process - track_child(ret); - // Install Signal Handlers - struct sigaction act_sigint = {0}; + child_pid = ret; + struct sigaction act_sigint = {}; act_sigint.sa_flags = SA_RESTART; act_sigint.sa_handler = &exit_handler; - sigaction(SIGINT, &act_sigint, NULL); - struct sigaction act_sigterm = {0}; + sigaction(SIGINT, &act_sigint, nullptr); + struct sigaction act_sigterm = {}; act_sigterm.sa_flags = SA_RESTART; act_sigterm.sa_handler = &exit_handler; - sigaction(SIGTERM, &act_sigterm, NULL); - atexit(murder_children); + sigaction(SIGTERM, &act_sigterm, nullptr); // Close Unneeded File Descriptors close(output_pipe[PIPE_WRITE]); @@ -136,24 +163,20 @@ void setup_crash_report() { // Set Debug Tag reborn_debug_tag = "(Crash Reporter) "; - // Setup Logging -#define BUFFER_SIZE 1024 - char buf[BUFFER_SIZE]; - // Setup Polling - int number_fds = 3; - struct pollfd poll_fds[number_fds]; + const int number_fds = 3; + pollfd poll_fds[number_fds]; poll_fds[0].fd = output_pipe[PIPE_READ]; poll_fds[1].fd = error_pipe[PIPE_READ]; poll_fds[2].fd = STDIN_FILENO; - for (int i = 0; i < number_fds; i++) { - poll_fds[i].events = POLLIN; + for (pollfd &poll_fd : poll_fds) { + poll_fd.events = POLLIN; } // Poll Data int status; while (waitpid(ret, &status, WNOHANG) != ret) { - int poll_ret = poll(poll_fds, number_fds, -1); + const int poll_ret = poll(poll_fds, number_fds, -1); if (poll_ret == -1) { if (errno == EINTR) { continue; @@ -163,86 +186,71 @@ void setup_crash_report() { } // Handle Data - for (int i = 0; i < number_fds; i++) { - if (poll_fds[i].revents != 0) { - if (poll_fds[i].revents & POLLIN) { - if (poll_fds[i].fd == STDIN_FILENO) { + for (pollfd &poll_fd : poll_fds) { + if (poll_fd.revents != 0) { + if (poll_fd.revents & POLLIN) { + char buf[BUFFER_SIZE]; + if (poll_fd.fd == STDIN_FILENO) { // Data Available From stdin int bytes_available; if (ioctl(fileno(stdin), FIONREAD, &bytes_available) == -1) { bytes_available = 0; } // Read - ssize_t bytes_read = read(poll_fds[i].fd, buf, BUFFER_SIZE); + const ssize_t bytes_read = read(poll_fd.fd, buf, BUFFER_SIZE); if (bytes_read == -1) { ERR("Unable To Read Input: %s", strerror(errno)); } // Write To Child - if (write(input_pipe[PIPE_WRITE], buf, bytes_read) == -1) { - ERR("Unable To Write Input To Child: %s", strerror(errno)); - } + safe_write(input_pipe[PIPE_WRITE], buf, bytes_read); } else { // Data Available From Child's stdout/stderr - ssize_t bytes_read = read(poll_fds[i].fd, buf, BUFFER_SIZE - 1 /* Account For NULL-Terminator */); + const ssize_t bytes_read = read(poll_fd.fd, buf, BUFFER_SIZE); if (bytes_read == -1) { ERR("Unable To Read Log Data: %s", strerror(errno)); } - // Print To Terminal - buf[bytes_read] = '\0'; - fprintf(poll_fds[i].fd == output_pipe[PIPE_READ] ? stdout : stderr, "%s", buf); - + safe_write(poll_fd.fd == output_pipe[PIPE_READ] ? STDOUT_FILENO : STDERR_FILENO, buf, bytes_read); // Write To log - if (write(reborn_get_log_fd(), buf, bytes_read) == -1) { - ERR("Unable To Write Log Data: %s", strerror(errno)); - } + safe_write(reborn_get_log_fd(), buf, bytes_read); } } else { // File Descriptor No Longer Accessible - poll_fds[i].events = 0; + poll_fd.events = 0; } } } } - // Untrack Process - untrack_child(ret); - // Close Pipes close(output_pipe[PIPE_READ]); close(error_pipe[PIPE_READ]); close(input_pipe[PIPE_WRITE]); // Check If Is Crash - int is_crash = !is_exit_status_success(status); + const bool is_crash = !is_exit_status_success(status); // Log Exit Code To log If Crash if (is_crash) { // Create Exit Code Log Line - char *exit_status = NULL; + char *exit_status = nullptr; get_exit_status_string(status, &exit_status); - char *exit_code_line = NULL; - safe_asprintf(&exit_code_line, "[CRASH]: Terminated%s\n", exit_status); + const std::string exit_code_line = "[CRASH]: Terminated" + std::string(exit_status) + '\n'; free(exit_status); // Print Exit Code Log Line - fprintf(stderr, "%s", exit_code_line); + safe_write(STDERR_FILENO, exit_code_line.c_str(), strlen(exit_code_line.c_str())); // Write Exit Code Log Line - if (write(reborn_get_log_fd(), exit_code_line, strlen(exit_code_line)) == -1) { - ERR("Unable To Write Exit Code To Log: %s", strerror(errno)); - } - - // Free Exit Code Log Line - free(exit_code_line); + safe_write(reborn_get_debug_fd(), exit_code_line.c_str(), strlen(exit_code_line.c_str())); } // Close Log File - reborn_close_log(); - unsetenv(MCPI_LOG_ENV); + close(log_fd); + unsetenv(_MCPI_LOG_FD_ENV); // Show Crash Log if (is_crash && !reborn_is_headless()) { - show_report(log_filename); + show_report(log_filename.c_str()); } // Exit diff --git a/launcher/src/crash-report.h b/launcher/src/crash-report.h index 1d667ad8..4042a60d 100644 --- a/launcher/src/crash-report.h +++ b/launcher/src/crash-report.h @@ -4,7 +4,6 @@ extern "C" { #endif -void setup_log_file(); void setup_crash_report(); #ifdef __cplusplus diff --git a/launcher/src/main.cpp b/launcher/src/main.cpp index 084488a0..0d4653c0 100644 --- a/launcher/src/main.cpp +++ b/launcher/src/main.cpp @@ -10,18 +10,20 @@ // Bind Options To Environmental Variable static void bind_to_env(const char *env, const bool value) { - const bool force = env[0] == '_'; - if (force || value) { - set_and_print_env(env, value ? "1" : nullptr); + if (value) { + set_and_print_env(env, "1"); } } static void setup_environment(const options_t &options) { + // Clear Internal Variables + clear_internal_env_vars(); + // Passthrough Options To Game - bind_to_env(MCPI_SERVER_MODE_ENV, options.server_mode); - bind_to_env("_MCPI_BENCHMARK", options.benchmark); - bind_to_env("_MCPI_ONLY_GENERATE", options.only_generate); - bind_to_env(MCPI_FORCE_HEADLESS_ENV, options.force_headless); - bind_to_env(MCPI_FORCE_NON_HEADLESS_ENV, options.force_non_headless); + bind_to_env(_MCPI_SERVER_MODE_ENV, options.server_mode); + bind_to_env(_MCPI_BENCHMARK_ENV, options.benchmark); + bind_to_env(_MCPI_ONLY_GENERATE_ENV, options.only_generate); + bind_to_env(_MCPI_FORCE_HEADLESS_ENV, options.force_headless); + bind_to_env(_MCPI_FORCE_NON_HEADLESS_ENV, options.force_non_headless); // GTK Dark Mode set_and_print_env("GTK_THEME", "Adwaita:dark"); @@ -29,12 +31,11 @@ static void setup_environment(const options_t &options) { // Configure PATH { // Get Binary Directory - char *binary_directory = get_binary_directory(); - std::string new_path = std::string(binary_directory) + "/bin"; - free(binary_directory); + const std::string binary_directory = get_binary_directory(); + std::string new_path = binary_directory + "/bin"; // Add Existing PATH { - char *value = getenv("PATH"); + const char *value = getenv("PATH"); if (value != nullptr && strlen(value) > 0) { new_path += std::string(":") + value; } @@ -42,27 +43,37 @@ static void setup_environment(const options_t &options) { // Set And Free set_and_print_env("PATH", new_path.c_str()); } + + // Setup MCPI_HOME + if (!reborn_is_server()) { + // Ensure $HOME + const char *home = getenv("HOME"); + if (home == nullptr) { + ERR("$HOME Is Not Set"); + } + set_and_print_env(_MCPI_HOME_ENV, home); + } else { + // Set Home To Current Directory, So World Data Is Stored There + char *launch_directory = getcwd(nullptr, 0); + ALLOC_CHECK(launch_directory); + set_and_print_env(_MCPI_HOME_ENV, launch_directory); + free(launch_directory); + } + // Create If Needed + const std::string minecraft_folder = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data(); + ensure_directory(minecraft_folder.c_str()); } // Non-Launch Commands static void handle_non_launch_commands(const options_t &options) { if (options.copy_sdk) { - char *binary_directory = get_binary_directory(); + const std::string binary_directory = get_binary_directory(); copy_sdk(binary_directory, false); - free(binary_directory); fflush(stdout); exit(EXIT_SUCCESS); } } -// Exit Handler -static void exit_handler(__attribute__((unused)) int signal_id) { - // Pass Signal To Child - murder_children(); - while (wait(nullptr) > 0) {} - _exit(EXIT_SUCCESS); -} - // Start The Game static void start_game(const options_t &options) { // Disable stdout Buffering @@ -70,46 +81,9 @@ static void start_game(const options_t &options) { // Setup Crash Reporting if (!options.disable_crash_report) { - setup_log_file(); setup_crash_report(); } - // Install Signal Handlers - struct sigaction act_sigint = {}; - act_sigint.sa_flags = SA_RESTART; - act_sigint.sa_handler = &exit_handler; - sigaction(SIGINT, &act_sigint, nullptr); - struct sigaction act_sigterm = {}; - act_sigterm.sa_flags = SA_RESTART; - act_sigterm.sa_handler = &exit_handler; - sigaction(SIGTERM, &act_sigterm, nullptr); - - // Setup Home - if (!reborn_is_server()) { - // Ensure $HOME - const char *home = getenv("HOME"); - if (home == nullptr) { - ERR("$HOME Is Not Set"); - } - // Create If Needed - { - std::string minecraft_folder = std::string(home) + get_home_subdirectory_for_game_data(); - struct stat tmp_stat = {}; - bool exists = stat(minecraft_folder.c_str(), &tmp_stat) != 0 ? false : S_ISDIR(tmp_stat.st_mode); - if (!exists) { - // Doesn't Exist - if (mkdir(minecraft_folder.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) { - ERR("Unable To Create Data Directory: %s", strerror(errno)); - } - } - } - } else { - // Set Home To Current Directory, So World Data Is Stored There - char *launch_directory = getcwd(nullptr, 0); - set_and_print_env("HOME", launch_directory); - free(launch_directory); - } - // Configure Client Options if (!reborn_is_server()) { configure_client(options); @@ -128,7 +102,7 @@ int main(int argc, char *argv[]) { reborn_debug_tag = "(Launcher) "; // Debug Logging - unsetenv(MCPI_LOG_ENV); + unsetenv(_MCPI_LOG_FD_ENV); bind_to_env(MCPI_DEBUG_ENV, options.debug); // Setup Environment diff --git a/launcher/src/mods.cpp b/launcher/src/mods.cpp index 11932ca1..a5cd30f8 100644 --- a/launcher/src/mods.cpp +++ b/launcher/src/mods.cpp @@ -10,6 +10,7 @@ // Get All Mods In Folder static void load(std::string &ld_preload, const std::string &folder) { // Open Folder + ensure_directory(folder.c_str()); DIR *dp = opendir(folder.c_str()); if (dp != nullptr) { // Loop Through Folder @@ -43,8 +44,6 @@ static void load(std::string &ld_preload, const std::string &folder) { } // Close Folder closedir(dp); - } else if (errno == ENOENT) { - // Folder Doesn't Exist } else { // Unable To Open Folder ERR("Error Opening Directory: %s: %s", folder.c_str(), strerror(errno)); @@ -60,7 +59,7 @@ std::string bootstrap_mods(const std::string &binary_directory) { // ~/.minecraft-pi/mods { // Get Mods Folder - std::string mods_folder = std::string(getenv("HOME")) + get_home_subdirectory_for_game_data() + SUBDIRECTORY_FOR_MODS; + std::string mods_folder = std::string(getenv(_MCPI_HOME_ENV)) + get_home_subdirectory_for_game_data() + SUBDIRECTORY_FOR_MODS; // Load Mods From ./mods load(preload, mods_folder); } diff --git a/launcher/src/options/option-list.h b/launcher/src/options/option-list.h index 315688bc..19fc58ef 100644 --- a/launcher/src/options/option-list.h +++ b/launcher/src/options/option-list.h @@ -1,4 +1,4 @@ -OPTION(debug, "debug", 'd', "Enable Debug Logging (" MCPI_DEBUG_ENV ")") +OPTION(debug, "debug", 'd', "Enable Debug Logging") OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit") OPTION(disable_crash_report, "disable-crash-report", -1, "Disable Crash Report Dialog") OPTION(use_default, "default", -3, "Skip Client-Mode Configuration Dialogs") diff --git a/launcher/src/options/parser.cpp b/launcher/src/options/parser.cpp index 416c3688..cadd8bcb 100644 --- a/launcher/src/options/parser.cpp +++ b/launcher/src/options/parser.cpp @@ -8,12 +8,19 @@ const char *argp_program_bug_address = "<" MCPI_DISCORD_INVITE ">"; static char doc[] = "Minecraft: Pi Edition Modding Project"; // Options -#define OPTION(ignored, name, key, doc) {name, key, nullptr, 0, doc, 0}, +static int env_key = -100; static argp_option options_data[] = { + {nullptr, 0, nullptr, 0, "Game Options:", 0}, +#define OPTION(ignored, name, key, doc) {name, key, nullptr, 0, doc, 0}, #include "option-list.h" +#undef OPTION + {nullptr, 0, nullptr, 0, "Environmental Variables:", 0}, +#define ENV(name, doc) {#name, env_key--, nullptr, OPTION_DOC | OPTION_NO_USAGE | (is_env_var_internal(name##_ENV) ? OPTION_HIDDEN : 0), doc, 0}, +#include +#undef ENV + {nullptr, 0, nullptr, 0, "Help Options:", -1}, {nullptr, 0, nullptr, 0, nullptr, 0} }; -#undef OPTION // Parse Options #define OPTION(name, ignored, key, ...) \ diff --git a/launcher/src/patchelf.cpp b/launcher/src/patchelf.cpp index e397f0f1..60300ef4 100644 --- a/launcher/src/patchelf.cpp +++ b/launcher/src/patchelf.cpp @@ -13,17 +13,7 @@ // Duplicate MCPI Executable Into /tmp static void duplicate_mcpi_executable(char *new_path) { // Ensure Temporary Directory - { - // Check If It Exists - struct stat tmp_stat = {}; - int exists = stat(MCPI_PATCHED_DIR, &tmp_stat) != 0 ? 0 : S_ISDIR(tmp_stat.st_mode); - if (!exists) { - // Doesn't Exist - if (mkdir(MCPI_PATCHED_DIR, S_IRUSR | S_IWUSR | S_IXUSR) != 0) { - ERR("Unable To Create Temporary Folder: %s", strerror(errno)); - } - } - } + ensure_directory(MCPI_PATCHED_DIR); // Generate New File int new_file_fd = mkstemp(new_path); diff --git a/launcher/src/sdk.cpp b/launcher/src/sdk.cpp index 2dde7e99..3f5b1b9a 100644 --- a/launcher/src/sdk.cpp +++ b/launcher/src/sdk.cpp @@ -19,7 +19,7 @@ void copy_sdk(const std::string &binary_directory, const bool log_with_debug) { // Ensure SDK Directory std::string sdk_path; { - sdk_path = std::string(getenv("HOME")) + HOME_SUBDIRECTORY_FOR_SDK; + sdk_path = std::string(getenv(_MCPI_HOME_ENV)) + HOME_SUBDIRECTORY_FOR_SDK; const char *const command[] = {"mkdir", "-p", sdk_path.c_str(), nullptr}; run_simple_command(command, "Unable To Create SDK Directory"); } diff --git a/launcher/src/util.c b/launcher/src/util.c deleted file mode 100644 index abc7b56d..00000000 --- a/launcher/src/util.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include "util.h" - -// Simpler Version Of run_command() -void run_simple_command(const char *const command[], const char *error) { - int status = 0; - char *output = run_command(command, &status, NULL); - if (output != NULL) { - free(output); - } - if (!is_exit_status_success(status)) { - ERR("%s", error); - } -} - -// Chop Off Last Component -void chop_last_component(char **str) { - size_t length = strlen(*str); - for (size_t i = 0; i < length; i++) { - size_t j = length - i - 1; - if ((*str)[j] == '/') { - (*str)[j] = '\0'; - break; - } - } -} -// Get Binary Directory (Remember To Free) -char *get_binary_directory() { - // Get Path To Current Executable - char *exe = realpath("/proc/self/exe", NULL); - ALLOC_CHECK(exe); - - // Chop Off Last Component - chop_last_component(&exe); - - // Return - return exe; -} diff --git a/launcher/src/util.cpp b/launcher/src/util.cpp new file mode 100644 index 00000000..c6564ae5 --- /dev/null +++ b/launcher/src/util.cpp @@ -0,0 +1,41 @@ +#include + +#include "util.h" + +// Simpler Version Of run_command() +void run_simple_command(const char *const command[], const char *error) { + int status = 0; + char *output = run_command(command, &status, nullptr); + if (output != nullptr) { + free(output); + } + if (!is_exit_status_success(status)) { + ERR("%s", error); + } +} + +// Chop Off Last Component +void chop_last_component(std::string &str) { + const std::string::size_type pos = str.find_last_of('/'); + if (pos == std::string::npos) { + return; + } + str = str.substr(0, pos); +} + +// Get Binary Directory (Remember To Free) +std::string safe_realpath(const std::string &path) { + char *raw = realpath(path.c_str(), nullptr); + ALLOC_CHECK(raw); + std::string str = raw; + free(raw); + return str; +} +std::string get_binary_directory() { + // Get Path To Current Executable + std::string exe = safe_realpath("/proc/self/exe"); + // Chop Off Last Component + chop_last_component(exe); + // Return + return exe; +} diff --git a/launcher/src/util.h b/launcher/src/util.h index 19d4706b..63e0aae7 100644 --- a/launcher/src/util.h +++ b/launcher/src/util.h @@ -1,14 +1,9 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif +#include void run_simple_command(const char *const command[], const char *error); -void chop_last_component(char **str); -char *get_binary_directory(); - -#ifdef __cplusplus -} -#endif +void chop_last_component(std::string &str); +std::string safe_realpath(const std::string &path); +std::string get_binary_directory(); diff --git a/libreborn/CMakeLists.txt b/libreborn/CMakeLists.txt index 3f5464e8..9c44a619 100644 --- a/libreborn/CMakeLists.txt +++ b/libreborn/CMakeLists.txt @@ -5,7 +5,14 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn") configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY) # Util -add_library(reborn-util SHARED src/util/exec.c src/util/string.c src/util/util.c src/util/log.c src/util/cp437.cpp) +add_library(reborn-util SHARED + src/util/exec.c + src/util/string.c + src/util/util.c + src/util/log.c + src/util/cp437.cpp + src/util/env.c +) target_include_directories( reborn-util PUBLIC @@ -25,7 +32,12 @@ endif() # Patch if(BUILD_ARM_COMPONENTS) - add_library(reborn-patch SHARED src/patch/patch.cpp src/patch/segments.cpp src/patch/code-block.cpp src/patch/instruction.cpp) + add_library(reborn-patch SHARED + src/patch/patch.cpp + src/patch/segments.cpp + src/patch/code-block.cpp + src/patch/instruction.cpp + ) target_link_libraries(reborn-patch dl pthread reborn-util) target_compile_definitions(reborn-patch PUBLIC -DREBORN_HAS_PATCH_CODE) # Install diff --git a/libreborn/include/libreborn/env.h b/libreborn/include/libreborn/env.h new file mode 100644 index 00000000..d23c34ab --- /dev/null +++ b/libreborn/include/libreborn/env.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define ENV(name, ...) extern const char *name##_ENV; +#include "env_list.h" +#undef ENV + +int is_env_var_internal(const char *env); +void clear_internal_env_vars(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/libreborn/include/libreborn/env_list.h b/libreborn/include/libreborn/env_list.h new file mode 100644 index 00000000..4ef6428c --- /dev/null +++ b/libreborn/include/libreborn/env_list.h @@ -0,0 +1,24 @@ +// Configure Client +ENV(MCPI_FEATURE_FLAGS, "Client-Mode Feature Flags") +ENV(MCPI_USERNAME, "Player Username") +ENV(MCPI_RENDER_DISTANCE, "Render Distance") +// Game Assets +ENV(_MCPI_REBORN_ASSETS_PATH, "") +ENV(_MCPI_VANILLA_ASSETS_PATH, "") +// Command Line Arguments +ENV(_MCPI_BENCHMARK, "") +ENV(_MCPI_ONLY_GENERATE, "") +// Logging +ENV(_MCPI_LOG_FD, "") +ENV(MCPI_DEBUG, "Enable Debug Logging") +// Server/Headless +ENV(_MCPI_SERVER_MODE, "") +ENV(_MCPI_FORCE_HEADLESS, "") +ENV(_MCPI_FORCE_NON_HEADLESS, "") +// Extra Configuration +ENV(MCPI_SKIN_SERVER, "Custom Skin Server") +ENV(MCPI_API_PORT, "Custom API Port") +ENV(MCPI_BLOCK_OUTLINE_WIDTH, "Custom Width For Block Outline (In Pixels)") +ENV(MCPI_GUI_SCALE, "Custom GUI Scale") +// $HOME +ENV(_MCPI_HOME, "") \ No newline at end of file diff --git a/libreborn/include/libreborn/exec.h b/libreborn/include/libreborn/exec.h index 9057bd69..e90b1320 100644 --- a/libreborn/include/libreborn/exec.h +++ b/libreborn/include/libreborn/exec.h @@ -32,11 +32,6 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_ // Get Exit Status String void get_exit_status_string(int status, char **out); -// Track Children -void track_child(pid_t pid); -void untrack_child(pid_t pid); -void murder_children(); - #ifdef __cplusplus } #endif diff --git a/libreborn/include/libreborn/libreborn.h b/libreborn/include/libreborn/libreborn.h index c9068b4b..54bf1b7d 100644 --- a/libreborn/include/libreborn/libreborn.h +++ b/libreborn/include/libreborn/libreborn.h @@ -1,6 +1,7 @@ #pragma once #include +#include "env.h" #include "log.h" #include "util.h" #include "string.h" diff --git a/libreborn/include/libreborn/log.h b/libreborn/include/libreborn/log.h index 785f3d33..cdc99ce5 100644 --- a/libreborn/include/libreborn/log.h +++ b/libreborn/include/libreborn/log.h @@ -8,12 +8,9 @@ extern "C" { #endif // Log File -#define MCPI_LOG_ENV "_MCPI_LOG" int reborn_get_log_fd(); -void reborn_close_log(); -void reborn_set_log(const char *file); +void reborn_set_log(int fd); // Debug Logging -#define MCPI_DEBUG_ENV "MCPI_DEBUG" extern const char *reborn_debug_tag; int reborn_get_debug_fd(); diff --git a/libreborn/include/libreborn/util.h b/libreborn/include/libreborn/util.h index c387a7d1..4b4ba3b7 100644 --- a/libreborn/include/libreborn/util.h +++ b/libreborn/include/libreborn/util.h @@ -51,9 +51,6 @@ int lock_file(const char *file); void unlock_file(const char *file, int fd); // Access Configuration At Runtime -#define MCPI_SERVER_MODE_ENV "_MCPI_SERVER_MODE" -#define MCPI_FORCE_HEADLESS_ENV "_MCPI_FORCE_HEADLESS" -#define MCPI_FORCE_NON_HEADLESS_ENV "_MCPI_FORCE_NON_HEADLESS" const char *reborn_get_version(); int reborn_is_headless(); int reborn_is_server(); @@ -64,6 +61,9 @@ void reborn_check_display(); // Get Home Subdirectory const char *get_home_subdirectory_for_game_data(); +// Make Sure Directory Exists +void ensure_directory(const char *path); + // Customize VTable #define CUSTOM_VTABLE(name, parent) \ void _setup_##name##_vtable(parent##_vtable *vtable); \ diff --git a/libreborn/src/util/env.c b/libreborn/src/util/env.c new file mode 100644 index 00000000..da0b114c --- /dev/null +++ b/libreborn/src/util/env.c @@ -0,0 +1,20 @@ +#include +#include + +// Define Constants +#define ENV(name, ...) const char *name##_ENV = #name; +#include +#undef ENV + +// Clear Internal Variables +int is_env_var_internal(const char *env) { + return env[0] == '_'; +} +void clear_internal_env_vars() { +#define ENV(name, ...) \ + if (is_env_var_internal(name##_ENV)) { \ + set_and_print_env(name##_ENV, NULL); \ + } +#include +#undef ENV +} \ No newline at end of file diff --git a/libreborn/src/util/exec.c b/libreborn/src/util/exec.c index c9e19ddd..398a693f 100644 --- a/libreborn/src/util/exec.c +++ b/libreborn/src/util/exec.c @@ -1,4 +1,5 @@ #include +#include #include @@ -57,12 +58,12 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_ // Setup stderr dup2(reborn_get_debug_fd(), STDERR_FILENO); + // Kill On Parent Death + prctl(PR_SET_PDEATHSIG, SIGKILL); + // Run safe_execvpe(command, (const char *const *) environ); } else { - // Parent Process - track_child(ret); - // Read stdout close(output_pipe[1]); #define BUFFER_SIZE 1024 @@ -75,7 +76,7 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_ // Grow Output If Needed size_t needed_size = position + bytes_read; if (needed_size > size) { - // More Memeory Needed + // More Memory Needed size_t new_size = size; while (new_size < needed_size) { new_size += BUFFER_SIZE; @@ -98,7 +99,7 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_ // Add NULL-Terminator To Output size_t needed_size = position + 1; if (needed_size > size) { - // More Memeory Needed + // More Memory Needed size_t new_size = size + 1; char *new_output = realloc(output, new_size); if (new_output == NULL) { @@ -117,7 +118,6 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_ // Get Return Code int status; waitpid(ret, &status, 0); - untrack_child(ret); if (exit_status != NULL) { *exit_status = status; } @@ -140,36 +140,3 @@ void get_exit_status_string(int status, char **out) { } } } - -// Track Children -#define MAX_CHILDREN 128 -static pid_t children[MAX_CHILDREN] = { 0 }; -static pthread_mutex_t children_lock = PTHREAD_MUTEX_INITIALIZER; -void track_child(pid_t pid) { - pthread_mutex_lock(&children_lock); - for (int i = 0; i < MAX_CHILDREN; i++) { - if (children[i] == 0) { - children[i] = pid; - break; - } - } - pthread_mutex_unlock(&children_lock); -} -void untrack_child(pid_t pid) { - pthread_mutex_lock(&children_lock); - for (int i = 0; i < MAX_CHILDREN; i++) { - if (children[i] == pid) { - children[i] = 0; - } - } - pthread_mutex_unlock(&children_lock); -} -void murder_children() { - pthread_mutex_lock(&children_lock); - for (int i = 0; i < MAX_CHILDREN; i++) { - if (children[i] != 0) { - kill(children[i], SIGTERM); - } - } - pthread_mutex_unlock(&children_lock); -} diff --git a/libreborn/src/util/log.c b/libreborn/src/util/log.c index 64b09804..c0e57101 100644 --- a/libreborn/src/util/log.c +++ b/libreborn/src/util/log.c @@ -5,6 +5,7 @@ #include #include +#include // Debug Tag const char *reborn_debug_tag = ""; @@ -16,11 +17,8 @@ int reborn_get_log_fd() { return log_fd; } // Open Log File - const char *file = getenv(MCPI_LOG_ENV); - if (file == NULL) { - file = "/dev/null"; - } - log_fd = open(file, O_WRONLY | O_APPEND | O_CLOEXEC); + const char *fd_str = getenv(_MCPI_LOG_FD_ENV); + log_fd = fd_str ? atoi(fd_str) : open("/dev/null", O_WRONLY | O_APPEND); // Check FD if (log_fd < 0) { ERR("Unable To Open Log: %s", strerror(errno)); @@ -28,17 +26,12 @@ int reborn_get_log_fd() { // Return return reborn_get_log_fd(); } -__attribute__((destructor)) void reborn_close_log() { - if (log_fd >= 0) { - close(log_fd); - log_fd = -1; - } -} -void reborn_set_log(const char *file) { - // Close Current Log - reborn_close_log(); +void reborn_set_log(const int fd) { // Set Variable - set_and_print_env(MCPI_LOG_ENV, file); + log_fd = -1; + char buf[128]; + sprintf(buf, "%i", fd); + set_and_print_env(_MCPI_LOG_FD_ENV, buf); } // Debug Logging diff --git a/libreborn/src/util/util.c b/libreborn/src/util/util.c index e45e2507..680cf539 100644 --- a/libreborn/src/util/util.c +++ b/libreborn/src/util/util.c @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include // Safe Version Of pipe() void safe_pipe2(int pipefd[2], int flags) { @@ -54,9 +56,9 @@ int reborn_is_headless() { static int is_set = 0; if (!is_set) { ret = reborn_is_server(); - if (getenv(MCPI_FORCE_HEADLESS_ENV)) { + if (getenv(_MCPI_FORCE_HEADLESS_ENV)) { ret = 1; - } else if (getenv(MCPI_FORCE_NON_HEADLESS_ENV)) { + } else if (getenv(_MCPI_FORCE_NON_HEADLESS_ENV)) { ret = 0; } is_set = 1; @@ -67,7 +69,7 @@ int reborn_is_server() { static int ret; static int is_set = 0; if (!is_set) { - ret = getenv(MCPI_SERVER_MODE_ENV) != NULL; + ret = getenv(_MCPI_SERVER_MODE_ENV) != NULL; is_set = 1; } return ret; @@ -89,4 +91,21 @@ const char *get_home_subdirectory_for_game_data() { // Store Game Data In $HOME Root (In Server Mode, $HOME Is Changed To The Launch Directory) return ""; } +} + +// Make Sure Directory Exists +void ensure_directory(const char *path) { + int ret = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (ret != 0 && errno != EEXIST) { + ERR("Unable To Create Directory: %s", strerror(errno)); + } + int is_dir = 0; + struct stat obj = {}; + ret = stat(path, &obj); + if (ret == 0) { + is_dir = S_ISDIR(obj.st_mode); + } + if (!is_dir) { + ERR("Not A Directory: %s", path); + } } \ No newline at end of file diff --git a/media-layer/extras/src/SDL.c b/media-layer/extras/src/SDL.c index 784e60f1..f80090f4 100644 --- a/media-layer/extras/src/SDL.c +++ b/media-layer/extras/src/SDL.c @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -32,11 +31,6 @@ void SDL_Quit() { // Cleanup Media Layer media_cleanup(); - // Wait For Children To Stop - signal(SIGCHLD, SIG_IGN); - murder_children(); - while (wait(NULL) > 0) {} - // Exit INFO("Stopped"); } diff --git a/mods/include/mods/init/init.h b/mods/include/mods/init/init.h index eaaabd4d..41ce33ee 100644 --- a/mods/include/mods/init/init.h +++ b/mods/include/mods/init/init.h @@ -26,4 +26,5 @@ void init_chat(); void init_bucket(); void init_cake(); void init_home(); +void init_override(); } diff --git a/mods/src/benchmark/benchmark.cpp b/mods/src/benchmark/benchmark.cpp index 0d7fdb49..91cb036a 100644 --- a/mods/src/benchmark/benchmark.cpp +++ b/mods/src/benchmark/benchmark.cpp @@ -158,7 +158,7 @@ static void Minecraft_update_injection(Minecraft *minecraft) { // Init Benchmark void init_benchmark() { // --benchmark: Activate Benchmark - bool active = getenv("_MCPI_BENCHMARK") != nullptr; + bool active = getenv(_MCPI_BENCHMARK_ENV) != nullptr; if (active) { misc_run_on_update(Minecraft_update_injection); // Track Ticks diff --git a/mods/src/compat/compat.cpp b/mods/src/compat/compat.cpp index b2ee1667..6f4a544a 100644 --- a/mods/src/compat/compat.cpp +++ b/mods/src/compat/compat.cpp @@ -102,7 +102,10 @@ static void exit_handler(__attribute__((unused)) int data) { } void init_compat() { // Install Signal Handlers - signal(SIGINT, SIG_IGN); + struct sigaction act_sigint = {}; + act_sigint.sa_flags = SA_RESTART; + act_sigint.sa_handler = &exit_handler; + sigaction(SIGINT, &act_sigint, nullptr); struct sigaction act_sigterm = {}; act_sigterm.sa_flags = SA_RESTART; act_sigterm.sa_handler = &exit_handler; diff --git a/mods/src/feature/feature.cpp b/mods/src/feature/feature.cpp index 71b33671..90cb26ea 100644 --- a/mods/src/feature/feature.cpp +++ b/mods/src/feature/feature.cpp @@ -12,7 +12,7 @@ bool _feature_has(const char *name, int server_default) { return server_default > 0; } // Get Value - char *env = getenv("MCPI_FEATURE_FLAGS"); + char *env = getenv(MCPI_FEATURE_FLAGS_ENV); char *features = strdup(env != nullptr ? env : ""); char *tok = strtok(features, "|"); bool ret = false; diff --git a/mods/src/home/home.cpp b/mods/src/home/home.cpp index fd118e06..d231bb3c 100644 --- a/mods/src/home/home.cpp +++ b/mods/src/home/home.cpp @@ -1,5 +1,3 @@ -#include - #include #include @@ -11,16 +9,23 @@ const char *home_get() { static std::string dir = ""; // Load if (dir.empty()) { - dir = std::string(getenv("HOME")) + std::string(get_home_subdirectory_for_game_data()); + dir = std::string(getenv(_MCPI_HOME_ENV)) + std::string(get_home_subdirectory_for_game_data()); } // Return return dir.c_str(); } +// Use MCPI_HOME +static const char *getenv_HOME(__attribute__((unused)) const char *env) { + return getenv(_MCPI_HOME_ENV); +} + // Init void init_home() { // Store Data In ~/.minecraft-pi Instead Of ~/.minecraft - patch_address((void *) &Strings::default_path, (void *) get_home_subdirectory_for_game_data()); + patch_address(&Strings::default_path, (void *) get_home_subdirectory_for_game_data()); + // Use MCPI_HOME Instead Of $HOME + overwrite_call((void *) 0xe0e4, (void *) getenv_HOME); // The override code resolves assets manually, // making changing directory redundant. diff --git a/mods/src/init/init.cpp b/mods/src/init/init.cpp index 259636ed..b713f9b9 100644 --- a/mods/src/init/init.cpp +++ b/mods/src/init/init.cpp @@ -32,6 +32,7 @@ __attribute__((constructor)) static void init() { init_bucket(); init_cake(); init_home(); + init_override(); if (!reborn_is_server()) { init_benchmark(); } diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp index b6b41a39..228b3365 100644 --- a/mods/src/misc/misc.cpp +++ b/mods/src/misc/misc.cpp @@ -381,7 +381,7 @@ HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) { if (addr->sa_family == AF_INET) { in_addr = *(const struct sockaddr_in *) new_addr; if (in_addr.sin_port == ntohs(4711)) { - const char *new_port_str = getenv("MCPI_API_PORT"); + const char *new_port_str = getenv(MCPI_API_PORT_ENV); long int new_port; if (new_port_str != nullptr && (new_port = strtol(new_port_str, nullptr, 0)) != 0L) { in_addr.sin_port = htons(new_port); @@ -555,7 +555,7 @@ static void LevelRenderer_render_AABB_glColor4f_injection(__attribute__((unused) glColor4f(0, 0, 0, 0.4); // Find Line Width - char *custom_line_width = getenv("MCPI_BLOCK_OUTLINE_WIDTH"); + char *custom_line_width = getenv(MCPI_BLOCK_OUTLINE_WIDTH_ENV); float line_width; if (custom_line_width != nullptr) { // Custom @@ -867,7 +867,7 @@ void init_misc() { } // Custom GUI Scale - const char *gui_scale_str = getenv("MCPI_GUI_SCALE"); + const char *gui_scale_str = getenv(MCPI_GUI_SCALE_ENV); if (gui_scale_str != nullptr) { unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" patch((void *) 0x173e8, nop_patch); diff --git a/mods/src/options/options.cpp b/mods/src/options/options.cpp index db786867..470d82e0 100644 --- a/mods/src/options/options.cpp +++ b/mods/src/options/options.cpp @@ -19,7 +19,7 @@ static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) LevelData * // Get Custom Render Distance static int get_render_distance() { - const char *distance_str = getenv("MCPI_RENDER_DISTANCE"); + const char *distance_str = getenv(MCPI_RENDER_DISTANCE_ENV); if (distance_str == nullptr) { distance_str = "Short"; } @@ -38,7 +38,7 @@ static int get_render_distance() { // Get Custom Username static const char *get_username() { - const char *username = getenv("MCPI_USERNAME"); + const char *username = getenv(MCPI_USERNAME_ENV); if (username == nullptr) { username = "StevePi"; } diff --git a/mods/src/override/override.cpp b/mods/src/override/override.cpp index 56d76ba3..7b1bc130 100644 --- a/mods/src/override/override.cpp +++ b/mods/src/override/override.cpp @@ -10,6 +10,7 @@ #include #include +#include // Hook access HOOK(access, int, (const char *pathname, int mode)) { @@ -25,6 +26,12 @@ HOOK(access, int, (const char *pathname, int mode)) { return ret; } +// Get Override Folder +static std::string get_override_directory() { + const std::string home_path = home_get(); + return home_path + "/overrides"; +} + // Get Override Path For File (If It Exists) char *override_get_path(const char *filename) { // Custom Skin @@ -33,10 +40,8 @@ char *override_get_path(const char *filename) { filename = "data/images/mob/char.png"; } - // Get MCPI Home Path - const std::string home_path = home_get(); // Get Asset Override Path - const std::string overrides = home_path + "/overrides"; + const std::string overrides = get_override_directory(); // Data Prefiix const std::string data_prefix = "data/"; @@ -45,8 +50,8 @@ char *override_get_path(const char *filename) { // Folders To Check std::string asset_folders[] = { overrides, - getenv("MCPI_REBORN_ASSETS_PATH"), - getenv("MCPI_VANILLA_ASSETS_PATH"), + getenv(_MCPI_REBORN_ASSETS_PATH_ENV), + getenv(_MCPI_VANILLA_ASSETS_PATH_ENV), "" }; @@ -105,3 +110,8 @@ HOOK(fopen64, FILE *, (const char *filename, const char *mode)) { // Return File return file; } + +// Init +void init_override() { + ensure_directory(get_override_directory().c_str()); +} \ No newline at end of file diff --git a/mods/src/screenshot/screenshot.cpp b/mods/src/screenshot/screenshot.cpp index cb4c345c..2f7b15a3 100644 --- a/mods/src/screenshot/screenshot.cpp +++ b/mods/src/screenshot/screenshot.cpp @@ -16,20 +16,9 @@ // Ensure Screenshots Folder Exists static void ensure_screenshots_folder(const char *screenshots) { // Check Screenshots Folder - struct stat obj = {}; - if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode)) { - // Create Screenshots Folder - const int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if (ret != 0) { - // Unable To Create Folder - ERR("Error Creating Directory: %s: %s", screenshots, strerror(errno)); - } - } + ensure_directory(screenshots); } -// 4 (Year) + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Null Terminator) -#define TIME_SIZE 20 - // Take Screenshot static int save_png(const char *filename, unsigned char *pixels, int line_size, int width, int height) { // Setup @@ -48,12 +37,11 @@ void screenshot_take(const char *home) { const std::string screenshots = std::string(home) + "/screenshots"; // Get Timestamp - time_t rawtime; - tm *timeinfo = {}; - time(&rawtime); - timeinfo = localtime(&rawtime); - char time[TIME_SIZE]; - strftime(time, TIME_SIZE, "%Y-%m-%d_%H.%M.%S", timeinfo); + time_t raw_time; + time(&raw_time); + tm *time_info = localtime(&raw_time); + char time[512]; + strftime(time, 512, "%Y-%m-%d_%H.%M.%S", time_info); // Ensure Screenshots Folder Exists ensure_screenshots_folder(screenshots.c_str()); diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index 9556167d..4320b2fb 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -26,7 +26,7 @@ // --only-generate: Ony Generate World And Then Exit static bool only_generate = false; __attribute__((constructor)) static void _init_only_generate() { - only_generate = getenv("_MCPI_ONLY_GENERATE") != nullptr; + only_generate = getenv(_MCPI_ONLY_GENERATE_ENV) != nullptr; } // Server Properties @@ -584,7 +584,7 @@ static void server_init() { // Init Server void init_server() { server_init(); - set_and_print_env("MCPI_FEATURE_FLAGS", get_features()); - set_and_print_env("MCPI_RENDER_DISTANCE", "Tiny"); - set_and_print_env("MCPI_USERNAME", get_motd().c_str()); + set_and_print_env(MCPI_FEATURE_FLAGS_ENV, get_features()); + set_and_print_env(MCPI_RENDER_DISTANCE_ENV, "Tiny"); + set_and_print_env(MCPI_USERNAME_ENV, get_motd().c_str()); } diff --git a/mods/src/skin/loader.cpp b/mods/src/skin/loader.cpp index a78c236c..aa50ee87 100644 --- a/mods/src/skin/loader.cpp +++ b/mods/src/skin/loader.cpp @@ -65,7 +65,7 @@ static void load_pending_skins(__attribute__((unused)) Minecraft *minecraft) { // Skin Server static std::string get_skin_server() { - const char *custom_server = getenv("MCPI_SKIN_SERVER"); + const char *custom_server = getenv(MCPI_SKIN_SERVER_ENV); if (custom_server != nullptr) { return custom_server; } else {