Refactor Launcher

This commit is contained in:
TheBrokenRail 2024-05-12 03:19:01 -04:00
parent d7616419bc
commit 4d54a9d28c
32 changed files with 784 additions and 796 deletions

View File

@ -77,3 +77,6 @@ mcpi_option(APP_TITLE "App Title" STRING "${DEFAULT_APP_TITLE}")
# Skin Server # Skin Server
mcpi_option(SKIN_SERVER "Skin Server" STRING "https://raw.githubusercontent.com/MCPI-Revival/Skins/data") mcpi_option(SKIN_SERVER "Skin Server" STRING "https://raw.githubusercontent.com/MCPI-Revival/Skins/data")
# Discord Invite
mcpi_option(DISCORD_INVITE "Discord Invite URL" STRING "https://discord.gg/mcpi-revival-740287937727561779")

View File

@ -30,7 +30,7 @@ ExternalProject_Add(qemu
"--cross-prefix=" "--cross-prefix="
"--cc=${CMAKE_C_COMPILER}" "--cc=${CMAKE_C_COMPILER}"
"--cxx=${CMAKE_CXX_COMPILER}" "--cxx=${CMAKE_CXX_COMPILER}"
"--extra-ldflags=-ldl" "--extra-ldflags=-ldl -Wl,-rpath=$ORIGIN/../lib/native -Wl,--disable-new-dtags"
"--disable-debug-info" "--disable-debug-info"
"--target-list=arm-linux-user" "--target-list=arm-linux-user"
"--without-default-features" "--without-default-features"

View File

@ -2,19 +2,19 @@ project(launcher)
# Launcher # Launcher
add_executable(launcher add_executable(launcher
src/bootstrap.c src/bootstrap.cpp
src/patchelf.cpp src/patchelf.cpp
src/util.c src/util.c
src/crash-report.c src/crash-report.c
src/sdk.c src/sdk.cpp
src/mods.c src/mods.cpp
src/options/parser.cpp
src/main.cpp
) )
if(MCPI_SERVER_MODE) if(NOT MCPI_SERVER_MODE)
target_sources(launcher PRIVATE src/server/launcher.c)
else()
embed_resource(launcher src/client/available-feature-flags) embed_resource(launcher src/client/available-feature-flags)
target_sources(launcher PRIVATE target_sources(launcher PRIVATE
src/client/launcher.cpp src/client/configuration.cpp
src/client/cache.cpp src/client/cache.cpp
src/client/available-feature-flags # Show In IDE src/client/available-feature-flags # Show In IDE
) )
@ -22,6 +22,7 @@ endif()
target_link_libraries(launcher reborn-util LIB_LIEF) target_link_libraries(launcher reborn-util LIB_LIEF)
# RPath # RPath
set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native") set_target_properties(launcher PROPERTIES INSTALL_RPATH "$ORIGIN/lib/native")
target_link_options(launcher PRIVATE "LINKER:--disable-new-dtags")
# Install # Install
install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}") install(TARGETS launcher DESTINATION "${MCPI_INSTALL_DIR}")

View File

@ -1,361 +0,0 @@
#define _FILE_OFFSET_BITS 64
#include <libreborn/libreborn.h>
#include "util.h"
#include "bootstrap.h"
#include "patchelf.h"
#include "crash-report.h"
#define MCPI_BINARY "minecraft-pi"
#define QEMU_BINARY "qemu-arm"
#define REQUIRED_PAGE_SIZE 4096
#define _STR(x) #x
#define STR(x) _STR(x)
// Exit Handler
static void exit_handler(__attribute__((unused)) int signal_id) {
// Pass Signal To Child
murder_children();
while (wait(NULL) > 0) {}
_exit(EXIT_SUCCESS);
}
// Debug Information
static void run_debug_command(const char *const command[], const char *prefix) {
int status = 0;
char *output = run_command(command, &status, NULL);
if (output != NULL) {
// Remove Newline
size_t length = strlen(output);
if (length > 0 && output[length - 1] == '\n') {
output[length - 1] = '\0';
}
// Print
DEBUG("%s: %s", prefix, output);
free(output);
}
if (!is_exit_status_success(status)) {
ERR("Unable To Gather Debug Information");
}
}
static void print_debug_information() {
// System Information
const char *const command[] = {"uname", "-a", NULL};
run_debug_command(command, "System Information");
// Version
DEBUG("Reborn Version: v%s", MCPI_VERSION);
// Architecture
const char *arch = "Unknown";
#ifdef __x86_64__
arch = "AMD64";
#elif defined(__aarch64__)
arch = "ARM64";
#elif defined(__arm__)
arch = "ARM32";
#endif
DEBUG("Reborn Target Architecture: %s", arch);
}
// Pre-Bootstrap
void pre_bootstrap(int argc, char *argv[]) {
// Set Debug Tag
reborn_debug_tag = "(Launcher) ";
// Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0);
// Print Version
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
// Print
printf("Reborn v%s\n", MCPI_VERSION);
fflush(stdout);
exit(EXIT_SUCCESS);
}
}
// Setup Logging
setup_log_file();
// --debug
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--debug") == 0) {
set_and_print_env("MCPI_DEBUG", "1");
break;
}
}
// Set Default Native Component Environment
#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name));
for_each_special_environmental_variable(set_variable_default);
// GTK Dark Mode
#ifndef MCPI_SERVER_MODE
set_and_print_env("GTK_THEME", "Adwaita:dark");
#endif
// Configure PATH
{
// Get Binary Directory
char *binary_directory = get_binary_directory();
// Add Library Directory
char *new_path = NULL;
safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH
{
char *value = getenv("PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&new_path, ":%s", value);
}
}
// Set And Free
set_and_print_env("PATH", new_path);
free(new_path);
// Free Binary Directory
free(binary_directory);
}
// --copy-sdk
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--copy-sdk") == 0) {
char *binary_directory = get_binary_directory();
copy_sdk(binary_directory, 0);
free(binary_directory);
fflush(stdout);
exit(EXIT_SUCCESS);
}
}
// Setup Crash Reports
setup_crash_report();
// AppImage
#ifdef MCPI_IS_APPIMAGE_BUILD
{
char *owd = getenv("OWD");
if (owd != NULL && chdir(owd) != 0) {
ERR("AppImage: Unable To Fix Current Directory: %s", strerror(errno));
}
}
#endif
// Install Signal Handlers
struct sigaction act_sigint;
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
// Check Page Size (Not Needed When Using QEMU)
#ifndef MCPI_USE_QEMU
long page_size = sysconf(_SC_PAGESIZE);
if (page_size != REQUIRED_PAGE_SIZE) {
ERR("Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
}
#endif
// Debug Information
print_debug_information();
}
// Bootstrap
void bootstrap(int argc, char *argv[]) {
INFO("Configuring Game...");
// Get Binary Directory
char *binary_directory = get_binary_directory();
DEBUG("Binary Directory: %s", binary_directory);
// Copy SDK
copy_sdk(binary_directory, 1);
// Set MCPI_REBORN_ASSETS_PATH
{
char *assets_path = realpath("/proc/self/exe", NULL);
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);
}
// Resolve Binary Path & Set MCPI_DIRECTORY
char *resolved_path = NULL;
{
// Log
DEBUG("Resolving File Paths...");
// Resolve Full Binary Path
char *full_path = NULL;
safe_asprintf(&full_path, "%s/" MCPI_BINARY, binary_directory);
resolved_path = realpath(full_path, NULL);
ALLOC_CHECK(resolved_path);
free(full_path);
}
// Fix MCPI Dependencies
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
{
// Log
DEBUG("Patching ELF Dependencies...");
// Find Linker
char *linker = NULL;
// Select Linker
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
// Use ARM Sysroot Linker
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory);
#else
// Use Current Linker
linker = patch_get_interpreter();
#endif
// Patch
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
// Free Linker Path
if (linker != NULL) {
free(linker);
}
// Verify
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
IMPOSSIBLE();
}
}
// 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);
}
// Free Resolved Path
free(resolved_path);
// Configure Library Search Path
{
// Log
DEBUG("Setting Linker Search Paths...");
// Prepare
char *transitive_ld_path = NULL;
char *mcpi_ld_path = NULL;
// Library Search Path For Native Components
{
// Add Native Library Directory
safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&transitive_ld_path, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path);
free(transitive_ld_path);
}
// Library Search Path For ARM Components
{
// Add ARM Library Directory
safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory);
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory);
#endif
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&mcpi_ld_path, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path);
free(mcpi_ld_path);
}
}
// Configure Preloaded Objects
{
// Log
DEBUG("Locating Mods...");
// Native Components
char *host_ld_preload = getenv("LD_PRELOAD");
set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
// ARM Components
bootstrap_mods(binary_directory);
}
// Free Binary Directory
free(binary_directory);
// Start Game
INFO("Starting Game...");
// Arguments
int argv_start = 1; // argv = &new_args[argv_start]
const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
// Copy Existing Arguments
for (int i = 1; i < argc; i++) {
new_args[i + argv_start] = argv[i];
}
// NULL-Terminator
new_args[argv_start + argc] = NULL;
// Set Executable Argument
new_args[argv_start] = new_mcpi_exe_path;
// Non-ARM Systems Need QEMU
#ifdef MCPI_USE_QEMU
argv_start--;
new_args[argv_start] = QEMU_BINARY;
// Use 4k Page Size
set_and_print_env("QEMU_PAGESIZE", STR(REQUIRED_PAGE_SIZE));
#endif
// Setup Environment
setup_exec_environment(1);
// Pass LD_* Variables Through QEMU
#ifdef MCPI_USE_QEMU
char *qemu_set_env = NULL;
#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name));
for_each_special_environmental_variable(pass_variable_through_qemu);
set_and_print_env("QEMU_SET_ENV", qemu_set_env);
free(qemu_set_env);
// Treat QEMU Itself As A Native Component
setup_exec_environment(0);
#endif
// Run
const char **new_argv = &new_args[argv_start];
safe_execvpe(new_argv, (const char *const *) environ);
}

226
launcher/src/bootstrap.cpp Normal file
View File

@ -0,0 +1,226 @@
#define _FILE_OFFSET_BITS 64
#include <string>
#include <vector>
#include <libreborn/libreborn.h>
#include "util.h"
#include "bootstrap.h"
#include "patchelf.h"
#define MCPI_BINARY "minecraft-pi"
#define QEMU_BINARY "qemu-arm"
#define REQUIRED_PAGE_SIZE 4096
#define _STR(x) #x
#define STR(x) _STR(x)
// Debug Information
static void run_debug_command(const char *const command[], const char *prefix) {
int status = 0;
char *output = run_command(command, &status, nullptr);
if (output != nullptr) {
// Remove Newline
size_t length = strlen(output);
if (length > 0 && output[length - 1] == '\n') {
output[length - 1] = '\0';
}
// Print
DEBUG("%s: %s", prefix, output);
free(output);
}
if (!is_exit_status_success(status)) {
ERR("Unable To Gather Debug Information");
}
}
static void print_debug_information() {
// System Information
const char *const command[] = {"uname", "-a", nullptr};
run_debug_command(command, "System Information");
// Version
DEBUG("Reborn Version: v%s", MCPI_VERSION);
// Architecture
const char *arch = "Unknown";
#ifdef __x86_64__
arch = "AMD64";
#elif defined(__aarch64__)
arch = "ARM64";
#elif defined(__arm__)
arch = "ARM32";
#endif
DEBUG("Reborn Target Architecture: %s", arch);
}
// Bootstrap
void bootstrap() {
// Debug Information
print_debug_information();
// Check Page Size (Not Needed When Using QEMU)
#ifndef MCPI_USE_QEMU
long page_size = sysconf(_SC_PAGESIZE);
if (page_size != REQUIRED_PAGE_SIZE) {
ERR("Invalid page size! A page size of %ld bytes is required, but the system size is %ld bytes.", (long) REQUIRED_PAGE_SIZE, page_size);
}
#else
set_and_print_env("QEMU_PAGESIZE", STR(REQUIRED_PAGE_SIZE));
#endif
// Get Binary Directory
char *binary_directory_raw = get_binary_directory();
const std::string binary_directory = binary_directory_raw;
free(binary_directory_raw);
DEBUG("Binary Directory: %s", binary_directory.c_str());
// Copy SDK
copy_sdk(binary_directory, true);
// 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);
}
// Resolve Binary Path & Set MCPI_DIRECTORY
char *resolved_path = nullptr;
{
// 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);
}
// Fix MCPI Dependencies
char new_mcpi_exe_path[] = MCPI_PATCHED_DIR "/XXXXXX";
{
// Log
DEBUG("Patching ELF Dependencies...");
// Find Linker
char *linker = nullptr;
// Select Linker
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
// Use ARM Sysroot Linker
safe_asprintf(&linker, "%s/sysroot/lib/ld-linux-armhf.so.3", binary_directory.c_str());
#else
// Use Current Linker
linker = patch_get_interpreter();
#endif
// Patch
patch_mcpi_elf_dependencies(resolved_path, new_mcpi_exe_path, linker);
// Free Linker Path
if (linker != nullptr) {
free(linker);
}
// Verify
if (!starts_with(new_mcpi_exe_path, MCPI_PATCHED_DIR)) {
IMPOSSIBLE();
}
}
// 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);
}
// Free Resolved Path
free(resolved_path);
// Configure Library Search Path
{
// Log
DEBUG("Setting Linker Search Paths...");
// Prepare
std::string mcpi_ld_path = "";
// Library Search Path For ARM Components
{
// Add ARM Library Directory
mcpi_ld_path += binary_directory + "/lib/arm:";
// Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN
mcpi_ld_path += binary_directory + "/sysroot/lib:";
mcpi_ld_path += binary_directory + "/sysroot/lib/arm-linux-gnueabihf:";
mcpi_ld_path += binary_directory + "/sysroot/usr/lib:";
mcpi_ld_path += binary_directory + "/sysroot/usr/lib/arm-linux-gnueabihf:";
#endif
// Add Host LD_LIBRARY_PATH
{
char *value = getenv("LD_LIBRARY_PATH");
if (value != nullptr && strlen(value) > 0) {
mcpi_ld_path += value;
}
}
// Set
set_and_print_env(MCPI_LD_VARIABLE_PREFIX "LD_LIBRARY_PATH", mcpi_ld_path.c_str());
}
}
// Configure Preloaded Objects
{
// Log
DEBUG("Locating Mods...");
// ARM Components
bootstrap_mods(binary_directory);
}
// Start Game
INFO("Starting Game...");
// Arguments
std::vector<std::string> args;
// Non-ARM Systems Need QEMU
#ifdef MCPI_USE_QEMU
args.insert(args.begin(), QEMU_BINARY);
#endif
// Preserve Existing LD_* Variables
#define preserve_variable(name) set_and_print_env(MCPI_ORIGINAL_LD_VARIABLE_PREFIX name, getenv(name))
for_each_special_environmental_variable(preserve_variable);
set_and_print_env(MCPI_ORIGINAL_LD_VARIABLES_PRESERVED_ENV, "1");
// Setup Environment
setup_exec_environment(1);
// Pass LD_* Variables Through QEMU
#ifdef MCPI_USE_QEMU
#define pass_variable_through_qemu(name) args.push_back("-E"); args.push_back(std::string(name) + "=" + getenv(name))
for_each_special_environmental_variable(pass_variable_through_qemu);
// Treat QEMU Itself As A Native Component
setup_exec_environment(0);
#endif
// Specify MCPI Binary
args.push_back(new_mcpi_exe_path);
// Run
const char *new_argv[args.size() + 1];
for (std::vector<std::string>::size_type i = 0; i < args.size(); i++) {
new_argv[i] = args[i].c_str();
}
new_argv[args.size()] = nullptr;
safe_execvpe(new_argv, environ);
}

View File

@ -1,14 +1,7 @@
#pragma once #pragma once
#ifdef __cplusplus #include <string>
extern "C" {
#endif
void pre_bootstrap(int argc, char *argv[]); void bootstrap();
void bootstrap(int argc, char *argv[]); void copy_sdk(const std::string &binary_directory, bool log_with_debug);
void copy_sdk(char *binary_directory, int log_with_debug); void bootstrap_mods(const std::string &binary_directory);
void bootstrap_mods(char *binary_directory);
#ifdef __cplusplus
}
#endif

View File

@ -8,7 +8,7 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "launcher.h" #include "configuration.h"
#include "cache.h" #include "cache.h"
// Get Cache Path // Get Cache Path

View File

@ -10,25 +10,24 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "../util.h" #include "../util.h"
#include "../bootstrap.h" #include "configuration.h"
#include "launcher.h"
#include "cache.h" #include "cache.h"
// Strip Feature Flag Default // Strip Feature Flag Default
std::string strip_feature_flag_default(std::string flag, bool *default_ret) { std::string strip_feature_flag_default(const 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 ";
// Test // Test
if (flag.rfind(true_str, 0) == 0) { if (flag.rfind(true_str, 0) == 0) {
// Enabled By Default // Enabled By Default
if (default_ret != NULL) { if (default_ret != nullptr) {
*default_ret = true; *default_ret = true;
} }
return flag.substr(true_str.length(), std::string::npos); return flag.substr(true_str.length(), std::string::npos);
} else if (flag.rfind(false_str, 0) == 0) { } else if (flag.rfind(false_str, 0) == 0) {
// Disabled By Default // Disabled By Default
if (default_ret != NULL) { if (default_ret != nullptr) {
*default_ret = false; *default_ret = false;
} }
return flag.substr(false_str.length(), std::string::npos); return flag.substr(false_str.length(), std::string::npos);
@ -41,7 +40,7 @@ std::string strip_feature_flag_default(std::string flag, bool *default_ret) {
// 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;
void load_available_feature_flags(std::function<void(std::string)> callback) { void load_available_feature_flags(const 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";
@ -55,7 +54,7 @@ void load_available_feature_flags(std::function<void(std::string)> callback) {
{ {
std::string line; std::string line;
while (std::getline(stream, line)) { while (std::getline(stream, line)) {
if (line.length() > 0) { if (!line.empty()) {
// Verify Line // Verify Line
if (line.find('|') == std::string::npos) { if (line.find('|') == std::string::npos) {
lines.push_back(line); lines.push_back(line);
@ -67,15 +66,15 @@ void load_available_feature_flags(std::function<void(std::string)> callback) {
} }
} }
// Sort // Sort
std::sort(lines.begin(), lines.end(), [](std::string a, std::string b) { std::sort(lines.begin(), lines.end(), [](const std::string &a, const std::string &b) {
// Strip Defaults // Strip Defaults
std::string stripped_a = strip_feature_flag_default(a, NULL); std::string stripped_a = strip_feature_flag_default(a, nullptr);
std::string stripped_b = strip_feature_flag_default(b, NULL); std::string stripped_b = strip_feature_flag_default(b, nullptr);
// Sort // Sort
return stripped_a < stripped_b; return stripped_a < stripped_b;
}); });
// Run Callbacks // Run Callbacks
for (std::string &line : lines) { for (const std::string &line : lines) {
callback(line); callback(line);
} }
} }
@ -83,11 +82,11 @@ void load_available_feature_flags(std::function<void(std::string)> callback) {
// Run Command And Set Environmental Variable // Run Command And Set Environmental Variable
static void run_command_and_set_env(const char *env_name, const char *command[]) { static void run_command_and_set_env(const char *env_name, const char *command[]) {
// Only Run If Environmental Variable Is NULL // Only Run If Environmental Variable Is NULL
if (getenv(env_name) == NULL) { if (getenv(env_name) == nullptr) {
// Run // Run
int return_code; int return_code;
char *output = run_command(command, &return_code, NULL); char *output = run_command(command, &return_code, nullptr);
if (output != NULL) { if (output != nullptr) {
// Trim // Trim
int length = strlen(output); int length = strlen(output);
if (output[length - 1] == '\n') { if (output[length - 1] == '\n') {
@ -122,14 +121,14 @@ static void run_zenity_and_set_env(const char *env_name, std::vector<std::string
for (std::vector<std::string>::size_type i = 0; i < full_command.size(); i++) { for (std::vector<std::string>::size_type i = 0; i < full_command.size(); i++) {
full_command_array[i] = full_command[i].c_str(); full_command_array[i] = full_command[i].c_str();
} }
full_command_array[full_command.size()] = NULL; full_command_array[full_command.size()] = nullptr;
// Run // Run
run_command_and_set_env(env_name, full_command_array); run_command_and_set_env(env_name, full_command_array);
} }
// Set Variable If Not Already Set // Set Variable If Not Already Set
static void set_env_if_unset(const char *env_name, std::function<std::string()> callback) { static void set_env_if_unset(const char *env_name, const std::function<std::string()> &callback) {
if (getenv(env_name) == NULL) { if (getenv(env_name) == nullptr) {
char *value = strdup(callback().c_str()); char *value = strdup(callback().c_str());
ALLOC_CHECK(value); ALLOC_CHECK(value);
set_and_print_env(env_name, value); set_and_print_env(env_name, value);
@ -137,76 +136,50 @@ static void set_env_if_unset(const char *env_name, std::function<std::string()>
} }
} }
// Launch // Handle Non-Launch Commands
#define LIST_DIALOG_SIZE "400" void handle_non_launch_client_only_commands(const options_t &options) {
int main(int argc, char *argv[]) { // Print Available Feature Flags
// Don't Run As Root if (options.print_available_feature_flags) {
if (getenv("_MCPI_SKIP_ROOT_CHECK") == NULL && (getuid() == 0 || geteuid() == 0)) { load_available_feature_flags([](const std::string &line) {
ERR("Don't Run As Root"); printf("%s\n", line.c_str());
fflush(stdout);
});
exit(EXIT_SUCCESS);
} }
}
// Ensure HOME // Check Environment
if (getenv("HOME") == NULL) { void check_environment_client() {
ERR("$HOME Isn't Set"); // Don't Run As Root
if (getenv("_MCPI_SKIP_ROOT_CHECK") == nullptr && (getuid() == 0 || geteuid() == 0)) {
ERR("Don't Run As Root");
} }
// Check For Display // Check For Display
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
if (getenv("DISPLAY") == NULL && getenv("WAYLAND_DISPLAY") == NULL) { if (getenv("DISPLAY") == nullptr && getenv("WAYLAND_DISPLAY") == nullptr) {
ERR("No display attached! Make sure $DISPLAY or $WAYLAND_DISPLAY is set."); ERR("No display attached! Make sure $DISPLAY or $WAYLAND_DISPLAY is set.");
} }
#endif #endif
}
// Print Features // Configure Client Options
for (int i = 1; i < argc; i++) { #define LIST_DIALOG_SIZE "400"
if (strcmp(argv[i], "--print-available-feature-flags") == 0) { void configure_client(const options_t &options) {
// Print Available Feature Flags // Wipe Cache If Needed
load_available_feature_flags([](std::string line) { if (options.wipe_cache) {
printf("%s\n", line.c_str());
fflush(stdout);
});
return 0;
}
}
// Pre-Bootstrap
pre_bootstrap(argc, argv);
// Create ~/.minecraft-pi If Needed
{
char *minecraft_folder = NULL;
safe_asprintf(&minecraft_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA, getenv("HOME"));
const char *const command[] = {"mkdir", "-p", minecraft_folder, NULL};
run_simple_command(command, "Unable To Create Data Directory");
free(minecraft_folder);
}
// --wipe-cache
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--wipe-cache") == 0) {
wipe_cache(); wipe_cache();
break;
}
} }
// --no-cache
bool no_cache = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--no-cache") == 0) {
no_cache = true;
break;
}
}
// Load Cache // Load Cache
launcher_cache cache = no_cache ? empty_cache : load_cache(); launcher_cache cache = options.no_cache ? empty_cache : load_cache();
// --default // --default
for (int i = 1; i < argc; i++) { if (options.use_default) {
if (strcmp(argv[i], "--default") == 0) {
// Use Default Feature Flags // Use Default Feature Flags
set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() { set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() {
std::string feature_flags = ""; std::string feature_flags = "";
load_available_feature_flags([&feature_flags, &cache](std::string flag) { load_available_feature_flags([&feature_flags, &cache](const std::string &flag) {
bool value; bool value;
// Strip Default Value // Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &value); std::string stripped_flag = strip_feature_flag_default(flag, &value);
@ -220,7 +193,7 @@ int main(int argc, char *argv[]) {
feature_flags += stripped_flag + '|'; feature_flags += stripped_flag + '|';
} }
}); });
if (feature_flags.length() > 0 && feature_flags[feature_flags.length() - 1] == '|') { if (!feature_flags.empty() && feature_flags[feature_flags.length() - 1] == '|') {
feature_flags.pop_back(); feature_flags.pop_back();
} }
return feature_flags; return feature_flags;
@ -231,8 +204,6 @@ int main(int argc, char *argv[]) {
set_env_if_unset("MCPI_USERNAME", [&cache]() { set_env_if_unset("MCPI_USERNAME", [&cache]() {
return cache.username; return cache.username;
}); });
break;
}
} }
// Setup MCPI_FEATURE_FLAGS // Setup MCPI_FEATURE_FLAGS
@ -248,7 +219,7 @@ 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, &cache](std::string flag) { load_available_feature_flags([&command, &cache](const std::string &flag) {
bool value; bool value;
// Strip Default Value // Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &value); std::string stripped_flag = strip_feature_flag_default(flag, &value);
@ -287,7 +258,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(cache.render_distance) == 0 ? "TRUE" : "FALSE"); command.push_back(render_distance == cache.render_distance ? "TRUE" : "FALSE");
command.push_back(render_distance); command.push_back(render_distance);
} }
// Run // Run
@ -306,10 +277,7 @@ int main(int argc, char *argv[]) {
} }
// Save Cache // Save Cache
if (!no_cache) { if (!options.no_cache) {
save_cache(); save_cache();
} }
// Bootstrap
bootstrap(argc, argv);
} }

View File

@ -0,0 +1,23 @@
#pragma once
#include <string>
#include <functional>
#include "../options/parser.h"
// Defaults
#define DEFAULT_USERNAME "StevePi"
#define DEFAULT_RENDER_DISTANCE "Short"
// Feature Flags
std::string strip_feature_flag_default(const std::string& flag, bool *default_ret);
void load_available_feature_flags(const std::function<void(std::string)> &callback);
// Handle Non-Launch Commands
void handle_non_launch_client_only_commands(const options_t &options);
// Check Environment
void check_environment_client();
// Configure Client Options
void configure_client(const options_t &options);

View File

@ -1,12 +0,0 @@
#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

@ -34,7 +34,7 @@ static void show_report(const char *log_filename) {
"--width", CRASH_REPORT_DIALOG_WIDTH, "--width", CRASH_REPORT_DIALOG_WIDTH,
"--height", CRASH_REPORT_DIALOG_HEIGHT, "--height", CRASH_REPORT_DIALOG_HEIGHT,
"--text-info", "--text-info",
"--text", MCPI_APP_BASE_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"https://discord.com/invite/aDqejQGMMy\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_BASE_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>", "--text", MCPI_APP_BASE_TITLE " has crashed!\n\nNeed help? Consider asking on the <a href=\"" MCPI_DISCORD_INVITE "\">Discord server</a>! <i>If you believe this is a problem with " MCPI_APP_BASE_TITLE " itself, please upload this crash report to the #bugs Discord channel.</i>",
"--filename", log_filename, "--filename", log_filename,
"--no-wrap", "--no-wrap",
"--font", "Monospace", "--font", "Monospace",
@ -121,13 +121,11 @@ void setup_crash_report() {
track_child(ret); track_child(ret);
// Install Signal Handlers // Install Signal Handlers
struct sigaction act_sigint; struct sigaction act_sigint = {0};
memset((void *) &act_sigint, 0, sizeof (struct sigaction));
act_sigint.sa_flags = SA_RESTART; act_sigint.sa_flags = SA_RESTART;
act_sigint.sa_handler = &exit_handler; act_sigint.sa_handler = &exit_handler;
sigaction(SIGINT, &act_sigint, NULL); sigaction(SIGINT, &act_sigint, NULL);
struct sigaction act_sigterm; struct sigaction act_sigterm = {0};
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
act_sigterm.sa_flags = SA_RESTART; act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler; act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL); sigaction(SIGTERM, &act_sigterm, NULL);

154
launcher/src/main.cpp Normal file
View File

@ -0,0 +1,154 @@
#include <cstdlib>
#include <libreborn/libreborn.h>
#include <sys/stat.h>
#include "bootstrap.h"
#include "options/parser.h"
#include "crash-report.h"
#include "util.h"
#ifndef MCPI_SERVER_MODE
#include "client/configuration.h"
#endif
// 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);
}
}
static void setup_environment(const options_t &options) {
// Passthrough Options To Game
#ifndef MCPI_SERVER_MODE
bind_to_env("_MCPI_BENCHMARK", options.benchmark);
#else
bind_to_env("_MCPI_ONLY_GENERATE", options.only_generate);
#endif
// GTK Dark Mode
#ifndef MCPI_HEADLESS_MODE
set_and_print_env("GTK_THEME", "Adwaita:dark");
#endif
// Configure PATH
{
// Get Binary Directory
char *binary_directory = get_binary_directory();
std::string new_path = std::string(binary_directory) + "/bin";
free(binary_directory);
// Add Existing PATH
{
char *value = getenv("PATH");
if (value != nullptr && strlen(value) > 0) {
new_path += std::string(":") + value;
}
}
// Set And Free
set_and_print_env("PATH", new_path.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();
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
setvbuf(stdout, nullptr, _IONBF, 0);
// Environemntal Variable Options
setup_environment(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
#ifndef MCPI_SERVER_MODE
// Ensure $HOME
const char *home = getenv("HOME");
if (home == nullptr) {
ERR("$HOME Isn't Set");
}
// Create If Needed
{
std::string minecraft_folder = std::string(home) + 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(NULL, 0);
set_and_print_env("HOME", launch_directory);
free(launch_directory);
#endif
// Configure Client Options
#ifndef MCPI_SERVER_MODE
configure_client(options);
#endif
// Bootstrap
bootstrap();
}
// Main
int main(int argc, char *argv[]) {
// Parse Options
options_t options = parse_options(argc, argv);
// Set Debug Tag
reborn_debug_tag = "(Launcher) ";
// Debug Logging
bind_to_env(MCPI_DEBUG_ENV, options.debug);
// Handle Non-Launch Commands (Copy SDK, Print Feature Flags, Etc)
handle_non_launch_commands(options);
#ifndef MCPI_SERVER_MODE
handle_non_launch_client_only_commands(options);
#endif
// Check Environment
#ifndef MCPI_SERVER_MODE
// Code After This Can Safely Open A Window
check_environment_client();
#endif
// Start The Game
start_game(options);
}

View File

@ -1,110 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "bootstrap.h"
// Get All Mods In Folder
static void load(char **ld_preload, const char *folder) {
int folder_name_length = strlen(folder);
// Open Folder
DIR *dp = opendir(folder);
if (dp != NULL) {
// Loop Through Folder
struct dirent *entry = NULL;
errno = 0;
while (1) {
errno = 0;
entry = readdir(dp);
if (entry != NULL) {
// Check If File Is Regular
if (entry->d_type == DT_REG) {
// Get Full Name
int name_length = strlen(entry->d_name);
int total_length = folder_name_length + name_length;
char name[total_length + 1];
// Concatenate Folder Name And File Name
for (int i = 0; i < folder_name_length; i++) {
name[i] = folder[i];
}
for (int i = 0; i < name_length; i++) {
name[folder_name_length + i] = entry->d_name[i];
}
// Add Terminator
name[total_length] = '\0';
// Check If File Is Accessible
int result = access(name, R_OK);
if (result == 0) {
// Add To LD_PRELOAD
string_append(ld_preload, "%s%s", *ld_preload == NULL ? "" : ":", name);
} else if (result == -1 && errno != 0) {
// Fail
WARN("Unable To Access: %s: %s", name, strerror(errno));
errno = 0;
}
}
} else if (errno != 0) {
// Error Reading Contents Of Folder
ERR("Error Reading Directory: %s: %s", folder, strerror(errno));
} else {
// Done!
break;
}
}
// Close Folder
closedir(dp);
} else if (errno == ENOENT) {
// Folder Doesn't Exist
} else {
// Unable To Open Folder
ERR("Error Opening Directory: %s: %s", folder, strerror(errno));
}
}
// Bootstrap Mods
void bootstrap_mods(char *binary_directory) {
// Prepare
char *preload = NULL;
// ~/.minecraft-pi/mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME"));
// Load Mods From ./mods
load(&preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Built-In Mods
{
// Get Mods Folder
char *mods_folder = NULL;
safe_asprintf(&mods_folder, "%s/mods/", binary_directory);
// Load Mods From ./mods
load(&preload, mods_folder);
// Free Mods Folder
free(mods_folder);
}
// Add LD_PRELOAD
{
char *value = getenv("LD_PRELOAD");
if (value != NULL && strlen(value) > 0) {
string_append(&preload, ":%s", value);
}
}
// Set
set_and_print_env("MCPI_ARM_LD_PRELOAD", preload);
free(preload);
}

86
launcher/src/mods.cpp Normal file
View File

@ -0,0 +1,86 @@
#include <dirent.h>
#include <cerrno>
#include <sys/stat.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "bootstrap.h"
// Get All Mods In Folder
static void load(std::string &ld_preload, const std::string &folder) {
// Open Folder
DIR *dp = opendir(folder.c_str());
if (dp != nullptr) {
// Loop Through Folder
while (true) {
errno = 0;
dirent *entry = readdir(dp);
if (entry != nullptr) {
// Check If File Is Regular
if (entry->d_type == DT_REG) {
// Get Full Name
std::string name = folder + entry->d_name;
// Check If File Is Accessible
int result = access(name.c_str(), R_OK);
if (result == 0) {
// Add To LD_PRELOAD
ld_preload += name + ":";
} else if (result == -1 && errno != 0) {
// Fail
WARN("Unable To Access: %s: %s", name.c_str(), strerror(errno));
errno = 0;
}
}
} else if (errno != 0) {
// Error Reading Contents Of Folder
ERR("Error Reading Directory: %s: %s", folder.c_str(), strerror(errno));
} else {
// Done!
break;
}
}
// 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));
}
}
// Bootstrap Mods
#define SUBDIRECTORY_FOR_MODS "/mods/"
void bootstrap_mods(const std::string &binary_directory) {
// Prepare
std::string preload = "";
// ~/.minecraft-pi/mods
{
// Get Mods Folder
std::string mods_folder = std::string(getenv("HOME")) + HOME_SUBDIRECTORY_FOR_GAME_DATA SUBDIRECTORY_FOR_MODS;
// Load Mods From ./mods
load(preload, mods_folder);
}
// Built-In Mods
{
// Get Mods Folder
std::string mods_folder = binary_directory + SUBDIRECTORY_FOR_MODS;
// Load Mods From ./mods
load(preload, mods_folder);
}
// Add LD_PRELOAD
{
const char *value = getenv("LD_PRELOAD");
if (value != nullptr && strlen(value) > 0) {
preload += value;
}
}
// Set
set_and_print_env(MCPI_LD_VARIABLE_PREFIX "LD_PRELOAD", preload.c_str());
}

View File

@ -0,0 +1,12 @@
OPTION(debug, "debug", 'd', "Enable Debug Logging (" MCPI_DEBUG_ENV ")")
OPTION(copy_sdk, "copy-sdk", -2, "Extract Modding SDK And Exit")
OPTION(disable_crash_report, "disable-crash-report", -1, "Disable Crash Report Dialog")
#ifndef MCPI_SERVER_MODE
OPTION(use_default, "default", -3, "Skip Configuration Dialogs")
OPTION(no_cache, "no-cache", -4, "Disable Configuration Cache")
OPTION(wipe_cache, "wipe-cache", -5, "Wipe Cached Configuration")
OPTION(print_available_feature_flags, "print-available-feature-flags", -6, "Print Available Feature Flags")
OPTION(benchmark, "benchmark", -7, "Run Benchmark")
#else
OPTION(only_generate, "only-generate", -8, "Generate World And Exit")
#endif

View File

@ -0,0 +1,38 @@
#include <argp.h>
#include "parser.h"
// Globals
const char *argp_program_version = "Reborn v" MCPI_VERSION;
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 argp_option options_data[] = {
#include "option-list.h"
{nullptr, 0, nullptr, 0, nullptr, 0}
};
#undef OPTION
// Parse Options
#define OPTION(name, ignored, key, ...) \
case key: \
options->name = true; \
break;
static error_t parse_opt(int key, __attribute__((unused)) char *arg, argp_state *state) {
options_t *options = (options_t *) state->input;
switch (key) {
#include "option-list.h"
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
#undef OPTION
static argp argp = {options_data, parse_opt, nullptr, doc, nullptr, nullptr, nullptr};
options_t parse_options(int argc, char *argv[]) {
options_t options = {};
argp_parse(&argp, argc, argv, 0, nullptr, &options);
return options;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <libreborn/libreborn.h>
#define OPTION(name, ...) bool name;
struct options_t {
#include "option-list.h"
};
#undef OPTION
options_t parse_options(int argc, char *argv[]);

View File

@ -1,67 +0,0 @@
#include <libreborn/libreborn.h>
#include "bootstrap.h"
#include "util.h"
// Log
#define LOG(is_debug, ...) \
{ \
if (is_debug) { \
DEBUG(__VA_ARGS__); \
} else { \
INFO(__VA_ARGS__); \
} \
}
// Copy SDK Into ~/.minecraft-pi
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
void copy_sdk(char *binary_directory, int log_with_debug) {
// Ensure SDK Directory
{
char *sdk_path = NULL;
safe_asprintf(&sdk_path, "%s" HOME_SUBDIRECTORY_FOR_SDK, getenv("HOME"));
const char *const command[] = {"mkdir", "-p", sdk_path, NULL};
run_simple_command(command, "Unable To Create SDK Directory");
}
// Lock File
char *lock_file_path = NULL;
safe_asprintf(&lock_file_path, "%s" HOME_SUBDIRECTORY_FOR_SDK "/.lock", getenv("HOME"));
int lock_file_fd = lock_file(lock_file_path);
// Output Directory
char *output = NULL;
safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_SDK "/" MCPI_SDK_DIR, getenv("HOME"));
// Source Directory
char *source = NULL;
safe_asprintf(&source, "%s/sdk/.", binary_directory);
// Clean
{
const char *const command[] = {"rm", "-rf", output, NULL};
run_simple_command(command, "Unable To Clean SDK Output Directory");
}
// Make Directory
{
const char *const command[] = {"mkdir", "-p", output, NULL};
run_simple_command(command, "Unable To Create SDK Output Directory");
}
// Copy
{
const char *const command[] = {"cp", "-ar", source, output, NULL};
run_simple_command(command, "Unable To Copy SDK");
}
// Log
LOG(log_with_debug, "Copied SDK To: %s", output);
// Free
free(output);
free(source);
// Unlock File
unlock_file(lock_file_path, lock_file_fd);
free(lock_file_path);
}

59
launcher/src/sdk.cpp Normal file
View File

@ -0,0 +1,59 @@
#include <libreborn/libreborn.h>
#include "bootstrap.h"
#include "util.h"
// Log
#define LOG(is_debug, ...) \
{ \
if (is_debug) { \
DEBUG(__VA_ARGS__); \
} else { \
INFO(__VA_ARGS__); \
} \
}
// Copy SDK Into ~/.minecraft-pi
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
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;
const char *const command[] = {"mkdir", "-p", sdk_path.c_str(), nullptr};
run_simple_command(command, "Unable To Create SDK Directory");
}
// Lock File
std::string lock_file_path = sdk_path + "/.lock";
int lock_file_fd = lock_file(lock_file_path.c_str());
// Output Directory
std::string output = sdk_path + "/" MCPI_SDK_DIR;
// Source Directory
std::string source = binary_directory + "/sdk/.";
// Clean
{
const char *const command[] = {"rm", "-rf", output.c_str(), nullptr};
run_simple_command(command, "Unable To Clean SDK Output Directory");
}
// Make Directory
{
const char *const command[] = {"mkdir", "-p", output.c_str(), nullptr};
run_simple_command(command, "Unable To Create SDK Output Directory");
}
// Copy
{
const char *const command[] = {"cp", "-ar", source.c_str(), output.c_str(), nullptr};
run_simple_command(command, "Unable To Copy SDK");
}
// Log
LOG(log_with_debug, "Copied SDK To: %s", output.c_str());
// Unlock File
unlock_file(lock_file_path.c_str(), lock_file_fd);
}

View File

@ -1,19 +0,0 @@
#include <stdlib.h>
#include <unistd.h>
#include <libreborn/libreborn.h>
#include "../bootstrap.h"
int main(int argc, char *argv[]) {
// Pre-Bootstrap
pre_bootstrap(argc, argv);
// Set Home To Current Directory, So World Data Is Stored There
char *launch_directory = getcwd(NULL, 0);
set_and_print_env("HOME", launch_directory);
free(launch_directory);
// Bootstrap
bootstrap(argc, argv);
}

View File

@ -14,3 +14,4 @@
#cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@" #cmakedefine MCPI_SDK_DIR "@MCPI_SDK_DIR@"
#cmakedefine MCPI_SKIN_SERVER "@MCPI_SKIN_SERVER@" #cmakedefine MCPI_SKIN_SERVER "@MCPI_SKIN_SERVER@"
#cmakedefine MCPI_USE_QEMU #cmakedefine MCPI_USE_QEMU
#cmakedefine MCPI_DISCORD_INVITE "@MCPI_DISCORD_INVITE@"

View File

@ -20,9 +20,12 @@ extern "C" {
void set_and_print_env(const char *name, const char *value); void set_and_print_env(const char *name, const char *value);
// Safe execvpe() // Safe execvpe()
#define MCPI_LD_VARIABLE_PREFIX "_MCPI_"
#define MCPI_ORIGINAL_LD_VARIABLE_PREFIX MCPI_LD_VARIABLE_PREFIX "ORIGINAL_"
#define MCPI_ORIGINAL_LD_VARIABLES_PRESERVED_ENV MCPI_ORIGINAL_LD_VARIABLE_PREFIX "PRESERVED"
#define for_each_special_environmental_variable(handle) \ #define for_each_special_environmental_variable(handle) \
handle("LD_LIBRARY_PATH"); \ handle("LD_LIBRARY_PATH"); \
handle("LD_PRELOAD"); handle("LD_PRELOAD")
void setup_exec_environment(int is_arm_component); void setup_exec_environment(int is_arm_component);
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]); __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);

View File

@ -8,6 +8,7 @@ extern "C" {
#endif #endif
// Debug // Debug
#define MCPI_DEBUG_ENV "MCPI_DEBUG"
extern const char *reborn_debug_tag; extern const char *reborn_debug_tag;
int reborn_get_debug_fd(); int reborn_get_debug_fd();

View File

@ -21,12 +21,14 @@ void set_and_print_env(const char *name, const char *value) {
// Safe execvpe() // Safe execvpe()
#define handle_environmental_variable(var) \ #define handle_environmental_variable(var) \
{ \ { \
const char *full_var = is_arm_component ? "MCPI_ARM_" var : "MCPI_NATIVE_" var; \ const char *full_var = is_arm_component ? MCPI_LD_VARIABLE_PREFIX var : MCPI_ORIGINAL_LD_VARIABLE_PREFIX var; \
const char *var_value = getenv(full_var); \ const char *var_value = getenv(full_var); \
set_and_print_env(var, var_value); \ set_and_print_env(var, var_value); \
} }
void setup_exec_environment(int is_arm_component) { void setup_exec_environment(int is_arm_component) {
if (is_arm_component || getenv(MCPI_ORIGINAL_LD_VARIABLES_PRESERVED_ENV) != NULL) {
for_each_special_environmental_variable(handle_environmental_variable); for_each_special_environmental_variable(handle_environmental_variable);
}
} }
__attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) { __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
// Log // Log
@ -89,7 +91,7 @@ char *run_command(const char *const command[], int *exit_status, size_t *output_
char buf[BUFFER_SIZE]; char buf[BUFFER_SIZE];
size_t position = 0; size_t position = 0;
ssize_t bytes_read = 0; ssize_t bytes_read = 0;
while ((bytes_read = read(output_pipe[0], (void *) buf, BUFFER_SIZE)) > 0) { while ((bytes_read = read(output_pipe[0], buf, BUFFER_SIZE)) > 0) {
// Grow Output If Needed // Grow Output If Needed
size_t needed_size = position + bytes_read; size_t needed_size = position + bytes_read;
if (needed_size > size) { if (needed_size > size) {

View File

@ -7,7 +7,7 @@ const char *reborn_debug_tag = "";
// Debug FD // Debug FD
int reborn_get_debug_fd() { int reborn_get_debug_fd() {
if (getenv("MCPI_DEBUG") != NULL) { if (getenv(MCPI_DEBUG_ENV) != NULL) {
return STDERR_FILENO; return STDERR_FILENO;
} else { } else {
static int debug_fd = -1; static int debug_fd = -1;

View File

@ -6,7 +6,7 @@
#include "common/common.h" #include "common/common.h"
CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params)) CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pname, (uint32_t) params); trampoline(pname, (uint32_t) params);
#else #else
GLenum pname = next_int(); GLenum pname = next_int();
@ -17,7 +17,7 @@ CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params))
} }
// 'pointer' Is Only Supported As An Integer, Not As An Actual Pointer // 'pointer' Is Only Supported As An Integer, Not As An Actual Pointer
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
#define CALL_GL_POINTER(unique_id, name) \ #define CALL_GL_POINTER(unique_id, name) \
CALL(unique_id, name, void, (GLint size, GLenum type, GLsizei stride, const void *pointer)) \ CALL(unique_id, name, void, (GLint size, GLenum type, GLsizei stride, const void *pointer)) \
trampoline(size, type, stride, (uint32_t) pointer); \ trampoline(size, type, stride, (uint32_t) pointer); \
@ -37,7 +37,7 @@ CALL(11, glFogfv, void, (GLenum pname, const GLfloat *params))
CALL_GL_POINTER(12, glVertexPointer) CALL_GL_POINTER(12, glVertexPointer)
CALL(13, glLineWidth, void, (GLfloat width)) CALL(13, glLineWidth, void, (GLfloat width))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, width)); trampoline(pun_to(uint32_t, width));
#else #else
GLfloat width = next_float(); GLfloat width = next_float();
@ -47,7 +47,7 @@ CALL(13, glLineWidth, void, (GLfloat width))
} }
CALL(14, glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) CALL(14, glBlendFunc, void, (GLenum sfactor, GLenum dfactor))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(sfactor, dfactor); trampoline(sfactor, dfactor);
#else #else
GLenum sfactor = next_int(); GLenum sfactor = next_int();
@ -58,7 +58,7 @@ CALL(14, glBlendFunc, void, (GLenum sfactor, GLenum dfactor))
} }
CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(mode, first, count); trampoline(mode, first, count);
#else #else
GLenum mode = next_int(); GLenum mode = next_int();
@ -70,7 +70,7 @@ CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count))
} }
CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha)); trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha));
#else #else
GLfloat red = next_float(); GLfloat red = next_float();
@ -83,7 +83,7 @@ CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alp
} }
CALL(17, glClear, void, (GLbitfield mask)) CALL(17, glClear, void, (GLbitfield mask))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(mask); trampoline(mask);
#else #else
GLbitfield mask = next_int(); GLbitfield mask = next_int();
@ -93,7 +93,7 @@ CALL(17, glClear, void, (GLbitfield mask))
} }
CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage)) CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, size, (uint32_t) data, usage); trampoline(target, size, (uint32_t) data, usage);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -106,7 +106,7 @@ CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data,
} }
CALL(19, glFogx, void, (GLenum pname, GLfixed param)) CALL(19, glFogx, void, (GLenum pname, GLfixed param))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pname, param); trampoline(pname, param);
#else #else
GLenum pname = next_int(); GLenum pname = next_int();
@ -117,7 +117,7 @@ CALL(19, glFogx, void, (GLenum pname, GLfixed param))
} }
CALL(20, glFogf, void, (GLenum pname, GLfloat param)) CALL(20, glFogf, void, (GLenum pname, GLfloat param))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pname, pun_to(uint32_t, param)); trampoline(pname, pun_to(uint32_t, param));
#else #else
GLenum pname = next_int(); GLenum pname = next_int();
@ -128,7 +128,7 @@ CALL(20, glFogf, void, (GLenum pname, GLfloat param))
} }
CALL(21, glMatrixMode, void, (GLenum mode)) CALL(21, glMatrixMode, void, (GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(mode); trampoline(mode);
#else #else
GLenum mode = next_int(); GLenum mode = next_int();
@ -140,7 +140,7 @@ CALL(21, glMatrixMode, void, (GLenum mode))
CALL_GL_POINTER(22, glColorPointer) CALL_GL_POINTER(22, glColorPointer)
CALL(23, glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) CALL(23, glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(x, y, width, height); trampoline(x, y, width, height);
#else #else
GLint x = next_int(); GLint x = next_int();
@ -153,7 +153,7 @@ CALL(23, glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height))
} }
CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, pname, param); trampoline(target, pname, param);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -165,7 +165,7 @@ CALL(24, glTexParameteri, void, (GLenum target, GLenum pname, GLint param))
} }
CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)) CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, level, internalformat, width, height, border, format, type, (uint32_t) pixels); trampoline(target, level, internalformat, width, height, border, format, type, (uint32_t) pixels);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -183,7 +183,7 @@ CALL(25, glTexImage2D, void, (GLenum target, GLint level, GLint internalformat,
} }
CALL(26, glEnable, void, (GLenum cap)) CALL(26, glEnable, void, (GLenum cap))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(cap); trampoline(cap);
#else #else
GLenum cap = next_int(); GLenum cap = next_int();
@ -193,7 +193,7 @@ CALL(26, glEnable, void, (GLenum cap))
} }
CALL(27, glEnableClientState, void, (GLenum array)) CALL(27, glEnableClientState, void, (GLenum array))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(array); trampoline(array);
#else #else
GLenum array = next_int(); GLenum array = next_int();
@ -203,7 +203,7 @@ CALL(27, glEnableClientState, void, (GLenum array))
} }
CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units)) CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, factor), pun_to(uint32_t, units)); trampoline(pun_to(uint32_t, factor), pun_to(uint32_t, units));
#else #else
GLfloat factor = next_float(); GLfloat factor = next_float();
@ -216,7 +216,7 @@ CALL(28, glPolygonOffset, void, (GLfloat factor, GLfloat units))
CALL_GL_POINTER(41, glTexCoordPointer) CALL_GL_POINTER(41, glTexCoordPointer)
CALL(29, glDisableClientState, void, (GLenum array)) CALL(29, glDisableClientState, void, (GLenum array))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(array); trampoline(array);
#else #else
GLenum array = next_int(); GLenum array = next_int();
@ -226,7 +226,7 @@ CALL(29, glDisableClientState, void, (GLenum array))
} }
CALL(30, glDepthRangef, void, (GLclampf near, GLclampf far)) CALL(30, glDepthRangef, void, (GLclampf near, GLclampf far))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, near), pun_to(uint32_t, far)); trampoline(pun_to(uint32_t, near), pun_to(uint32_t, far));
#else #else
GLclampf near = next_float(); GLclampf near = next_float();
@ -237,7 +237,7 @@ CALL(30, glDepthRangef, void, (GLclampf near, GLclampf far))
} }
CALL(31, glDepthFunc, void, (GLenum func)) CALL(31, glDepthFunc, void, (GLenum func))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(func); trampoline(func);
#else #else
GLenum func2 = next_int(); GLenum func2 = next_int();
@ -247,7 +247,7 @@ CALL(31, glDepthFunc, void, (GLenum func))
} }
CALL(32, glBindBuffer, void, (GLenum target, GLuint buffer)) CALL(32, glBindBuffer, void, (GLenum target, GLuint buffer))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, buffer); trampoline(target, buffer);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -258,7 +258,7 @@ CALL(32, glBindBuffer, void, (GLenum target, GLuint buffer))
} }
CALL(33, glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) CALL(33, glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha)); trampoline(pun_to(uint32_t, red), pun_to(uint32_t, green), pun_to(uint32_t, blue), pun_to(uint32_t, alpha));
#else #else
GLclampf red = next_float(); GLclampf red = next_float();
@ -271,7 +271,7 @@ CALL(33, glClearColor, void, (GLclampf red, GLclampf green, GLclampf blue, GLcla
} }
CALL(34, glPopMatrix, void, ()) CALL(34, glPopMatrix, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -280,7 +280,7 @@ CALL(34, glPopMatrix, void, ())
} }
CALL(35, glLoadIdentity, void, ()) CALL(35, glLoadIdentity, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -289,7 +289,7 @@ CALL(35, glLoadIdentity, void, ())
} }
CALL(36, glScalef, void, (GLfloat x, GLfloat y, GLfloat z)) CALL(36, glScalef, void, (GLfloat x, GLfloat y, GLfloat z))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z)); trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
#else #else
GLfloat x = next_float(); GLfloat x = next_float();
@ -301,7 +301,7 @@ CALL(36, glScalef, void, (GLfloat x, GLfloat y, GLfloat z))
} }
CALL(37, glPushMatrix, void, ()) CALL(37, glPushMatrix, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -310,7 +310,7 @@ CALL(37, glPushMatrix, void, ())
} }
CALL(38, glDepthMask, void, (GLboolean flag)) CALL(38, glDepthMask, void, (GLboolean flag))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(flag); trampoline(flag);
#else #else
GLboolean flag = next_int(); GLboolean flag = next_int();
@ -320,7 +320,7 @@ CALL(38, glDepthMask, void, (GLboolean flag))
} }
CALL(39, glHint, void, (GLenum target, GLenum mode)) CALL(39, glHint, void, (GLenum target, GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, mode); trampoline(target, mode);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -331,7 +331,7 @@ CALL(39, glHint, void, (GLenum target, GLenum mode))
} }
CALL(40, glMultMatrixf, void, (const GLfloat *m)) CALL(40, glMultMatrixf, void, (const GLfloat *m))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline((uint32_t) m); trampoline((uint32_t) m);
#else #else
GLfloat *m = next_ptr(); GLfloat *m = next_ptr();
@ -341,7 +341,7 @@ CALL(40, glMultMatrixf, void, (const GLfloat *m))
} }
CALL(42, glDeleteBuffers, void, (GLsizei n, const GLuint *buffers)) CALL(42, glDeleteBuffers, void, (GLsizei n, const GLuint *buffers))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(n, (uint32_t) buffers); trampoline(n, (uint32_t) buffers);
#else #else
GLsizei n = next_int(); GLsizei n = next_int();
@ -352,7 +352,7 @@ CALL(42, glDeleteBuffers, void, (GLsizei n, const GLuint *buffers))
} }
CALL(43, glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) CALL(43, glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(red, green, blue, alpha); trampoline(red, green, blue, alpha);
#else #else
GLboolean red = next_int(); GLboolean red = next_int();
@ -365,7 +365,7 @@ CALL(43, glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLb
} }
CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)) CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, level, xoffset, yoffset, width, height, format, type, (uint32_t) pixels); trampoline(target, level, xoffset, yoffset, width, height, format, type, (uint32_t) pixels);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -383,7 +383,7 @@ CALL(44, glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLin
} }
CALL(45, glGenTextures, void, (GLsizei n, GLuint *textures)) CALL(45, glGenTextures, void, (GLsizei n, GLuint *textures))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(n, (uint32_t) textures); trampoline(n, (uint32_t) textures);
#else #else
GLsizei n = next_int(); GLsizei n = next_int();
@ -394,7 +394,7 @@ CALL(45, glGenTextures, void, (GLsizei n, GLuint *textures))
} }
CALL(46, glDeleteTextures, void, (GLsizei n, const GLuint *textures)) CALL(46, glDeleteTextures, void, (GLsizei n, const GLuint *textures))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(n, (uint32_t) textures); trampoline(n, (uint32_t) textures);
#else #else
GLsizei n = next_int(); GLsizei n = next_int();
@ -405,7 +405,7 @@ CALL(46, glDeleteTextures, void, (GLsizei n, const GLuint *textures))
} }
CALL(47, glAlphaFunc, void, (GLenum func, GLclampf ref)) CALL(47, glAlphaFunc, void, (GLenum func, GLclampf ref))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(func, pun_to(uint32_t, ref)); trampoline(func, pun_to(uint32_t, ref));
#else #else
GLenum func2 = next_int(); GLenum func2 = next_int();
@ -416,7 +416,7 @@ CALL(47, glAlphaFunc, void, (GLenum func, GLclampf ref))
} }
CALL(48, glGetFloatv, void, (GLenum pname, GLfloat *params)) CALL(48, glGetFloatv, void, (GLenum pname, GLfloat *params))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pname, (uint32_t) params); trampoline(pname, (uint32_t) params);
#else #else
GLenum pname = next_int(); GLenum pname = next_int();
@ -427,7 +427,7 @@ CALL(48, glGetFloatv, void, (GLenum pname, GLfloat *params))
} }
CALL(49, glBindTexture, void, (GLenum target, GLuint texture)) CALL(49, glBindTexture, void, (GLenum target, GLuint texture))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(target, texture); trampoline(target, texture);
#else #else
GLenum target = next_int(); GLenum target = next_int();
@ -438,7 +438,7 @@ CALL(49, glBindTexture, void, (GLenum target, GLuint texture))
} }
CALL(50, glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z)) CALL(50, glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z)); trampoline(pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
#else #else
GLfloat x = next_float(); GLfloat x = next_float();
@ -450,7 +450,7 @@ CALL(50, glTranslatef, void, (GLfloat x, GLfloat y, GLfloat z))
} }
CALL(51, glShadeModel, void, (GLenum mode)) CALL(51, glShadeModel, void, (GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(mode); trampoline(mode);
#else #else
GLenum mode = next_int(); GLenum mode = next_int();
@ -460,7 +460,7 @@ CALL(51, glShadeModel, void, (GLenum mode))
} }
CALL(52, glOrthof, void, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far)) CALL(52, glOrthof, void, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, left), pun_to(uint32_t, right), pun_to(uint32_t, bottom), pun_to(uint32_t, top), pun_to(uint32_t, near), pun_to(uint32_t, far)); trampoline(pun_to(uint32_t, left), pun_to(uint32_t, right), pun_to(uint32_t, bottom), pun_to(uint32_t, top), pun_to(uint32_t, near), pun_to(uint32_t, far));
#else #else
GLfloat left = next_float(); GLfloat left = next_float();
@ -475,7 +475,7 @@ CALL(52, glOrthof, void, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat t
} }
CALL(53, glDisable, void, (GLenum cap)) CALL(53, glDisable, void, (GLenum cap))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(cap); trampoline(cap);
#else #else
GLenum cap = next_int(); GLenum cap = next_int();
@ -485,7 +485,7 @@ CALL(53, glDisable, void, (GLenum cap))
} }
CALL(54, glCullFace, void, (GLenum mode)) CALL(54, glCullFace, void, (GLenum mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(mode); trampoline(mode);
#else #else
GLenum mode = next_int(); GLenum mode = next_int();
@ -495,7 +495,7 @@ CALL(54, glCullFace, void, (GLenum mode))
} }
CALL(55, glRotatef, void, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z)) CALL(55, glRotatef, void, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, angle), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z)); trampoline(pun_to(uint32_t, angle), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z));
#else #else
GLfloat angle = next_float(); GLfloat angle = next_float();
@ -508,7 +508,7 @@ CALL(55, glRotatef, void, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
} }
CALL(56, glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) CALL(56, glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(x, y, width, height); trampoline(x, y, width, height);
#else #else
GLint x = next_int(); GLint x = next_int();
@ -521,7 +521,7 @@ CALL(56, glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height))
} }
CALL(57, glNormal3f, void, (GLfloat nx, GLfloat ny, GLfloat nz)) CALL(57, glNormal3f, void, (GLfloat nx, GLfloat ny, GLfloat nz))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, nx), pun_to(uint32_t, ny), pun_to(uint32_t, nz)); trampoline(pun_to(uint32_t, nx), pun_to(uint32_t, ny), pun_to(uint32_t, nz));
#else #else
GLfloat nx = next_float(); GLfloat nx = next_float();
@ -533,7 +533,7 @@ CALL(57, glNormal3f, void, (GLfloat nx, GLfloat ny, GLfloat nz))
} }
CALL(58, glIsEnabled, GLboolean, (GLenum cap)) CALL(58, glIsEnabled, GLboolean, (GLenum cap))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline(cap); return trampoline(cap);
#else #else
GLenum cap = next_int(); GLenum cap = next_int();
@ -543,7 +543,7 @@ CALL(58, glIsEnabled, GLboolean, (GLenum cap))
} }
CALL(61, glGetIntegerv, void, (GLenum pname, GLint *params)) CALL(61, glGetIntegerv, void, (GLenum pname, GLint *params))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pname, (uint32_t) params); trampoline(pname, (uint32_t) params);
#else #else
GLenum pname = next_int(); GLenum pname = next_int();
@ -554,7 +554,7 @@ CALL(61, glGetIntegerv, void, (GLenum pname, GLint *params))
} }
CALL(65, glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data)) CALL(65, glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(x, y, width, height, format, type, (uint32_t) data); trampoline(x, y, width, height, format, type, (uint32_t) data);
#else #else
GLint x = next_int(); GLint x = next_int();
@ -570,7 +570,7 @@ CALL(65, glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, G
} }
CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers)) CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(n, (uint32_t) buffers); trampoline(n, (uint32_t) buffers);
#else #else
GLsizei n = next_int(); GLsizei n = next_int();

View File

@ -11,7 +11,7 @@
// SDL Functions // SDL Functions
CALL(0, SDL_Init, int, (uint32_t flags)) CALL(0, SDL_Init, int, (uint32_t flags))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline(flags); return trampoline(flags);
#else #else
uint32_t flags = next_int(); uint32_t flags = next_int();
@ -21,7 +21,7 @@ CALL(0, SDL_Init, int, (uint32_t flags))
} }
CALL(1, SDL_PollEvent, int, (SDL_Event *event)) CALL(1, SDL_PollEvent, int, (SDL_Event *event))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline((uint32_t) event); return trampoline((uint32_t) event);
#else #else
SDL_Event *event = next_ptr(); SDL_Event *event = next_ptr();
@ -31,7 +31,7 @@ CALL(1, SDL_PollEvent, int, (SDL_Event *event))
} }
CALL(2, SDL_PushEvent, int, (SDL_Event *event)) CALL(2, SDL_PushEvent, int, (SDL_Event *event))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline((uint32_t) event); return trampoline((uint32_t) event);
#else #else
SDL_Event *event = next_ptr(); SDL_Event *event = next_ptr();
@ -41,7 +41,7 @@ CALL(2, SDL_PushEvent, int, (SDL_Event *event))
} }
CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon)) CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline((uint32_t) title, (uint32_t) icon); trampoline((uint32_t) title, (uint32_t) icon);
#else #else
char *title = next_ptr(); char *title = next_ptr();
@ -52,7 +52,7 @@ CALL(3, SDL_WM_SetCaption, void, (const char *title, const char *icon))
} }
CALL(4, media_toggle_fullscreen, void, ()) CALL(4, media_toggle_fullscreen, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -61,7 +61,7 @@ CALL(4, media_toggle_fullscreen, void, ())
} }
CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode)) CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline(mode); return trampoline(mode);
#else #else
SDL_GrabMode mode = next_int(); SDL_GrabMode mode = next_int();
@ -71,7 +71,7 @@ CALL(5, SDL_WM_GrabInput, SDL_GrabMode, (SDL_GrabMode mode))
} }
CALL(6, SDL_ShowCursor, int, (int32_t toggle)) CALL(6, SDL_ShowCursor, int, (int32_t toggle))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline(toggle); return trampoline(toggle);
#else #else
int mode = next_int(); int mode = next_int();
@ -81,7 +81,7 @@ CALL(6, SDL_ShowCursor, int, (int32_t toggle))
} }
CALL(8, media_swap_buffers, void, ()) CALL(8, media_swap_buffers, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -90,7 +90,7 @@ CALL(8, media_swap_buffers, void, ())
} }
CALL(9, media_cleanup, void, ()) CALL(9, media_cleanup, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -99,7 +99,7 @@ CALL(9, media_cleanup, void, ())
} }
CALL(10, media_get_framebuffer_size, void, (int *width, int *height)) CALL(10, media_get_framebuffer_size, void, (int *width, int *height))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline((uint32_t) width, (uint32_t) height); trampoline((uint32_t) width, (uint32_t) height);
#else #else
int *width = next_ptr(); int *width = next_ptr();
@ -110,7 +110,7 @@ CALL(10, media_get_framebuffer_size, void, (int *width, int *height))
} }
CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw)) CALL(59, media_audio_update, void, (float volume, float x, float y, float z, float yaw))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(pun_to(uint32_t, volume), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, yaw)); trampoline(pun_to(uint32_t, volume), pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, yaw));
#else #else
float volume = next_float(); float volume = next_float();
@ -124,7 +124,7 @@ CALL(59, media_audio_update, void, (float volume, float x, float y, float z, flo
} }
CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui)) CALL(60, media_audio_play, void, (const char *source, const char *name, float x, float y, float z, float pitch, float volume, int is_ui))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline((uint32_t) source, (uint32_t) name, pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, pitch), pun_to(uint32_t, volume), is_ui); trampoline((uint32_t) source, (uint32_t) name, pun_to(uint32_t, x), pun_to(uint32_t, y), pun_to(uint32_t, z), pun_to(uint32_t, pitch), pun_to(uint32_t, volume), is_ui);
#else #else
char *source = next_ptr(); char *source = next_ptr();
@ -141,7 +141,7 @@ CALL(60, media_audio_play, void, (const char *source, const char *name, float x,
} }
CALL(62, media_set_interactable, void, (int is_interactable)) CALL(62, media_set_interactable, void, (int is_interactable))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(is_interactable); trampoline(is_interactable);
#else #else
int is_interactable = next_int(); int is_interactable = next_int();
@ -151,7 +151,7 @@ CALL(62, media_set_interactable, void, (int is_interactable))
} }
CALL(63, media_disable_vsync, void, ()) CALL(63, media_disable_vsync, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -160,7 +160,7 @@ CALL(63, media_disable_vsync, void, ())
} }
CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled)) CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled))
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(enabled); trampoline(enabled);
#else #else
int enabled = next_int(); int enabled = next_int();
@ -170,7 +170,7 @@ CALL(64, media_set_raw_mouse_motion_enabled, void, (int enabled))
} }
CALL(66, media_force_egl, void, ()) CALL(66, media_force_egl, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run
@ -179,7 +179,7 @@ CALL(66, media_force_egl, void, ())
} }
CALL(68, media_ensure_loaded, void, ()) CALL(68, media_ensure_loaded, void, ())
#if defined(MEDIA_LAYER_TRAMPOLINE_GUEST) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
trampoline(); trampoline();
#else #else
// Run // Run

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#include <libreborn/libreborn.h>
extern "C" { extern "C" {
void run_tests(); void run_tests();
void init_version(); void init_version();
@ -10,7 +8,7 @@ void init_compat();
void init_server(); void init_server();
#else #else
void init_multiplayer(); void init_multiplayer();
void init_benchmark(int argc, char *argv[]); void init_benchmark();
#endif #endif
#ifndef MCPI_HEADLESS_MODE #ifndef MCPI_HEADLESS_MODE
void init_sound(); void init_sound();

View File

@ -158,17 +158,9 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
} }
// Init Benchmark // Init Benchmark
void init_benchmark(int argc, char *argv[]) { void init_benchmark() {
// --benchmark: Activate Benchmark // --benchmark: Activate Benchmark
bool active = false; bool active = getenv("_MCPI_BENCHMARK") != nullptr;
for (int i = 1; i < argc; i++) {
// Check Argument
if (strcmp(argv[i], "--benchmark") == 0) {
// Enabled
active = true;
break;
}
}
if (active) { if (active) {
misc_run_on_update(Minecraft_update_injection); misc_run_on_update(Minecraft_update_injection);
// Track Ticks // Track Ticks

View File

@ -3,7 +3,7 @@
#include <media-layer/core.h> #include <media-layer/core.h>
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
__attribute__((constructor)) static void init(int argc, char *argv[]) { __attribute__((constructor)) static void init() {
media_ensure_loaded(); media_ensure_loaded();
reborn_init_patch(); reborn_init_patch();
run_tests(); run_tests();
@ -37,9 +37,6 @@ __attribute__((constructor)) static void init(int argc, char *argv[]) {
init_cake(); init_cake();
init_home(); init_home();
#ifndef MCPI_SERVER_MODE #ifndef MCPI_SERVER_MODE
init_benchmark(argc, argv); init_benchmark();
#else
(void) argc;
(void) argv;
#endif #endif
} }

View File

@ -234,7 +234,7 @@ CUSTOM_VTABLE(info_screen, Screen) {
self->handleBackEvent(false); self->handleBackEvent(false);
} else if (button->id == DISCORD_ID) { } else if (button->id == DISCORD_ID) {
// Open Discord Invite // Open Discord Invite
open_url("https://discord.gg/mcpi-revival-740287937727561779"); open_url(MCPI_DISCORD_INVITE);
} else if (button->id >= INFO_ID_START) { } else if (button->id >= INFO_ID_START) {
// Open Info URL // Open Info URL
int i = button->id - INFO_ID_START; int i = button->id - INFO_ID_START;

View File

@ -31,16 +31,8 @@
// --only-generate: Ony Generate World And Then Exit // --only-generate: Ony Generate World And Then Exit
static bool only_generate = false; static bool only_generate = false;
__attribute__((constructor)) static void _init_only_generate(int argc, char *argv[]) { __attribute__((constructor)) static void _init_only_generate() {
// Iterate Arguments only_generate = getenv("_MCPI_ONLY_GENERATE") != nullptr;
for (int i = 1; i < argc; i++) {
// Check Argument
if (strcmp(argv[i], "--only-generate") == 0) {
// Enabled
only_generate = true;
break;
}
}
} }
// Server Properties // Server Properties