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