284 lines
9.3 KiB
C++
Raw Normal View History

2022-07-13 23:35:05 -04:00
#include <sstream>
2021-06-17 17:32:24 -04:00
#include <cstring>
#include <cerrno>
#include <sys/wait.h>
2021-08-15 23:11:03 -04:00
#include <sys/stat.h>
2021-06-17 17:32:24 -04:00
#include <vector>
#include <functional>
2022-03-16 19:51:45 -04:00
#include <algorithm>
2021-06-17 17:32:24 -04:00
#include <libreborn/libreborn.h>
2023-11-24 22:16:13 -05:00
#include "../util.h"
2024-05-12 03:19:01 -04:00
#include "configuration.h"
2022-09-22 17:43:21 -04:00
#include "cache.h"
2021-06-17 17:32:24 -04:00
2022-03-16 19:51:45 -04:00
// Strip Feature Flag Default
2024-05-12 03:19:01 -04:00
std::string strip_feature_flag_default(const std::string &flag, bool *default_ret) {
2022-03-16 19:51:45 -04:00
// Valid Values
std::string true_str = "TRUE ";
std::string false_str = "FALSE ";
// Test
if (flag.rfind(true_str, 0) == 0) {
// Enabled By Default
2024-05-12 03:19:01 -04:00
if (default_ret != nullptr) {
2022-03-16 19:51:45 -04:00
*default_ret = true;
}
return flag.substr(true_str.length(), std::string::npos);
} else if (flag.rfind(false_str, 0) == 0) {
// Disabled By Default
2024-05-12 03:19:01 -04:00
if (default_ret != nullptr) {
2022-03-16 19:51:45 -04:00
*default_ret = false;
}
return flag.substr(false_str.length(), std::string::npos);
} else {
// Invalid
2022-04-14 21:12:42 -04:00
ERR("Invalid Feature Flag Default");
2022-03-16 19:51:45 -04:00
}
}
2021-06-17 17:32:24 -04:00
// Load Available Feature Flags
2022-07-13 23:35:05 -04:00
extern unsigned char available_feature_flags[];
2022-07-29 22:13:03 -04:00
extern size_t available_feature_flags_len;
2024-05-12 03:19:01 -04:00
void load_available_feature_flags(const std::function<void(std::string)> &callback) {
2021-06-17 17:32:24 -04:00
// Get Path
char *binary_directory = get_binary_directory();
std::string path = std::string(binary_directory) + "/available-feature-flags";
free(binary_directory);
// Load File
2022-07-13 23:35:05 -04:00
std::string data(available_feature_flags, available_feature_flags + available_feature_flags_len);
std::stringstream stream(data);
// Store Lines
std::vector<std::string> lines;
// Read File
{
std::string line;
while (std::getline(stream, line)) {
2024-05-12 03:19:01 -04:00
if (!line.empty()) {
2022-07-13 23:35:05 -04:00
// Verify Line
if (line.find('|') == std::string::npos) {
lines.push_back(line);
} else {
// Invalid Line
ERR("Feature Flag Contains Invalid '|'");
2021-06-17 17:32:24 -04:00
}
}
}
2022-07-13 23:35:05 -04:00
}
// Sort
2024-05-12 03:19:01 -04:00
std::sort(lines.begin(), lines.end(), [](const std::string &a, const std::string &b) {
2022-07-13 23:35:05 -04:00
// Strip Defaults
2024-05-12 03:19:01 -04:00
std::string stripped_a = strip_feature_flag_default(a, nullptr);
std::string stripped_b = strip_feature_flag_default(b, nullptr);
2022-03-16 19:51:45 -04:00
// Sort
2022-07-13 23:35:05 -04:00
return stripped_a < stripped_b;
});
// Run Callbacks
2024-05-12 03:19:01 -04:00
for (const std::string &line : lines) {
2022-07-13 23:35:05 -04:00
callback(line);
2021-06-17 17:32:24 -04:00
}
}
// Run Command And Set Environmental Variable
2022-03-14 19:09:25 -04:00
static void run_command_and_set_env(const char *env_name, const char *command[]) {
2021-06-17 17:32:24 -04:00
// Only Run If Environmental Variable Is NULL
2024-05-12 03:19:01 -04:00
if (getenv(env_name) == nullptr) {
2021-06-17 17:32:24 -04:00
// Run
int return_code;
2024-05-12 03:19:01 -04:00
char *output = run_command(command, &return_code, nullptr);
if (output != nullptr) {
2021-06-17 17:32:24 -04:00
// Trim
int length = strlen(output);
if (output[length - 1] == '\n') {
output[length - 1] = '\0';
}
// Set
2022-03-09 22:08:47 -05:00
set_and_print_env(env_name, output);
2022-03-14 19:09:25 -04:00
// Free
free(output);
2021-06-17 17:32:24 -04:00
}
// Check Return Code
2022-05-15 13:51:28 -04:00
if (!is_exit_status_success(return_code)) {
// Launch Interrupted
2022-05-13 22:36:12 -04:00
exit(EXIT_SUCCESS);
2021-06-17 17:32:24 -04:00
}
}
}
// Use Zenity To Set Environmental Variable
2022-06-09 21:31:40 -04:00
#define DIALOG_TITLE "Launcher"
2021-06-17 17:32:24 -04:00
static void run_zenity_and_set_env(const char *env_name, std::vector<std::string> command) {
// Create Full Command
std::vector<std::string> full_command;
full_command.push_back("zenity");
2022-06-09 21:31:40 -04:00
full_command.push_back("--title");
full_command.push_back(DIALOG_TITLE);
2022-05-13 23:27:06 -04:00
full_command.push_back("--name");
2022-07-29 22:13:03 -04:00
full_command.push_back(MCPI_APP_ID);
2021-06-17 17:32:24 -04:00
full_command.insert(full_command.end(), command.begin(), command.end());
// Convert To C Array
const char *full_command_array[full_command.size() + 1];
for (std::vector<std::string>::size_type i = 0; i < full_command.size(); i++) {
full_command_array[i] = full_command[i].c_str();
}
2024-05-12 03:19:01 -04:00
full_command_array[full_command.size()] = nullptr;
2021-06-17 17:32:24 -04:00
// Run
2022-03-14 19:09:25 -04:00
run_command_and_set_env(env_name, full_command_array);
2021-06-17 17:32:24 -04:00
}
2022-07-08 13:57:48 -04:00
// Set Variable If Not Already Set
2024-05-12 03:19:01 -04:00
static void set_env_if_unset(const char *env_name, const std::function<std::string()> &callback) {
if (getenv(env_name) == nullptr) {
2022-07-08 13:57:48 -04:00
char *value = strdup(callback().c_str());
ALLOC_CHECK(value);
set_and_print_env(env_name, value);
free(value);
}
}
2024-05-12 03:19:01 -04:00
// Handle Non-Launch Commands
void handle_non_launch_client_only_commands(const options_t &options) {
// Print Available Feature Flags
if (options.print_available_feature_flags) {
load_available_feature_flags([](const std::string &line) {
printf("%s\n", line.c_str());
fflush(stdout);
});
exit(EXIT_SUCCESS);
2022-06-24 20:37:52 -04:00
}
2024-05-12 03:19:01 -04:00
}
2022-06-24 20:37:52 -04:00
2024-05-12 03:19:01 -04:00
// Check Environment
void check_environment_client() {
// Don't Run As Root
if (getenv("_MCPI_SKIP_ROOT_CHECK") == nullptr && (getuid() == 0 || geteuid() == 0)) {
ERR("Don't Run As Root");
2022-09-22 17:43:21 -04:00
}
2023-12-02 14:23:28 -05:00
// Check For Display
#ifndef MCPI_HEADLESS_MODE
2024-05-12 03:19:01 -04:00
if (getenv("DISPLAY") == nullptr && getenv("WAYLAND_DISPLAY") == nullptr) {
2023-12-02 14:23:28 -05:00
ERR("No display attached! Make sure $DISPLAY or $WAYLAND_DISPLAY is set.");
}
#endif
2024-05-12 03:19:01 -04:00
}
2023-12-02 14:23:28 -05:00
2024-05-12 03:19:01 -04:00
// Configure Client Options
#define LIST_DIALOG_SIZE "400"
void configure_client(const options_t &options) {
// Wipe Cache If Needed
if (options.wipe_cache) {
wipe_cache();
2022-09-23 00:31:42 -04:00
}
// Load Cache
2024-05-12 03:19:01 -04:00
launcher_cache cache = options.no_cache ? empty_cache : load_cache();
2022-09-23 00:31:42 -04:00
2022-07-08 13:57:48 -04:00
// --default
2024-05-12 03:19:01 -04:00
if (options.use_default) {
// Use Default Feature Flags
set_env_if_unset("MCPI_FEATURE_FLAGS", [&cache]() {
std::string feature_flags = "";
load_available_feature_flags([&feature_flags, &cache](const std::string &flag) {
bool value;
// Strip Default Value
std::string stripped_flag = strip_feature_flag_default(flag, &value);
// Use Cache
if (cache.feature_flags.count(stripped_flag) > 0) {
value = cache.feature_flags[stripped_flag];
}
// Specify Default Value
if (value) {
// Enabled By Default
feature_flags += stripped_flag + '|';
2022-07-08 13:57:48 -04:00
}
});
2024-05-12 03:19:01 -04:00
if (!feature_flags.empty() && feature_flags[feature_flags.length() - 1] == '|') {
feature_flags.pop_back();
}
return feature_flags;
});
set_env_if_unset("MCPI_RENDER_DISTANCE", [&cache]() {
return cache.render_distance;
});
set_env_if_unset("MCPI_USERNAME", [&cache]() {
return cache.username;
});
2022-07-08 13:57:48 -04:00
}
2021-06-17 17:32:24 -04:00
// Setup MCPI_FEATURE_FLAGS
{
std::vector<std::string> command;
command.push_back("--list");
command.push_back("--checklist");
command.push_back("--width");
2022-04-27 23:38:30 -04:00
command.push_back(LIST_DIALOG_SIZE);
2021-06-17 17:32:24 -04:00
command.push_back("--height");
2022-04-27 23:38:30 -04:00
command.push_back(LIST_DIALOG_SIZE);
2021-06-17 17:32:24 -04:00
command.push_back("--column");
command.push_back("Enabled");
command.push_back("--column");
command.push_back("Feature");
2024-05-12 03:19:01 -04:00
load_available_feature_flags([&command, &cache](const std::string &flag) {
2022-09-22 17:43:21 -04:00
bool value;
2022-03-16 19:51:45 -04:00
// Strip Default Value
2022-09-22 17:43:21 -04:00
std::string stripped_flag = strip_feature_flag_default(flag, &value);
// Use Cache
if (cache.feature_flags.count(stripped_flag) > 0) {
value = cache.feature_flags[stripped_flag];
}
2022-03-16 19:51:45 -04:00
// Specify Default Value
2022-09-22 17:43:21 -04:00
if (value) {
2021-06-17 17:32:24 -04:00
// Enabled By Default
command.push_back("TRUE");
2022-03-16 19:51:45 -04:00
} else {
2021-06-17 17:32:24 -04:00
// Disabled By Default
command.push_back("FALSE");
}
2022-03-16 19:51:45 -04:00
// Specify Name
command.push_back(stripped_flag);
2021-06-17 17:32:24 -04:00
});
// Run
run_zenity_and_set_env("MCPI_FEATURE_FLAGS", command);
}
// Setup MCPI_RENDER_DISTANCE
{
std::vector<std::string> command;
command.push_back("--list");
command.push_back("--radiolist");
command.push_back("--width");
2022-04-27 23:38:30 -04:00
command.push_back(LIST_DIALOG_SIZE);
2021-06-17 17:32:24 -04:00
command.push_back("--height");
2022-04-27 23:38:30 -04:00
command.push_back(LIST_DIALOG_SIZE);
2021-06-17 17:32:24 -04:00
command.push_back("--text");
2022-04-27 23:38:30 -04:00
command.push_back("Select Minecraft Render Distance:");
2021-06-17 17:32:24 -04:00
command.push_back("--column");
command.push_back("Selected");
command.push_back("--column");
command.push_back("Name");
2022-07-08 13:57:48 -04:00
std::string render_distances[] = {"Far", "Normal", "Short", "Tiny"};
for (std::string &render_distance : render_distances) {
2024-05-12 03:19:01 -04:00
command.push_back(render_distance == cache.render_distance ? "TRUE" : "FALSE");
2022-07-08 13:57:48 -04:00
command.push_back(render_distance);
}
2021-06-17 17:32:24 -04:00
// Run
run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command);
}
2022-04-12 20:38:44 -04:00
// Setup MCPI_USERNAME
{
std::vector<std::string> command;
command.push_back("--entry");
command.push_back("--text");
2022-04-27 23:38:30 -04:00
command.push_back("Enter Minecraft Username:");
2022-04-12 20:38:44 -04:00
command.push_back("--entry-text");
2022-09-22 17:43:21 -04:00
command.push_back(cache.username);
2022-04-12 20:38:44 -04:00
// Run
run_zenity_and_set_env("MCPI_USERNAME", command);
}
2021-06-17 17:32:24 -04:00
2022-09-22 17:43:21 -04:00
// Save Cache
2024-05-12 03:19:01 -04:00
if (!options.no_cache) {
2022-09-22 17:43:21 -04:00
save_cache();
}
2021-06-17 17:32:24 -04:00
}