diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 096e91433e..3d74886366 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -71,6 +71,9 @@ * `Fix Camera Functionality` * `Property Scale Animated Textures` * `Enable Text Input` + * `Update Default Options` + * `Fix options.txt Loading/Saving` + * `Fix Reloading Textures On Resize` * Split Up `Remove Creative Mode Restrictions` Feature Flag * `Remove Creative Mode Restrictions` (Disabled By Default) * `Display Slot Count In Creative Mode` (Disabled By Default) diff --git a/launcher/src/client/ui.cpp b/launcher/src/client/ui.cpp index 58a54e972f..e947180e26 100644 --- a/launcher/src/client/ui.cpp +++ b/launcher/src/client/ui.cpp @@ -116,6 +116,7 @@ static std::string get_label(const FlagNode &node) { } void ConfigurationUI::draw_advanced() const { if (ImGui::BeginChild("Features", ImVec2(0, 0), ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar)) { + // Categories for (FlagNode &category : state.flags.root.children) { std::string label = get_label(category); if (ImGui::CollapsingHeader(label.c_str())) { diff --git a/libreborn/include/libreborn/patch.h b/libreborn/include/libreborn/patch.h index 7729d786fc..9a106c7b7b 100644 --- a/libreborn/include/libreborn/patch.h +++ b/libreborn/include/libreborn/patch.h @@ -29,7 +29,7 @@ void *reborn_thunk_enabler(void *target, void *thunk); // Replace All Calls To start With target Within [to, from) void overwrite_calls_within_manual(void *from, void *to, void *start, void *target); template -void _overwrite_calls_within(void *from, void *to, T *start, typename T::ptr_type target) { +void overwrite_calls_within(void *from, void *to, T *start, typename T::ptr_type target) { overwrite_calls_within_manual(from, to, (void *) start->get(), (void *) target); } @@ -51,4 +51,4 @@ void patch_vtable(const T *start, typename T::ptr_type target) { WARN("Use overwrite_calls() Instead!"); } patch_address((void *) start->get_vtable_addr(), (void *) target); -} +} \ No newline at end of file diff --git a/libreborn/src/util/flags/available-feature-flags b/libreborn/src/util/flags/available-feature-flags index 3b41d80b11..d6de6bd5ee 100644 --- a/libreborn/src/util/flags/available-feature-flags +++ b/libreborn/src/util/flags/available-feature-flags @@ -124,6 +124,8 @@ CATEGORY Bug Fixes TRUE Fix Switching Perspective While Sneaking TRUE Fix Crash When Generating Certain Seeds TRUE Fix Sugar Position In Hand + TRUE Fix Reloading Textures On Resize + TRUE Fix options.txt Loading/Saving CATEGORY Logging FALSE Log FPS TRUE Log Chat Messages @@ -133,4 +135,5 @@ CATEGORY Miscellaneous TRUE Fullscreen Support TRUE Always Save Chest Tile Entities TRUE Screenshot Support - TRUE Fix Camera Functionality \ No newline at end of file + TRUE Fix Camera Functionality + TRUE Update Default Options \ No newline at end of file diff --git a/mods/include/mods/creative/creative.h b/mods/include/mods/creative/creative.h index e073d92387..b189fddd41 100644 --- a/mods/include/mods/creative/creative.h +++ b/mods/include/mods/creative/creative.h @@ -1,5 +1,5 @@ #pragma once extern "C" { -int creative_is_restricted(); +bool creative_is_restricted(); } \ No newline at end of file diff --git a/mods/src/creative/creative.cpp b/mods/src/creative/creative.cpp index e3fe41ec52..b57026569b 100644 --- a/mods/src/creative/creative.cpp +++ b/mods/src/creative/creative.cpp @@ -95,11 +95,16 @@ static TileItem *Tile_initTiles_TileItem_injection(TileItem *tile_item, int32_t } // Check Restriction Status -static int is_restricted = 1; -int creative_is_restricted() { +static bool is_restricted = true; +bool creative_is_restricted() { return is_restricted; } +// Allow Creative Players To Drop Items +static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(__attribute__((unused)) Minecraft *minecraft) { + return false; +} + // Init void init_creative() { // Add Extra Items To Creative Inventory (Only Replace Specific Function Call) @@ -128,8 +133,16 @@ void init_creative() { patch((void *) 0x99010, nop_patch); // Allow Nether Reactor patch((void *) 0xc0290, nop_patch); + // Item Dropping + void *addr = (void *) 0x27800; + const void *func = extract_from_bl_instruction((unsigned char *) addr); + if (func == Minecraft_isCreativeMode->backup) { + overwrite_call(addr, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection); + } else { + // Handled By input/misc.cpp + } // Disable Other Restrictions - is_restricted = 0; + is_restricted = false; } // Inventory Behavior diff --git a/mods/src/input/misc.cpp b/mods/src/input/misc.cpp index bdcbbe7e5a..b6638e8f1a 100644 --- a/mods/src/input/misc.cpp +++ b/mods/src/input/misc.cpp @@ -9,9 +9,6 @@ #include #include -// Enable Miscellaneous Input Fixes -static int enable_misc = 0; - // Handle Back Button Presses static void _handle_back(Minecraft *minecraft) { // If Minecraft's Level property is initialized, but Minecraft's Player property is nullptr, then Minecraft::handleBack may crash. @@ -50,7 +47,7 @@ static bool InBedScreen_handleBackEvent_injection(InBedScreen *screen, const boo // Block UI Interaction When Mouse Is Locked static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(Minecraft *minecraft) { const bool is_in_game = minecraft->screen == nullptr || minecraft->screen->vtable == (Screen_vtable *) Touch_IngameBlockSelectionScreen_vtable::base; - if (!enable_misc || (media_SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF && is_in_game)) { + if (media_SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF && is_in_game) { // Call Original Method return creative_is_restricted() && minecraft->isCreativeMode(); } else { @@ -69,8 +66,7 @@ static void Gui_handleClick_injection(Gui_handleClick_t original, Gui *gui, cons // Init void _init_misc() { - enable_misc = feature_has("Miscellaneous Input Fixes", server_disabled); - if (enable_misc) { + if (feature_has("Miscellaneous Input Fixes", server_disabled)) { // Fix OptionsScreen Ignoring The Back Button patch_vtable(OptionsScreen_handleBackEvent, OptionsScreen_handleBackEvent_injection); // Fix "Sleeping Beauty" Bug @@ -86,7 +82,7 @@ void _init_misc() { return false; } }); + // Disable Item Dropping Using The Cursor When Cursor Is Hidden + overwrite_call((void *) 0x27800, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection); } - // Disable Item Dropping Using The Cursor When Cursor Is Hidden - overwrite_call((void *) 0x27800, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection); } diff --git a/mods/src/misc/graphics.cpp b/mods/src/misc/graphics.cpp index a0b4b35b7f..ffa78a921e 100644 --- a/mods/src/misc/graphics.cpp +++ b/mods/src/misc/graphics.cpp @@ -546,12 +546,19 @@ void _init_misc_graphics() { } // Modify Entity Rendering - overwrite_call((void *) 0x606c0, (void *) EntityRenderDispatcher_render_EntityRenderer_render_injection); + bool hijack_entity_rendering = false; should_render_fire = feature_has("Render Fire In Third-Person", server_disabled); + if (should_render_fire) { + hijack_entity_rendering = true; + } should_render_shadows = feature_has("Render Entity Shadows", server_disabled); if (should_render_shadows) { overwrite_calls(EntityRenderDispatcher_assign, EntityRenderDispatcher_assign_injection); overwrite_calls(ArmorScreen_renderPlayer, ArmorScreen_renderPlayer_injection); + hijack_entity_rendering = true; + } + if (hijack_entity_rendering) { + overwrite_call((void *) 0x606c0, (void *) EntityRenderDispatcher_render_EntityRenderer_render_injection); } // Slightly Nicer Water Rendering diff --git a/mods/src/options/options.cpp b/mods/src/options/options.cpp index a224f733b6..683a7c538c 100644 --- a/mods/src/options/options.cpp +++ b/mods/src/options/options.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -40,15 +41,6 @@ static int get_render_distance() { } } -// Get Custom Username -static const char *get_username() { - const char *username = getenv(MCPI_USERNAME_ENV); - if (username == nullptr) { - username = "StevePi"; - } - return username; -} - static int render_distance; // Configure Options Options *stored_options = nullptr; @@ -59,9 +51,6 @@ static void Options_initDefaultValue_injection(Options_initDefaultValue_t origin // Default Graphics Settings options->fancy_graphics = true; options->ambient_occlusion = true; - - // Store - stored_options = options; } static void Minecraft_init_injection(Minecraft_init_t original, Minecraft *minecraft) { // Call Original Method @@ -72,6 +61,9 @@ static void Minecraft_init_injection(Minecraft_init_t original, Minecraft *minec options->split_controls = true; // Render Distance options->render_distance = render_distance; + + // Store + stored_options = options; } // Smooth Lighting @@ -89,9 +81,10 @@ static void Options_save_Options_addOptionToSaveOutput_injection(Options *option // Call Original Method options->addOptionToSaveOutput(data, option, value); + // Save Smooth Lighting + options->addOptionToSaveOutput(data, "gfx_ao", options->ambient_occlusion); // Save Fancy Graphics options->addOptionToSaveOutput(data, "gfx_fancygraphics", options->fancy_graphics); - // Save 3D Anaglyph options->addOptionToSaveOutput(data, "gfx_anaglyph", options->anaglyph_3d); @@ -100,36 +93,67 @@ static void Options_save_Options_addOptionToSaveOutput_injection(Options *option options_file->save(data); } -// MCPI's OptionsFile::getOptionStrings is broken, this is the version in v0.7.0 -static std::vector OptionsFile_getOptionStrings_injection(__attribute__((unused)) OptionsFile_getOptionStrings_t original, OptionsFile *options_file) { +// MCPI's OptionsFile::getOptionStrings is broken, this is modified from the version in v0.7.0 +static std::vector OptionsFile_getOptionStrings_v2(OptionsFile *options_file) { // Get options.txt Path const std::string path = options_file->options_txt_path; // Parse std::vector ret; - FILE *stream = fopen(path.c_str(), "r"); - if (stream != nullptr) { - char line[128]; - while (fgets(line, 0x80, stream) != nullptr) { - const size_t sVar1 = strlen(line); - if (2 < sVar1) { + std::ifstream stream(path, std::ios::binary); + if (stream) { + std::string line; + while (std::getline(stream, line)) { + if (!line.empty()) { std::stringstream string_stream(line); - while (true) { - std::string data; - std::getline(string_stream, data, ':'); - const int iVar2 = data.find_last_not_of(" \n\r\t"); - data.erase(iVar2 + 1); - if (data.length() == 0) { - break; - } - ret.push_back(data); + std::string part; + while (std::getline(string_stream, part, ':')) { + ret.push_back(part); } } } - fclose(stream); + stream.close(); } return ret; } +// Replacement Of Options::update +static void Options_update_injection(__attribute__((unused)) Options_update_t original, Options *self) { + const std::vector strings = OptionsFile_getOptionStrings_v2(&self->options_file); + for (std::vector::size_type i = 0; i < strings.size(); i++) { + // Read + const std::string key = strings[i++]; + if (i == strings.size()) { + // Missing Value + break; + } + const std::string value = strings[i]; + if (key == "mp_server_visible_default") { + Options::readBool(value, self->server_visible); + } else if (key == "game_difficulty") { + int &difficulty = self->game_difficulty; + Options::readInt(value, difficulty); + constexpr int normal_difficulty = 2; + if (difficulty != 0 && difficulty != normal_difficulty) { + difficulty = normal_difficulty; + } + } else if (key == "ctrl_invertmouse") { + Options::readBool(value, self->invert_mouse); + } else if (key == "ctrl_islefthanded") { + Options::readBool(value, self->lefty); + } else if (key == "gfx_ao") { + Options::readBool(value, self->ambient_occlusion); + } else if (key == "gfx_fancygraphics") { + Options::readBool(value, self->fancy_graphics); + } else if (key == "gfx_anaglyph") { + Options::readBool(value, self->anaglyph_3d); + } else if (key == "ctrl_usetouchscreen" || key == "feedback_vibration") { + // Skip + } else { + WARN("Unknown Option: %s", key.c_str()); + } + } +} + // Get New options.txt Path static const char *get_new_options_txt_path() { static std::string path = ""; @@ -153,17 +177,21 @@ void init_options() { DEBUG("Setting Render Distance: %i", render_distance); // Set Options - overwrite_calls(Options_initDefaultValue, Options_initDefaultValue_injection); + if (feature_has("Update Default Options", server_disabled)) { + overwrite_calls(Options_initDefaultValue, Options_initDefaultValue_injection); + } overwrite_calls(Minecraft_init, Minecraft_init_injection); // Change Username - const char *username = get_username(); - DEBUG("Setting Username: %s", username); - if (strcmp(Strings::default_username, "StevePi") != 0) { - ERR("Default Username Is Invalid"); + const char *username = getenv(MCPI_USERNAME_ENV); + if (username != nullptr) { + DEBUG("Setting Username: %s", username); + if (strcmp(Strings::default_username, "StevePi") != 0) { + ERR("Default Username Is Invalid"); + } + static std::string safe_username = to_cp437(username); + patch_address((void *) &Strings::default_username, (void *) safe_username.c_str()); } - static std::string safe_username = to_cp437(username); - patch_address((void *) &Strings::default_username, (void *) safe_username.c_str()); // Disable Autojump By Default if (feature_has("Disable Autojump By Default", server_disabled)) { @@ -181,54 +209,21 @@ void init_options() { // Smooth Lighting overwrite_calls(TileRenderer_tesselateBlockInWorld, TileRenderer_tesselateBlockInWorld_injection); - // NOP - unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + // options.txt + if (feature_has("Fix options.txt Loading/Saving", server_disabled)) { + // Actually Save options.txt + overwrite_call((void *) 0x197fc, (void *) Options_save_Options_addOptionToSaveOutput_injection); + // Fix options.txt Path + patch_address((void *) &Strings::options_txt_path, (void *) get_new_options_txt_path()); + // When Loading, options.txt Should Be Opened In Read Mode + patch_address((void *) &Strings::options_txt_fopen_mode_when_loading, (void *) "r"); + // Fix Loading + overwrite_calls(Options_update, Options_update_injection); - // Actually Save options.txt - overwrite_call((void *) 0x197fc, (void *) Options_save_Options_addOptionToSaveOutput_injection); - // Fix options.txt Path - patch_address((void *) &Strings::options_txt_path, (void *) get_new_options_txt_path()); - // When Loading, options.txt Should Be Opened In Read Mode - patch_address((void *) &Strings::options_txt_fopen_mode_when_loading, (void *) "r"); - // Fix OptionsFile::getOptionStrings - overwrite_calls(OptionsFile_getOptionStrings, OptionsFile_getOptionStrings_injection); - - // Sensitivity Loading/Saving Is Broken, Disable It - patch((void *) 0x1931c, nop_patch); - patch((void *) 0x1973c, nop_patch); - - // Unsplit Touch Controls Breaks Things, Never Load/Save It - unsigned char cmp_r0_r0_patch[4] = {0x00, 0x00, 0x50, 0xe1}; // "cmp r0, r0" - patch((void *) 0x19378, cmp_r0_r0_patch); - patch((void *) 0x197cc, nop_patch); - - // Custom Username Is Loaded Manually, Disable Loading From options.txt - patch((void *) 0x192ac, nop_patch); - - // Replace "feedback_vibration" Loading/Saving With "gfx_ao" - { - // Replace String - patch_address((void *) &Strings::feedback_vibration_options_txt_name, (void *) "gfx_ao"); - // Loading - constexpr unsigned char offset = (unsigned char) offsetof(Options, ambient_occlusion); - unsigned char gfx_ao_loading_patch[4] = {offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET" - patch((void *) 0x193b8, gfx_ao_loading_patch); - // Saving - unsigned char gfx_ao_saving_patch[4] = {offset, 0x30, 0xd4, 0xe5}; // "ldrb r3, [r4, #OFFSET]" - patch((void *) 0x197f8, gfx_ao_saving_patch); - } - - // Replace "gfx_lowquality" Loading With "gfx_anaglyph" - { - // Replace String - patch_address((void *) &Strings::gfx_lowquality_options_txt_name, (void *) "gfx_anaglyph"); - // Loading - constexpr unsigned char offset = (unsigned char) offsetof(Options, anaglyph_3d); - unsigned char gfx_anaglyph_loading_patch[4] = {offset, 0x10, 0x84, 0xe2}; // "add r1, r4, #OFFSET" - patch((void *) 0x19400, gfx_anaglyph_loading_patch); - // Disable Loading Side Effects - patch((void *) 0x19414, nop_patch); - patch((void *) 0x1941c, nop_patch); + // Disable Saving Some Settings + unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x1973c, nop_patch); // "ctrl_sensitivity" + patch((void *) 0x197cc, nop_patch); // "ctrl_usetouchjoypad" } // UI diff --git a/mods/src/textures/lava.cpp b/mods/src/textures/lava.cpp index a4a04ad3c2..15e0b0299a 100644 --- a/mods/src/textures/lava.cpp +++ b/mods/src/textures/lava.cpp @@ -224,5 +224,9 @@ void _init_textures_lava(const bool animated_water_param, const bool animated_la animated_water = animated_water_param; animated_lava = animated_lava_param; animated_fire = animated_fire_param; + if (!animated_water) { + unsigned char disable_water_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x17094, disable_water_patch); + } overwrite_call((void *) 0x170b4, (void *) Textures_addDynamicTexture_injection); } diff --git a/mods/src/textures/textures.cpp b/mods/src/textures/textures.cpp index fdf1bd5d72..9bf4222699 100644 --- a/mods/src/textures/textures.cpp +++ b/mods/src/textures/textures.cpp @@ -164,12 +164,6 @@ void init_textures() { if (animated_water || animated_lava || animated_fire) { // Tick Dynamic Textures misc_run_on_tick(Minecraft_tick_injection); - // Disable Animated Water If Set - if (!animated_water) { - unsigned char disable_water_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" - patch((void *) 0x17094, disable_water_patch); - patch((void *) 0x170b4, disable_water_patch); - } // Animated Lava _init_textures_lava(animated_water, animated_lava, animated_fire); } @@ -178,6 +172,8 @@ void init_textures() { overwrite_calls(AppPlatform_linux_loadTexture, AppPlatform_linux_loadTexture_injection); // Stop Reloading Textures On Resize - unsigned char texture_reset_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" - patch((void *) 0x126b4, texture_reset_patch); + if (feature_has("Fix Reloading Textures On Resize", server_disabled)) { + unsigned char texture_reset_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x126b4, texture_reset_patch); + } } diff --git a/mods/src/title-screen/title-screen.cpp b/mods/src/title-screen/title-screen.cpp index 25239f05ea..3b61d3966e 100644 --- a/mods/src/title-screen/title-screen.cpp +++ b/mods/src/title-screen/title-screen.cpp @@ -183,18 +183,25 @@ void init_title_screen() { } // Better Scaling And Position + bool hijack_version_rendering = false; if (feature_has("Improved Classic Title Positioning", server_disabled)) { overwrite_call((void *) 0x3956c, (void *) StartMenuScreen_render_Textures_getTemporaryTextureData_injection_modern); overwrite_call((void *) 0x39528, (void *) StartMenuScreen_render_Screen_renderBackground_injection); + hijack_version_rendering = true; adjust_version_y = get_version_y; } - overwrite_call((void *) 0x39728, (void *) StartMenuScreen_render_GuiComponent_drawString_injection); // Add Splashes if (feature_has("Add Splashes", server_disabled)) { + hijack_version_rendering = true; _init_splashes(); } + // Adjust And Record Version String Rendering + if (hijack_version_rendering) { + overwrite_call((void *) 0x39728, (void *) StartMenuScreen_render_GuiComponent_drawString_injection); + } + // Init Welcome Screen if (feature_has("Add Welcome Screen", server_disabled)) { _init_welcome(); diff --git a/symbols/src/game/options/Options.def b/symbols/src/game/options/Options.def index aa6a7365ac..0974b045a6 100644 --- a/symbols/src/game/options/Options.def +++ b/symbols/src/game/options/Options.def @@ -4,6 +4,10 @@ method void initDefaultValue() = 0x18a54; method bool getBooleanValue(Options_Option *option) = 0x1cd74; method void addOptionToSaveOutput(std::vector *data, std::string option, int value) = 0x195e4; method void save() = 0x1966c; +method void update() = 0x19248; + +static-method bool readBool(const std::string &str, bool &out) = 0x19168; +static-method bool readInt(const std::string &str, int &out) = 0x19014; property OptionsFile options_file = 0x10c; property bool fancy_graphics = 0x17; @@ -18,3 +22,5 @@ property int sound = 0x4; property bool debug = 0xee; property bool server_visible = 0x104; property std::string username = 0x100; +property bool invert_mouse = 0xc; +property bool lefty = 0x1a; \ No newline at end of file