WIP UI Scale Slider

This commit is contained in:
TheBrokenRail 2024-11-28 02:42:22 -05:00
parent c531e7ba7d
commit cfac7d0a12
12 changed files with 167 additions and 84 deletions

View File

@ -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<std::string, bool> 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<std::string, bool> 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<std::string, bool> flags_cache = state.flags.to_cache();
for (const std::pair<const std::string, bool> &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<std::string, bool> flags_cache = state.flags.to_cache();
for (const std::pair<const std::string, bool> &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();

View File

@ -1,13 +1,16 @@
#pragma once
#include <ostream>
// 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

View File

@ -1,6 +1,7 @@
#include <sstream>
#include <libreborn/env.h>
#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 <typename T>
static void update_from_env(const char *env, T &value, const bool save) {
if (save) {
const std::string str = static_cast<std::string>(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<std::string>(x) == static_cast<std::string>(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

View File

@ -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;
};

View File

@ -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());
}

View File

@ -1,5 +1,7 @@
#pragma once
#include <string>
#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);
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);

View File

@ -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<std::string, bool> to_cache() const;
void from_cache(const std::unordered_map<std::string, bool> &cache);

View File

@ -1,6 +1,7 @@
#include <libreborn/env.h>
#include <libreborn/exec.h>
#include <libreborn/log.h>
#include <libreborn/flags.h>
// 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);
}

View File

@ -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<std::string> 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<std::string, bool> Flags::to_cache() const {
std::unordered_map<std::string, bool> out;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}