From 623cf065167b707f640ab41218324d334d46e27b Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sun, 10 Apr 2022 22:41:47 -0400 Subject: [PATCH] Fix Options Screen --- .../available-feature-flags | 5 +- launcher/src/client/launcher.cpp | 11 -- mods/CMakeLists.txt | 4 +- mods/src/options/options.c | 69 +++---- mods/src/options/options.cpp | 187 ++++++++++++++++++ mods/src/options/options.h | 12 ++ mods/src/server/server.cpp | 16 -- symbols/include/symbols/minecraft.h | 53 ++++- 8 files changed, 276 insertions(+), 81 deletions(-) create mode 100644 mods/src/options/options.cpp create mode 100644 mods/src/options/options.h diff --git a/launcher/data/client/lib/minecraft-pi-reborn-client/available-feature-flags b/launcher/data/client/lib/minecraft-pi-reborn-client/available-feature-flags index d15781fe..74f4c023 100644 --- a/launcher/data/client/lib/minecraft-pi-reborn-client/available-feature-flags +++ b/launcher/data/client/lib/minecraft-pi-reborn-client/available-feature-flags @@ -2,18 +2,15 @@ TRUE Touch GUI TRUE Fix Bow & Arrow TRUE Fix Attacking FALSE Force Mob Spawning -TRUE Fancy Graphics TRUE Disable Autojump By Default TRUE Display Nametags By Default TRUE Fix Sign Placement TRUE Show Block Outlines FALSE Expand Creative Inventory FALSE Remove Creative Mode Restrictions -FALSE Peaceful Mode TRUE Animated Water TRUE Remove Invalid Item Background TRUE Disable "gui_blocks" Atlas -TRUE Smooth Lighting FALSE 3D Anaglyph TRUE Fix Camera Rendering TRUE Implement Chat @@ -31,6 +28,6 @@ TRUE Implement Sound Engine TRUE Close Current Screen On Death FALSE Disable Raw Mouse Motion (Not Recommended) TRUE Fix Furnace Not Checking Item Auxiliary -FALSE Disable Hosting LAN Worlds TRUE Improved Cursor Rendering FALSE Disable V-Sync +TRUE Fix Options Screen diff --git a/launcher/src/client/launcher.cpp b/launcher/src/client/launcher.cpp index 3c923269..49b6ed89 100644 --- a/launcher/src/client/launcher.cpp +++ b/launcher/src/client/launcher.cpp @@ -216,17 +216,6 @@ int main(int argc, char *argv[]) { // Run run_zenity_and_set_env("MCPI_RENDER_DISTANCE", command); } - // Setup MCPI_USERNAME - { - std::vector command; - command.push_back("--entry"); - command.push_back("--text"); - command.push_back("Minecraft Username:"); - command.push_back("--entry-text"); - command.push_back("StevePi"); - // Run - run_zenity_and_set_env("MCPI_USERNAME", command); - } // Bootstrap bootstrap(argc, argv); diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 54e82892..988f4d49 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -74,8 +74,8 @@ target_link_libraries(death reborn-patch symbols feature) add_library(misc SHARED src/misc/misc.c src/misc/misc.cpp src/misc/logging.cpp) target_link_libraries(misc reborn-patch symbols media-layer-core feature GLESv1_CM) -add_library(options SHARED src/options/options.c) -target_link_libraries(options reborn-patch symbols feature) +add_library(options SHARED src/options/options.c src/options/options.cpp) +target_link_libraries(options reborn-patch symbols feature home) add_library(home SHARED src/home/home.c) target_link_libraries(home reborn-patch symbols) diff --git a/mods/src/options/options.c b/mods/src/options/options.c index 554e63e1..b2493d9f 100644 --- a/mods/src/options/options.c +++ b/mods/src/options/options.c @@ -5,6 +5,7 @@ #include "../feature/feature.h" #include "../init/init.h" +#include "options.h" // Force Mob Spawning static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) { @@ -32,41 +33,32 @@ static int get_render_distance() { } #endif -// Get Custom Username -static char *get_username() { - char *username = getenv("MCPI_USERNAME"); - if (username == NULL) { - username = "StevePi"; - } - return username; -} - -static int fancy_graphics; -static int peaceful_mode; static int anaglyph; -static int smooth_lighting; static int render_distance; -static int server_visible; // Configure Options -static void Minecraft_init_injection(unsigned char *this) { +unsigned char *stored_options = NULL; +static void Options_initDefaultValue_injection(unsigned char *options) { // Call Original Method - (*Minecraft_init)(this); + (*Options_initDefaultValue)(options); - unsigned char *options = this + Minecraft_options_property_offset; - // Enable Fancy Graphics - *(options + Options_fancy_graphics_property_offset) = fancy_graphics; // Enable Crosshair In Touch GUI *(options + Options_split_controls_property_offset) = 1; - // Peaceful Mode - *(int32_t *) (options + Options_peaceful_mode_property_offset) = peaceful_mode ? 0 : 2; // 3D Anaglyph *(options + Options_3d_anaglyph_property_offset) = anaglyph; - // Smooth Lighting - *(options + Options_ambient_occlusion_property_offset) = smooth_lighting; // Render Distance *(int32_t *) (options + Options_render_distance_property_offset) = render_distance; - // Server Visible - *(options + Options_server_visible_property_offset) = server_visible; + + // Store + stored_options = options; +} + +// Smooth Lighting +static void TileRenderer_tesselateBlockInWorld_injection(unsigned char *tile_renderer, unsigned char *tile, int32_t x, int32_t y, int32_t z) { + // Set Variable + *Minecraft_useAmbientOcclusion = *(stored_options + Options_ambient_occlusion_property_offset); + + // Call Original Method + (*TileRenderer_tesselateBlockInWorld)(tile_renderer, tile, x, y, z); } // Init @@ -76,10 +68,6 @@ void init_options() { overwrite((void *) LevelData_getSpawnMobs, (void *) LevelData_getSpawnMobs_injection); } - // Enable Fancy Graphics - fancy_graphics = feature_has("Fancy Graphics", server_disabled); - // Peaceful Mode - peaceful_mode = feature_has("Peaceful Mode", server_auto); // 3D Anaglyph anaglyph = feature_has("3D Anaglyph", server_disabled); // Render Distance @@ -89,21 +77,9 @@ void init_options() { #else render_distance = 3; #endif - // Server Visible - server_visible = !feature_has("Disable Hosting LAN Worlds", server_disabled); // Set Options - overwrite_calls((void *) Minecraft_init, (void *) Minecraft_init_injection); - - // Change Username - const char *username = get_username(); -#ifndef MCPI_SERVER_MODE - INFO("Setting Username: %s", username); -#endif - if (strcmp(*default_username, "StevePi") != 0) { - ERR("%s", "Default Username Is Invalid"); - } - patch_address((void *) default_username, (void *) username); + overwrite_calls((void *) Options_initDefaultValue, (void *) Options_initDefaultValue_injection); // Disable Autojump By Default if (feature_has("Disable Autojump By Default", server_disabled)) { @@ -118,10 +94,9 @@ void init_options() { patch((void *) 0xa6628, display_nametags_patch); } - // Enable Smooth Lighting - smooth_lighting = feature_has("Smooth Lighting", server_disabled); - if (smooth_lighting) { - unsigned char smooth_lighting_patch[4] = {0x01, 0x00, 0x53, 0xe3}; // "cmp r3, #0x1" - patch((void *) 0x59ea4, smooth_lighting_patch); - } + // Smooth Lighting + overwrite_calls((void *) TileRenderer_tesselateBlockInWorld, (void *) TileRenderer_tesselateBlockInWorld_injection); + + // Init C++ + _init_options_cpp(); } diff --git a/mods/src/options/options.cpp b/mods/src/options/options.cpp new file mode 100644 index 00000000..a193c7c9 --- /dev/null +++ b/mods/src/options/options.cpp @@ -0,0 +1,187 @@ +#include +#include +#include +#include + +#include + +#include "../feature/feature.h" +#include "../home/home.h" +#include "options.h" + +#include + +// Fix Initial Option Button Rendering +// The calling function doesn't exist in MCPE v0.6.1, so its name is unknown. +static unsigned char *OptionsPane_unknown_toggle_creating_function_OptionButton_injection(unsigned char *option_button, unsigned char *option) { + // Call Original Method + unsigned char *ret = (*OptionButton)(option_button, option); + + // Setup Image + (*OptionButton_updateImage)(option_button, stored_options); + + // Return + return ret; +} + +// Actually Save options.txt +// Hook Last Options::addOptionToSaveOutput Call +static void Options_save_Options_addOptionToSaveOutput_injection(unsigned char *options, std::vector &data, std::string option, int32_t value) { + // Call Original Method + (*Options_addOptionToSaveOutput)(options, data, option, value); + + // Save Fancy Graphics + (*Options_addOptionToSaveOutput)(options, data, "gfx_fancygraphics", *(options + Options_fancy_graphics_property_offset)); + + // Save Username + { + std::string entry = "mp_username:"; + std::string username = *(std::string *) (options + Options_username_property_offset); + entry += username; + data.push_back(entry); + } + + // Save File + unsigned char *options_file = options + Options_options_file_property_offset; + (*OptionsFile_save)(options_file, data); +} + +// MCPI's OptionsFile::getOptionStrings is broken, this is the version in v0.7.0 +static std::vector OptionsFile_getOptionStrings_injection(unsigned char *options_file) { + // Get options.txt Path + std::string path = *(std::string *) (options_file + OptionsFile_options_txt_path_property_offset); + // Parse + std::vector ret; + FILE *stream = fopen(path.c_str(), "r"); + char line[128]; + if (stream != NULL) { + while (fgets(line, 0x80, stream) != NULL) { + size_t sVar1 = strlen(line); + if (2 < sVar1) { + std::stringstream string_stream(line); + while (true) { + std::string data; + std::getline(string_stream, data, ':'); + int iVar2 = data.find_last_not_of(" \n\r\t"); + data.erase(iVar2 + 1); + if (data.length() == 0) { + break; + } + ret.push_back(data); + } + } + } + fclose(stream); + } + return ret; +} + +// Get New options.txt Path +static char *get_new_options_txt_path() { + static char *path = NULL; + // Path + if (path == NULL) { + safe_asprintf(&path, "%s/options.txt", home_get()); + } + // Return + return path; +} +// Free +__attribute__((destructor)) static void _free_new_options_txt_path() { + free(get_new_options_txt_path()); +} + +// Modify Option Toggles +static void OptionsPane_unknown_toggle_creating_function_injection(unsigned char *options_pane, unsigned char *unknown_object, std::string const& name, unsigned char *option) { + // Modify + if (name == "Fancy Graphics") { + option = Options_Option_GRAPHICS; + } else if (name == "Soft shadows") { + option = Options_Option_AMBIENT_OCCLUSION; + } else if (name == "Fancy Skies" || name == "Animated water") { + // These have no corresponding option, so disable the toggle. + return; + } else if (name == "Third person camera") { + // This isn't saved/loaded, so disable the toggle. + return; + } else if (name == "Lefty" || name == "Use touch screen" || name == "Split touch controls") { + // These toggles require touch support, so disable them. + return; + } else if (name == "Vibrate on destroy") { + // This toggle requires vibration support, so disable it. + return; + } + + // Call Original Method + (*OptionsPane_unknown_toggle_creating_function)(options_pane, unknown_object, name, option); +} + +// Add Missing Options To Options::getBooleanValue +static bool Options_getBooleanValue_injection(unsigned char *options, unsigned char *option) { + // Check + if (option == Options_Option_GRAPHICS) { + return *(options + Options_fancy_graphics_property_offset); + } else { + // Call Original Method + return (*Options_getBooleanValue)(options, option); + } +} + +// Init C++ +void _init_options_cpp() { + // NOP + unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + + // Fix Options Screen + if (feature_has("Fix Options Screen", server_disabled)) { + // Fix Initial Option Button Rendering + overwrite_call((void *) 0x24510, (void *) OptionsPane_unknown_toggle_creating_function_OptionButton_injection); + + // "Gui Scale" slider is broken, so disable it. + patch((void *) 0x35a10, nop_patch); + // "Vibrate on destroy" is disabled, so "Feedback" is empty, so disable it. + patch((void *) 0x35960, nop_patch); + + // Disconnect "This works?" Slider From Difficulty + unsigned char this_works_slider_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0" + patch((void *) 0x3577c, this_works_slider_patch); + + // Modify Option Toggles + overwrite_calls((void *) OptionsPane_unknown_toggle_creating_function, (void *) OptionsPane_unknown_toggle_creating_function_injection); + + // Add Missing Options To Options::getBooleanValue + overwrite_calls((void *) Options_getBooleanValue, (void *) Options_getBooleanValue_injection); + } + + // Actually Save options.txt + overwrite_call((void *) 0x197fc, (void *) Options_save_Options_addOptionToSaveOutput_injection); + // Fix options.txt Path + patch_address((void *) options_txt_path, (void *) get_new_options_txt_path()); + // When Loading, options.txt Should Be Opened In Read Mode + patch_address((void *) options_txt_fopen_mode_when_loading, (void *) "r"); + // Fix OptionsFile::getOptionStrings + overwrite_calls((void *) OptionsFile_getOptionStrings, (void *) OptionsFile_getOptionStrings_injection); + + // Sensitivity Loading/Saving Is Broken, Disable It + patch((void *) 0x1931c, nop_patch); + patch((void *) 0x1973c, nop_patch); + + // Replace "feedback_vibration" Loading/Saving With "gfx_ao" + { + // Replace String + static const char *new_feedback_vibration_options_txt_nam = "gfx_ao"; + static const char **new_feedback_vibration_options_txt_nam_ptr = &new_feedback_vibration_options_txt_nam; + patch_address((void *) feedback_vibration_options_txt_name_1, (void *) new_feedback_vibration_options_txt_nam_ptr); + patch_address((void *) feedback_vibration_options_txt_name_2, (void *) new_feedback_vibration_options_txt_nam_ptr); + // Loading + unsigned char gfx_ao_loading_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x10, 0x84, 0xe2}; // "add param_2, r4, #OFFSET" + patch((void *) 0x193b8, gfx_ao_loading_patch); + // Saving + unsigned char gfx_ao_saving_patch[4] = {(unsigned char) Options_ambient_occlusion_property_offset, 0x30, 0xd4, 0xe5}; // "ldrb r3, [r4, #OFFSET]" + patch((void *) 0x197f8, gfx_ao_saving_patch); + } + + // Disable "gfx_lowquality" Loading + patch((void *) 0x19414, nop_patch); + patch((void *) 0x1941c, nop_patch); +} diff --git a/mods/src/options/options.h b/mods/src/options/options.h new file mode 100644 index 00000000..924c4e2c --- /dev/null +++ b/mods/src/options/options.h @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((visibility("internal"))) void _init_options_cpp(); +__attribute__((visibility("internal"))) extern unsigned char *stored_options; + +#ifdef __cplusplus +} +#endif diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index 90318b43..bf796bf4 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -48,13 +48,11 @@ static ServerProperties &get_server_properties() { } // Default Server Properties -#define DEFAULT_MOTD "Minecraft Server" #define DEFAULT_SHOW_MINECON_BADGE "false" #define DEFAULT_GAME_MODE "0" #define DEFAULT_PORT "19132" #define DEFAULT_SEED "" #define DEFAULT_FORCE_MOB_SPAWNING "false" -#define DEFAULT_PEACEFUL_MODE "false" #define DEFAULT_WORLD_NAME "world" #define DEFAULT_MAX_PLAYERS "4" #define DEFAULT_WHITELIST "false" @@ -404,12 +402,6 @@ static unsigned char *ServerSideNetworkHandler_onReady_ClientGeneration_ServerSi return player; } -// Get MOTD -static std::string get_motd() { - std::string motd(get_server_properties().get_string("motd", DEFAULT_MOTD)); - return motd; -} - // Get Feature Flags static bool loaded_features = false; static const char *get_features() { @@ -418,9 +410,6 @@ static const char *get_features() { loaded_features = true; features.clear(); - if (get_server_properties().get_bool("peaceful-mode", DEFAULT_PEACEFUL_MODE)) { - features += "Peaceful Mode|"; - } if (get_server_properties().get_bool("force-mob-spawning", DEFAULT_FORCE_MOB_SPAWNING)) { features += "Force Mob Spawning|"; } @@ -453,8 +442,6 @@ static void server_init() { if (!properties_file.good()) { // Write Defaults std::ofstream properties_file_output(file); - properties_file_output << "# Message Of The Day\n"; - properties_file_output << "motd=" DEFAULT_MOTD "\n"; properties_file_output << "# Show The MineCon Badge Next To MOTD In Server List\n"; properties_file_output << "show-minecon-badge=" DEFAULT_SHOW_MINECON_BADGE "\n"; properties_file_output << "# Game Mode (0 = Survival, 1 = Creative)\n"; @@ -465,8 +452,6 @@ static void server_init() { properties_file_output << "seed=" DEFAULT_SEED "\n"; properties_file_output << "# Force Mob Spawning (false = Disabled, true = Enabled)\n"; properties_file_output << "force-mob-spawning=" DEFAULT_FORCE_MOB_SPAWNING "\n"; - properties_file_output << "# Peaceful Mode (false = Disabled, true = Enabled)\n"; - properties_file_output << "peaceful-mode=" DEFAULT_PEACEFUL_MODE "\n"; properties_file_output << "# World To Select\n"; properties_file_output << "world-name=" DEFAULT_WORLD_NAME "\n"; properties_file_output << "# Maximum Player Count\n"; @@ -531,5 +516,4 @@ static void server_init() { void init_server() { server_init(); setenv("MCPI_FEATURE_FLAGS", get_features(), 1); - setenv("MCPI_USERNAME", get_motd().c_str(), 1); } diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index 1267eef7..69253e6b 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -18,6 +18,10 @@ static renderCursor_t renderCursor = (renderCursor_t) 0x480c4; static char **default_path = (char **) 0xe264; // /.minecraft/ static char **default_username = (char **) 0x18fd4; // StevePi static char **minecraft_pi_version = (char **) 0x39d94; // v0.1.1 alpha +static char **options_txt_path = (char **) 0x19bc8; // options.txt +static char **options_txt_fopen_mode_when_loading = (char **) 0x19d24; // w +static char ***feedback_vibration_options_txt_name_1 = (char ***) 0x198a0; // feedback_vibration +static char ***feedback_vibration_options_txt_name_2 = (char ***) 0x194bc; // feedback_vibration static unsigned char **Material_stone = (unsigned char **) 0x180a9c; // Material @@ -53,6 +57,11 @@ static unsigned char **Tile_grass_carried = (unsigned char **) 0x181dd4; // Tile static float *InvGuiScale = (float *) 0x135d98; +static unsigned char *Options_Option_GRAPHICS = (unsigned char *) 0x136c2c; // Option +static unsigned char *Options_Option_AMBIENT_OCCLUSION = (unsigned char *) 0x136c38; // Option + +static bool *Minecraft_useAmbientOcclusion = (bool *) 0x136b90; + // Structures struct AABB { @@ -109,6 +118,11 @@ static uint32_t Tile_use_vtable_offset = 0x98; static uint32_t Tile_id_property_offset = 0x8; // int32_t static uint32_t Tile_category_property_offset = 0x3c; // int32_t +// TileRenderer + +typedef void (*TileRenderer_tesselateBlockInWorld_t)(unsigned char *tile_renderer, unsigned char *tile, int32_t x, int32_t y, int32_t z); +static TileRenderer_tesselateBlockInWorld_t TileRenderer_tesselateBlockInWorld = (TileRenderer_tesselateBlockInWorld_t) 0x59e30; + // GameMode typedef void (*GameMode_releaseUsingItem_t)(unsigned char *game_mode, unsigned char *player); @@ -237,9 +251,16 @@ static uint32_t HitResult_type_property_offset = 0x0; // Options +typedef void (*Options_initDefaultValue_t)(unsigned char *options); +static Options_initDefaultValue_t Options_initDefaultValue = (Options_initDefaultValue_t) 0x18a54; + +typedef bool (*Options_getBooleanValue_t)(unsigned char *options, unsigned char *option); +static Options_getBooleanValue_t Options_getBooleanValue = (Options_getBooleanValue_t) 0x1cd74; + +static uint32_t Options_options_file_property_offset = 0x10c; // OptionsFile static uint32_t Options_fancy_graphics_property_offset = 0x17; // unsigned char / bool static uint32_t Options_split_controls_property_offset = 0x105; // int32_t -static uint32_t Options_peaceful_mode_property_offset = 0xe8; // unsigned char / bool +static uint32_t Options_game_difficulty_property_offset = 0xe8; // int32_t static uint32_t Options_3d_anaglyph_property_offset = 0x15; // unsigned char / bool static uint32_t Options_ambient_occlusion_property_offset = 0x18; // unsigned char / bool static uint32_t Options_hide_gui_property_offset = 0xec; // unsigned char / bool @@ -248,6 +269,15 @@ static uint32_t Options_render_distance_property_offset = 0x10; // int32_t static uint32_t Options_sound_property_offset = 0x4; // int32_t static uint32_t Options_debug_property_offset = 0xee; // unsigned char / bool static uint32_t Options_server_visible_property_offset = 0x104; // unsigned char / bool +static uint32_t Options_username_property_offset = 0x100; // std::string + +// OptionButton + +typedef unsigned char *(*OptionButton_t)(unsigned char *option_button, unsigned char *option); +static OptionButton_t OptionButton = (OptionButton_t) 0x1c968; + +typedef void (*OptionButton_updateImage_t)(unsigned char *option_button, unsigned char *options); +static OptionButton_updateImage_t OptionButton_updateImage = (OptionButton_updateImage_t) 0x1ca58; // MouseBuildInput @@ -644,6 +674,7 @@ static uint32_t SoundEngine_options_property_offset = 0x4; // Options * #ifdef __cplusplus #include +#include // Structures @@ -730,6 +761,26 @@ static SoundEngine_play_t SoundEngine_play = (SoundEngine_play_t) 0x67860; typedef std::string (*Common_getGameVersionString_t)(std::string const& version_suffix); static Common_getGameVersionString_t Common_getGameVersionString = (Common_getGameVersionString_t) 0x15068; +// Options + +typedef void (*Options_addOptionToSaveOutput_t)(unsigned char *options, std::vector &data, std::string option, int32_t value); +static Options_addOptionToSaveOutput_t Options_addOptionToSaveOutput = (Options_addOptionToSaveOutput_t) 0x195e4; + +// OptionsFile + +typedef std::vector (*OptionsFile_getOptionStrings_t)(unsigned char *options_file); +static OptionsFile_getOptionStrings_t OptionsFile_getOptionStrings = (OptionsFile_getOptionStrings_t) 0x19c1c; + +typedef void (*OptionsFile_save_t)(unsigned char *options_file, std::vector const& data); +static OptionsFile_save_t OptionsFile_save = (OptionsFile_save_t) 0x19bcc; + +static uint32_t OptionsFile_options_txt_path_property_offset = 0x0; // std::string + +// OptionsPane + +typedef void (*OptionsPane_unknown_toggle_creating_function_t)(unsigned char *options_pane, unsigned char *unknown_object, std::string const& name, unsigned char *option); +static OptionsPane_unknown_toggle_creating_function_t OptionsPane_unknown_toggle_creating_function = (OptionsPane_unknown_toggle_creating_function_t) 0x24470; + #endif #pragma GCC diagnostic pop