From cfac7d0a1208d8e5970f6fb1d35f6e43afb5c017 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 28 Nov 2024 02:42:22 -0500 Subject: [PATCH] WIP UI Scale Slider --- launcher/src/client/cache.cpp | 126 +++++++++++++++----------- launcher/src/client/cache.h | 5 +- launcher/src/client/configuration.cpp | 18 ++-- launcher/src/client/configuration.h | 2 + launcher/src/client/ui.cpp | 27 ++++-- libreborn/include/libreborn/env.h | 13 ++- libreborn/include/libreborn/flags.h | 5 +- libreborn/src/util/env.cpp | 21 +++++ libreborn/src/util/flags/flags.cpp | 8 +- mods/src/feature/feature.cpp | 2 +- mods/src/misc/ui.cpp | 22 +++-- mods/src/title-screen/splashes.cpp | 2 +- 12 files changed, 167 insertions(+), 84 deletions(-) diff --git a/launcher/src/client/cache.cpp b/launcher/src/client/cache.cpp index b6a5c4f4f4..4b8560463a 100644 --- a/launcher/src/client/cache.cpp +++ b/launcher/src/client/cache.cpp @@ -17,6 +17,57 @@ static std::string get_cache_path() { } // Load +static void read_cache(std::ifstream &stream, State &ret) { + // Cache Version + unsigned char cache_version; + stream.read((char *) &cache_version, 1); + if (stream.eof()) { + // Unable To Read Version + WARN("Unable To Read Launcher Cache Version"); + return; + } + + // Support Older Versions + bool load_gui_scale = true; + if (cache_version == 0) { + // Pre-v3.0.0 Cache + load_gui_scale = false; + } else if (cache_version != (unsigned char) CACHE_VERSION) { + // Invalid Version + WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", CACHE_VERSION, (int) cache_version); + return; + } + + // Load Username And Render Distance + State state; + std::getline(stream, state.username, '\0'); + std::getline(stream, state.render_distance, '\0'); + if (load_gui_scale) { + stream.read((char *) &state.gui_scale, sizeof(float)); + } + + // Load Feature Flags + std::unordered_map flags; + std::string flag; + while (!stream.eof() && std::getline(stream, flag, '\0')) { + if (!flag.empty()) { + bool is_enabled = false; + stream.read((char *) &is_enabled, sizeof(bool)); + flags[flag] = is_enabled; + } + stream.peek(); + } + state.flags.from_cache(flags); + + // Check For Error + if (!stream) { + WARN("Failure While Loading Launcher Cache"); + return; + } + + // Success + ret = state; +} State load_cache() { // Log DEBUG("Loading Launcher Cache..."); @@ -35,42 +86,8 @@ State load_cache() { // Lock File int lock_fd = lock_file(get_cache_path().c_str()); - // Check Version - unsigned char cache_version; - stream.read((char *) &cache_version, 1); - if (stream.eof()) { - // Unable To Read Version - WARN("Unable To Read Launcher Cache Version"); - } else if (cache_version != (unsigned char) CACHE_VERSION) { - // Invalid Version - WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", CACHE_VERSION, (int) cache_version); - } else { - // Load Username And Render Distance - State state; - std::getline(stream, state.username, '\0'); - std::getline(stream, state.render_distance, '\0'); - - // Load Feature Flags - std::unordered_map flags; - std::string flag; - while (!stream.eof() && std::getline(stream, flag, '\0')) { - if (!flag.empty()) { - bool is_enabled = false; - stream.read((char *) &is_enabled, sizeof(bool)); - flags[flag] = is_enabled; - } - stream.peek(); - } - state.flags.from_cache(flags); - - // Check For Error - if (!stream) { - WARN("Failure While Loading Launcher Cache"); - } else { - // Success - ret = state; - } - } + // Load + read_cache(stream, ret); // Close stream.close(); @@ -84,9 +101,26 @@ State load_cache() { } // Save -static void write_env_to_stream(std::ofstream &stream, const std::string &value) { +static void write_env_to_stream(std::ostream &stream, const std::string &value) { stream.write(value.c_str(), int(value.size()) + 1); } +void write_cache(std::ostream &stream, const State &state) { + // Save Cache Version + constexpr unsigned char cache_version = CACHE_VERSION; + stream.write((const char *) &cache_version, 1); + + // Save Username And Render Distance + write_env_to_stream(stream, state.username); + write_env_to_stream(stream, state.render_distance); + stream.write((const char *) &state.gui_scale, sizeof(float)); + + // Save Feature Flags + const std::unordered_map flags_cache = state.flags.to_cache(); + for (const std::pair &it : flags_cache) { + stream.write(it.first.c_str(), int(it.first.size()) + 1); + stream.write((const char *) &it.second, sizeof(bool)); + } +} void save_cache(const State &state) { // Log DEBUG("Saving Launcher Cache..."); @@ -98,22 +132,10 @@ void save_cache(const State &state) { WARN("Unable To Open Launcher Cache For Saving"); } else { // Lock File - int lock_fd = lock_file(get_cache_path().c_str()); + const int lock_fd = lock_file(get_cache_path().c_str()); - // Save Cache Version - constexpr unsigned char cache_version = CACHE_VERSION; - stream.write((const char *) &cache_version, 1); - - // Save Username And Render Distance - write_env_to_stream(stream, state.username); - write_env_to_stream(stream, state.render_distance); - - // Save Feature Flags - const std::unordered_map flags_cache = state.flags.to_cache(); - for (const std::pair &it : flags_cache) { - stream.write(it.first.c_str(), int(it.first.size()) + 1); - stream.write((const char *) &it.second, sizeof(bool)); - } + // Write + write_cache(stream, state); // Finish stream.close(); diff --git a/launcher/src/client/cache.h b/launcher/src/client/cache.h index f989510088..538e70bad3 100644 --- a/launcher/src/client/cache.h +++ b/launcher/src/client/cache.h @@ -1,13 +1,16 @@ #pragma once +#include + // Cache Version -#define CACHE_VERSION 0 +#define CACHE_VERSION 1 // Load Cache struct State; State load_cache(); // Save Cache +void write_cache(std::ostream &stream, const State &state); void save_cache(const State &state); // Wipe Cache diff --git a/launcher/src/client/configuration.cpp b/launcher/src/client/configuration.cpp index 9c928a5b54..169a9fad69 100644 --- a/launcher/src/client/configuration.cpp +++ b/launcher/src/client/configuration.cpp @@ -1,6 +1,7 @@ +#include + #include -#include "../util/util.h" #include "configuration.h" #include "cache.h" @@ -8,17 +9,17 @@ State::State(): flags("") { username = DEFAULT_USERNAME; render_distance = DEFAULT_RENDER_DISTANCE; + gui_scale = AUTO_GUI_SCALE; flags = Flags::get(); } template static void update_from_env(const char *env, T &value, const bool save) { if (save) { - const std::string str = static_cast(value); - set_and_print_env(env, str.c_str()); + set_and_print_env(env, obj_to_env_value(value).c_str()); } else { const char *env_value = getenv(env); if (env_value != nullptr) { - value = env_value; + env_value_to_obj(value, env_value); } } } @@ -26,11 +27,14 @@ void State::update(const bool save) { update_from_env(MCPI_FEATURE_FLAGS_ENV, flags, save); update_from_env(MCPI_USERNAME_ENV, username, save); update_from_env(MCPI_RENDER_DISTANCE_ENV, render_distance, save); + update_from_env(MCPI_GUI_SCALE_ENV, gui_scale, save); } bool State::operator==(const State &other) const { -#define test(x) static_cast(x) == static_cast(other.x) - return test(username) && test(render_distance) && test(flags); -#undef test + std::ostringstream one; + write_cache(one, *this); + std::ostringstream two; + write_cache(two, other); + return one.str() == two.str(); } // Handle Non-Launch Commands diff --git a/launcher/src/client/configuration.h b/launcher/src/client/configuration.h index 3240198a38..7fb46666d6 100644 --- a/launcher/src/client/configuration.h +++ b/launcher/src/client/configuration.h @@ -11,6 +11,7 @@ // Default Configuration #define DEFAULT_USERNAME "StevePi" #define DEFAULT_RENDER_DISTANCE "Short" +#define AUTO_GUI_SCALE 0 // State struct State { @@ -21,6 +22,7 @@ struct State { // Properties std::string username; std::string render_distance; + float gui_scale; Flags flags; }; diff --git a/launcher/src/client/ui.cpp b/launcher/src/client/ui.cpp index e1a0f20a2c..24484e9b5e 100644 --- a/launcher/src/client/ui.cpp +++ b/launcher/src/client/ui.cpp @@ -16,9 +16,9 @@ static constexpr std::array render_distances = { }; // Tooltips/Text -static constexpr std::string revert_text = "Revert"; -static constexpr std::string revert_tooltip_text = "Last Saved"; -static constexpr std::string make_tooltip(const std::string &text, const std::string &type) { +static const char *revert_text = "Revert"; +static const char *revert_tooltip_text = "Last Saved"; +static std::string make_tooltip(const std::string &text, const std::string &type) { return "Use " + text + ' ' + type; } @@ -123,20 +123,35 @@ int ConfigurationUI::get_render_distance_index() const { } void ConfigurationUI::draw_main() const { const ImGuiStyle &style = ImGui::GetStyle(); - const char *labels[] = {"Username", "Render Distance"}; + const char *labels[] = {"Username", "Render Distance", "UI Scale"}; // Calculate Label Size float label_size = 0; for (const char *label : labels) { label_size = std::max(label_size, ImGui::CalcTextSize(label).x + style.ItemInnerSpacing.x); } ImGui::PushItemWidth(-label_size); - // Options + // Username ImGui::InputText(labels[0], &state.username); + // Render Distance int render_distance_index = get_render_distance_index(); if (ImGui::Combo(labels[1], &render_distance_index, render_distances.data(), int(render_distances.size()))) { state.render_distance = render_distances[render_distance_index]; } + // UI Scale + std::string scale_format = "%i"; + scale_format += 'x'; + if (state.gui_scale <= AUTO_GUI_SCALE) { + scale_format = "Auto"; + } + int gui_scale_int = int(state.gui_scale); + if (ImGui::SliderInt(labels[2], &gui_scale_int, 0, 8, scale_format.c_str())) { + state.gui_scale = float(gui_scale_int); + if (state.gui_scale < AUTO_GUI_SCALE) { + state.gui_scale = AUTO_GUI_SCALE; + } + } ImGui::PopItemWidth(); + // Launcher Cache ImGui::Checkbox("Save Settings On Launch", &save_settings); } @@ -193,7 +208,7 @@ void ConfigurationUI::draw_servers() { // Revert/Save int clicked_button = -1; ImGui::BeginDisabled(!are_servers_unsaved()); - draw_right_aligned_buttons({revert_text.c_str(), "Save"}, [&clicked_button](const int id, const bool was_clicked) { + draw_right_aligned_buttons({revert_text, "Save"}, [&clicked_button](const int id, const bool was_clicked) { if (id == 0) { ImGui::SetItemTooltip("%s", make_tooltip(revert_tooltip_text, "Server List").c_str()); } diff --git a/libreborn/include/libreborn/env.h b/libreborn/include/libreborn/env.h index d74aed37ce..f575bcefa5 100644 --- a/libreborn/include/libreborn/env.h +++ b/libreborn/include/libreborn/env.h @@ -1,5 +1,7 @@ #pragma once +#include + #define ENV(name, ...) extern const char *const name##_ENV; #include "env-list.h" #undef ENV @@ -8,4 +10,13 @@ bool is_env_var_internal(const char *env); void clear_internal_env_vars(); // Set Environmental Variable -void set_and_print_env(const char *name, const char *value); \ No newline at end of file +void set_and_print_env(const char *name, const char *value); + +// Convert Variable To Value And Vice-Versa +struct Flags; +std::string obj_to_env_value(const std::string &obj); +std::string obj_to_env_value(const float &obj); +std::string obj_to_env_value(const Flags &obj); +void env_value_to_obj(std::string &out, const char *value); +void env_value_to_obj(float &out, const char *value); +void env_value_to_obj(Flags &out, const char *value); \ No newline at end of file diff --git a/libreborn/include/libreborn/flags.h b/libreborn/include/libreborn/flags.h index 974811fa82..7dc43738b5 100644 --- a/libreborn/include/libreborn/flags.h +++ b/libreborn/include/libreborn/flags.h @@ -36,8 +36,9 @@ struct Flags { explicit Flags(const std::string &data); static Flags get(); // To/From Strings - explicit operator std::string() const; - Flags &operator=(const std::string &str); + std::string to_string() const; + void from_string(const std::string &str); + bool operator==(const Flags &other) const; // To/From Cache [[nodiscard]] std::unordered_map to_cache() const; void from_cache(const std::unordered_map &cache); diff --git a/libreborn/src/util/env.cpp b/libreborn/src/util/env.cpp index 5744ade959..3f30afb222 100644 --- a/libreborn/src/util/env.cpp +++ b/libreborn/src/util/env.cpp @@ -1,6 +1,7 @@ #include #include #include +#include // Define Constants #define ENV(name, ...) const char *const name##_ENV = #name; @@ -35,4 +36,24 @@ void set_and_print_env(const char *name, const char *value) { // Print New Value DEBUG("Set %s = %s", name, value != NULL ? value : "(unset)"); +} + +// Conversion +std::string obj_to_env_value(const std::string &obj) { + return obj; +} +std::string obj_to_env_value(const float &obj) { + return std::to_string(obj); +} +std::string obj_to_env_value(const Flags &obj) { + return obj.to_string(); +} +void env_value_to_obj(std::string &out, const char *value) { + out = value; +} +void env_value_to_obj(float &out, const char *value) { + out = strtof(value, nullptr); +} +void env_value_to_obj(Flags &out, const char *value) { + out.from_string(value); } \ No newline at end of file diff --git a/libreborn/src/util/flags/flags.cpp b/libreborn/src/util/flags/flags.cpp index 99971883d8..3e7a62b3b0 100644 --- a/libreborn/src/util/flags/flags.cpp +++ b/libreborn/src/util/flags/flags.cpp @@ -62,7 +62,7 @@ Flags::Flags(const std::string &data) { } }); } -Flags::operator std::string() const { +std::string Flags::to_string() const { std::string out; root.for_each_const([&out](const FlagNode &flag) { if (flag.value) { @@ -74,7 +74,7 @@ Flags::operator std::string() const { }); return out; } -Flags &Flags::operator=(const std::string &str) { +void Flags::from_string(const std::string &str) { // Find Flags To Enable std::unordered_set to_enable; std::stringstream stream(str); @@ -88,7 +88,9 @@ Flags &Flags::operator=(const std::string &str) { root.for_each([&to_enable](FlagNode &flag) { flag.value = to_enable.contains(flag.name); }); - return *this; +} +bool Flags::operator==(const Flags &other) const { + return to_string() == other.to_string(); } std::unordered_map Flags::to_cache() const { std::unordered_map out; diff --git a/mods/src/feature/feature.cpp b/mods/src/feature/feature.cpp index 05cefd93e2..c5875ddf88 100644 --- a/mods/src/feature/feature.cpp +++ b/mods/src/feature/feature.cpp @@ -20,7 +20,7 @@ bool _feature_has(const char *name, const int server_default) { if (!loaded) { const char *env = getenv(MCPI_FEATURE_FLAGS_ENV); if (env) { - flags = env; + flags.from_string(env); } loaded = true; } diff --git a/mods/src/misc/ui.cpp b/mods/src/misc/ui.cpp index da91848fff..cd8f8fa909 100644 --- a/mods/src/misc/ui.cpp +++ b/mods/src/misc/ui.cpp @@ -15,9 +15,8 @@ // Heart Food Overlay static int heal_amount = 0, heal_amount_drawing = 0; static void Gui_renderHearts_injection(Gui_renderHearts_t original, Gui *gui) { - // Get heal_amount + // Calculate heal_amount heal_amount = heal_amount_drawing = 0; - Inventory *inventory = gui->minecraft->player->inventory; const ItemInstance *held_ii = inventory->getSelected(); if (held_ii) { @@ -30,7 +29,7 @@ static void Gui_renderHearts_injection(Gui_renderHearts_t original, Gui *gui) { } } - // Call original + // Call Original Method original(gui); } #define PINK_HEART_FULL 70 @@ -306,13 +305,16 @@ void _init_misc_ui() { // Custom GUI Scale const char *gui_scale_str = getenv(MCPI_GUI_SCALE_ENV); if (gui_scale_str != nullptr) { - unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" - patch((void *) 0x173e8, nop_patch); - patch((void *) 0x173f0, nop_patch); - const float gui_scale = strtof(gui_scale_str, nullptr); - uint32_t gui_scale_raw; - memcpy(&gui_scale_raw, &gui_scale, sizeof (gui_scale_raw)); - patch_address((void *) 0x17520, (void *) gui_scale_raw); + float gui_scale; + env_value_to_obj(gui_scale, gui_scale_str); + if (gui_scale > 0) { + unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x173e8, nop_patch); + patch((void *) 0x173f0, nop_patch); + uint32_t gui_scale_raw; + memcpy(&gui_scale_raw, &gui_scale, sizeof (gui_scale_raw)); + patch_address((void *) 0x17520, (void *) gui_scale_raw); + } } // Don't Wrap Text On '\r' Or '\t' Because They Are Actual Characters In MCPI diff --git a/mods/src/title-screen/splashes.cpp b/mods/src/title-screen/splashes.cpp index 02795d6181..ed5efec464 100644 --- a/mods/src/title-screen/splashes.cpp +++ b/mods/src/title-screen/splashes.cpp @@ -103,7 +103,7 @@ static bool draw_splash(StartMenuScreen *screen, const float y_factor, const boo const int text_width = screen->font->width(current_splash); float splash_width = float(text_width) * scale; if (splash_width > float(max_width)) { - const float multiplier = (float(max_width) / splash_width); + const float multiplier = float(max_width) / splash_width; scale *= multiplier; splash_width *= multiplier; }