Cache Launcher Configuration

This commit is contained in:
TheBrokenRail 2022-09-22 17:43:21 -04:00
parent 02c73176a5
commit f328800ce8
17 changed files with 238 additions and 17 deletions

View File

@ -25,6 +25,9 @@ If you run MCPI-Reborn with ``--benchmark``, it will enter a simple benchmark mo
The world used will always be re-created on start and uses a hard-coded seed. The world used will always be re-created on start and uses a hard-coded seed.
### ``--no-cache`` (Client Mode Only)
If you run MCPI-Reborn with ``--no-cache``, it will skip loading and saving the cached launcher configuration.
## Environmental Variables ## Environmental Variables
### ``MCPI_DEBUG`` ### ``MCPI_DEBUG``

View File

@ -9,7 +9,7 @@ if(MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c) target_sources(launcher PRIVATE src/server/launcher.c)
else() else()
embed_resource(launcher src/client/available-feature-flags) embed_resource(launcher src/client/available-feature-flags)
target_sources(launcher PRIVATE src/client/launcher.cpp) target_sources(launcher PRIVATE src/client/launcher.cpp src/client/cache.cpp)
endif() endif()
target_link_libraries(launcher reborn-util) target_link_libraries(launcher reborn-util)
# RPath # RPath

View File

@ -101,6 +101,9 @@ void pre_bootstrap(int argc, char *argv[]) {
// Disable stdout Buffering // Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);
// Set Debug Tag
reborn_debug_tag = "(Launcher) ";
// Set Default Native Component Environment // Set Default Native Component Environment
#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name)); #define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name));
for_each_special_environmental_variable(set_variable_default); for_each_special_environmental_variable(set_variable_default);

View File

@ -0,0 +1,137 @@
#include <cstdlib>
#include <string>
#include <fstream>
#include <unordered_map>
#include <sstream>
#include <sys/stat.h>
#include <libreborn/libreborn.h>
#include "launcher.h"
#include "cache.h"
// Get Cache Path
static std::string get_cache_path() {
const char *home = getenv("HOME");
if (home == NULL) {
IMPOSSIBLE();
}
return std::string(home) + "/.minecraft-pi/.launcher-cache";
}
// Load
launcher_cache empty_cache = {
.username = DEFAULT_USERNAME,
.render_distance = DEFAULT_RENDER_DISTANCE,
.feature_flags = {}
};
launcher_cache load_cache() {
// Log
DEBUG("Loading Launcher Cache...");
// Open File
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
if (!stream) {
// No Warning If File Doesn't Exist
struct stat s;
if (stat(get_cache_path().c_str(), &s) == 0) {
WARN("Unable To Open Launcher Cache For Loading");
}
return empty_cache;
}
// Check Version
unsigned char cache_version;
stream.read((char *) &cache_version, 1);
if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) {
WARN("Invalid Launcher Cache Version");
stream.close();
return empty_cache;
}
// Load Username And Render Distance
launcher_cache cache;
std::getline(stream, cache.username, '\0');
std::getline(stream, cache.render_distance, '\0');
// Load Feature Flags
std::string flag;
while (!stream.eof() && std::getline(stream, flag, '\0')) {
if (flag.length() > 0) {
unsigned char is_enabled = 0;
stream.read((char *) &is_enabled, 1);
cache.feature_flags[flag] = is_enabled != (unsigned char) 0;
}
stream.peek();
}
// Finish
stream.close();
if (!stream) {
WARN("Failure While Loading Launcher Cache: %s", strerror(errno));
return empty_cache;
}
// Return
return cache;
}
// Save
#define write_env_to_stream(stream, env) \
{ \
const char *env_value = getenv(env); \
if (env == NULL) { \
IMPOSSIBLE(); \
} \
stream.write(env_value, strlen(env_value) + 1); \
}
void save_cache() {
// Log
DEBUG("Saving Launcher Cache...");
// Open File
std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary);
if (!stream) {
WARN("Unable To Open Launcher Cache For Saving");
return;
}
// Save Cache Version
unsigned char cache_version = (unsigned char) CACHE_VERSION;
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");
// Save Feature Flags
std::unordered_map<std::string, bool> flags;
load_available_feature_flags([&flags](std::string flag) {
std::string stripped_flag = strip_feature_flag_default(flag, NULL);
flags[stripped_flag] = false;
});
{
const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS");
if (enabled_flags == NULL) {
IMPOSSIBLE();
}
std::istringstream enabled_flags_stream(enabled_flags);
std::string flag;
while (std::getline(enabled_flags_stream, flag, '|')) {
if (flag.length() > 0) {
flags[flag] = true;
}
}
}
for (auto &it : flags) {
stream.write(it.first.c_str(), it.first.size() + 1);
unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0;
stream.write((const char *) &val, 1);
}
// Finish
stream.close();
if (!stream.good()) {
WARN("Failure While Saving Launcher Cache");
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <string>
#include <unordered_map>
// Cache Version
#define CACHE_VERSION 0
// Load Cache
typedef struct {
std::string username;
std::string render_distance;
std::unordered_map<std::string, bool> feature_flags;
} launcher_cache;
extern launcher_cache empty_cache;
launcher_cache load_cache();
// Save Cache
void save_cache();

View File

@ -10,9 +10,11 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "../bootstrap.h" #include "../bootstrap.h"
#include "launcher.h"
#include "cache.h"
// Strip Feature Flag Default // Strip Feature Flag Default
static std::string strip_feature_flag_default(std::string flag, bool *default_ret) { std::string strip_feature_flag_default(std::string flag, bool *default_ret) {
// Valid Values // Valid Values
std::string true_str = "TRUE "; std::string true_str = "TRUE ";
std::string false_str = "FALSE "; std::string false_str = "FALSE ";
@ -38,7 +40,7 @@ static std::string strip_feature_flag_default(std::string flag, bool *default_re
// Load Available Feature Flags // Load Available Feature Flags
extern unsigned char available_feature_flags[]; extern unsigned char available_feature_flags[];
extern size_t available_feature_flags_len; extern size_t available_feature_flags_len;
static void load_available_feature_flags(std::function<void(std::string)> callback) { void load_available_feature_flags(std::function<void(std::string)> callback) {
// Get Path // Get Path
char *binary_directory = get_binary_directory(); char *binary_directory = get_binary_directory();
std::string path = std::string(binary_directory) + "/available-feature-flags"; std::string path = std::string(binary_directory) + "/available-feature-flags";
@ -134,10 +136,6 @@ static void set_env_if_unset(const char *env_name, std::function<std::string()>
} }
} }
// Defaults
#define DEFAULT_USERNAME "StevePi"
#define DEFAULT_RENDER_DISTANCE "Short"
// Launch // Launch
#define LIST_DIALOG_SIZE "400" #define LIST_DIALOG_SIZE "400"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -146,6 +144,11 @@ int main(int argc, char *argv[]) {
ERR("Don't Run As Root"); ERR("Don't Run As Root");
} }
// Ensure HOME
if (getenv("HOME") == NULL) {
ERR("$HOME Isn't Set");
}
// Pre-Bootstrap // Pre-Bootstrap
pre_bootstrap(argc, argv); pre_bootstrap(argc, argv);
@ -192,6 +195,15 @@ int main(int argc, char *argv[]) {
} }
} }
// --no-cache
bool no_cache = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--no-cache") == 0) {
no_cache = true;
break;
}
}
// Create ~/.minecraft-pi If Needed // Create ~/.minecraft-pi If Needed
// Minecraft Folder // Minecraft Folder
{ {
@ -212,6 +224,9 @@ int main(int argc, char *argv[]) {
free(minecraft_folder); free(minecraft_folder);
} }
// Load Cache
launcher_cache cache = no_cache ? empty_cache : load_cache();
// Setup MCPI_FEATURE_FLAGS // Setup MCPI_FEATURE_FLAGS
{ {
std::vector<std::string> command; std::vector<std::string> command;
@ -225,12 +240,16 @@ int main(int argc, char *argv[]) {
command.push_back("Enabled"); command.push_back("Enabled");
command.push_back("--column"); command.push_back("--column");
command.push_back("Feature"); command.push_back("Feature");
load_available_feature_flags([&command](std::string flag) { load_available_feature_flags([&command, &cache](std::string flag) {
bool default_value; bool value;
// Strip Default Value // Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &default_value); std::string stripped_flag = strip_feature_flag_default(flag, &value);
// Use Cache
if (cache.feature_flags.count(stripped_flag) > 0) {
value = cache.feature_flags[stripped_flag];
}
// Specify Default Value // Specify Default Value
if (default_value) { if (value) {
// Enabled By Default // Enabled By Default
command.push_back("TRUE"); command.push_back("TRUE");
} else { } else {
@ -260,7 +279,7 @@ int main(int argc, char *argv[]) {
command.push_back("Name"); command.push_back("Name");
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"}; std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
for (std::string &render_distance : render_distances) { for (std::string &render_distance : render_distances) {
command.push_back(render_distance.compare(DEFAULT_RENDER_DISTANCE) == 0 ? "TRUE" : "FALSE"); command.push_back(render_distance.compare(cache.render_distance) == 0 ? "TRUE" : "FALSE");
command.push_back(render_distance); command.push_back(render_distance);
} }
// Run // Run
@ -273,11 +292,16 @@ int main(int argc, char *argv[]) {
command.push_back("--text"); command.push_back("--text");
command.push_back("Enter Minecraft Username:"); command.push_back("Enter Minecraft Username:");
command.push_back("--entry-text"); command.push_back("--entry-text");
command.push_back(DEFAULT_USERNAME); command.push_back(cache.username);
// Run // Run
run_zenity_and_set_env("MCPI_USERNAME", command); run_zenity_and_set_env("MCPI_USERNAME", command);
} }
// Save Cache
if (!no_cache) {
save_cache();
}
// Bootstrap // Bootstrap
bootstrap(argc, argv); bootstrap(argc, argv);
} }

View File

@ -0,0 +1,12 @@
#pragma once
#include <string>
#include <functional>
// Defaults
#define DEFAULT_USERNAME "StevePi"
#define DEFAULT_RENDER_DISTANCE "Short"
// Feature Flags
std::string strip_feature_flag_default(std::string flag, bool *default_ret);
void load_available_feature_flags(std::function<void(std::string)> callback);

View File

@ -98,6 +98,9 @@ void setup_crash_report() {
close(error_pipe[PIPE_WRITE]); close(error_pipe[PIPE_WRITE]);
close(input_pipe[PIPE_READ]); close(input_pipe[PIPE_READ]);
// Set Debug Tag
reborn_debug_tag = "(Crash Reporter) ";
// Setup Logging // Setup Logging
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
char buf[BUFFER_SIZE]; char buf[BUFFER_SIZE];

View File

@ -5,7 +5,7 @@ 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) configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY)
# Util # Util
add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c) add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c)
target_include_directories( target_include_directories(
reborn-util reborn-util
PUBLIC PUBLIC

View File

@ -32,6 +32,9 @@ void chop_last_component(char **str);
// Get Binary Directory (Remember To Free) // Get Binary Directory (Remember To Free)
char *get_binary_directory(); char *get_binary_directory();
// Debug Tag
#define CHILD_PROCESS_TAG "(Child Process) "
// Run Command And Get Output // Run Command And Get Output
char *run_command(const char *const command[], int *exit_status); char *run_command(const char *const command[], int *exit_status);
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0) #define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)

View File

@ -3,9 +3,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
// Debug Tag
extern const char *reborn_debug_tag;
// Logging // Logging
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); } #define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", ##__VA_ARGS__); }
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); } #define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", ##__VA_ARGS__); }
#define DEBUG(format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: " format "\n", ##__VA_ARGS__); } } #define RAW_DEBUG(tag, format, ...) { const char *debug = getenv("MCPI_DEBUG"); if (debug != NULL) { fprintf(stderr, "[DEBUG]: %s" format "\n", tag, ##__VA_ARGS__); } }
#define DEBUG(format, ...) RAW_DEBUG(reborn_debug_tag, format, ##__VA_ARGS__)
#define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } #define ERR(format, ...) { fprintf(stderr, "[ERR]: (%s:%i): " format "\n", __FILE__, __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); }
#define IMPOSSIBLE() ERR("This Should Never Be Called") #define IMPOSSIBLE() ERR("This Should Never Be Called")

View File

@ -82,6 +82,9 @@ char *run_command(const char *const command[], int *exit_status) {
} else if (ret == 0) { } else if (ret == 0) {
// Child Process // Child Process
// Set Debug Tag
reborn_debug_tag = CHILD_PROCESS_TAG;
// Pipe stdout // Pipe stdout
dup2(output_pipe[1], STDOUT_FILENO); dup2(output_pipe[1], STDOUT_FILENO);
close(output_pipe[0]); close(output_pipe[0]);

4
libreborn/src/util/log.c Normal file
View File

@ -0,0 +1,4 @@
#include <libreborn/log.h>
// Debug Tag
const char *reborn_debug_tag = "";

View File

@ -45,6 +45,9 @@ static void exit_handler(__attribute__((unused)) int signal_id) {
// Main // Main
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Set Debug Tag
reborn_debug_tag = PROXY_LOG_TAG;
// Install Signal Handlers // Install Signal Handlers
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
struct sigaction act_sigterm; struct sigaction act_sigterm;

View File

@ -22,7 +22,7 @@ extern "C" {
#define CONNECTED_MSG "Connected" #define CONNECTED_MSG "Connected"
#define PROXY_INFO(format, ...) DEBUG(PROXY_LOG_TAG format, ##__VA_ARGS__); #define PROXY_INFO(format, ...) RAW_DEBUG(PROXY_LOG_TAG, format, ##__VA_ARGS__);
#define PROXY_ERR(format, ...) { close_connection(); ERR(PROXY_LOG_TAG format, ##__VA_ARGS__); } #define PROXY_ERR(format, ...) { close_connection(); ERR(PROXY_LOG_TAG format, ##__VA_ARGS__); }
// Safely Send/Receive Data From The Connection // Safely Send/Receive Data From The Connection

View File

@ -64,6 +64,9 @@ static void start_media_layer_proxy_client(int read, int write) {
} else if (ret == 0) { } else if (ret == 0) {
// Child Process // Child Process
// Set Debug Tag
reborn_debug_tag = CHILD_PROCESS_TAG;
// Prepare Arguments // Prepare Arguments
char *read_str = NULL; char *read_str = NULL;
safe_asprintf(&read_str, "%i", read); safe_asprintf(&read_str, "%i", read);

View File

@ -31,4 +31,4 @@ export _MCPI_SKIP_ROOT_CHECK=1
# Run Benchmark # Run Benchmark
export HOME="$(pwd)/build/test" export HOME="$(pwd)/build/test"
minecraft-pi-reborn-client --default --benchmark minecraft-pi-reborn-client --default --no-cache --benchmark