2024-05-09 00:18:50 +00:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include <libreborn/libreborn.h>
|
|
|
|
#include <symbols/minecraft.h>
|
|
|
|
|
|
|
|
#include <mods/feature/feature.h>
|
|
|
|
|
|
|
|
#include "options-internal.h"
|
|
|
|
|
|
|
|
// Fix Initial Option Button Rendering
|
|
|
|
// The calling function doesn't exist in MCPE v0.6.1, so its name is unknown.
|
|
|
|
static OptionButton *OptionsPane_unknown_toggle_creating_function_OptionButton_injection(OptionButton *option_button, Options_Option *option) {
|
|
|
|
// Call Original Method
|
2024-05-15 09:02:19 +00:00
|
|
|
OptionButton *ret = option_button->constructor(option);
|
2024-05-09 00:18:50 +00:00
|
|
|
|
|
|
|
// Setup Image
|
2024-05-15 09:02:19 +00:00
|
|
|
option_button->updateImage(stored_options);
|
2024-05-09 00:18:50 +00:00
|
|
|
|
|
|
|
// Return
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Modify Option Toggles
|
2024-09-21 01:30:47 +00:00
|
|
|
static void OptionsPane_unknown_toggle_creating_function_injection(OptionsPane_unknown_toggle_creating_function_t original, OptionsPane *options_pane, const uint32_t group_id, std::string *name_ptr, Options_Option *option) {
|
2024-05-09 00:18:50 +00:00
|
|
|
// Modify
|
2024-09-21 01:30:47 +00:00
|
|
|
const std::string name = *name_ptr;
|
2024-05-09 00:18:50 +00:00
|
|
|
std::string new_name = name;
|
|
|
|
if (name == "Fancy Graphics") {
|
2024-05-17 06:52:55 +00:00
|
|
|
option = &Options_Option::GRAPHICS;
|
2024-05-09 00:18:50 +00:00
|
|
|
} else if (name == "Soft shadows") {
|
2024-05-17 06:52:55 +00:00
|
|
|
option = &Options_Option::AMBIENT_OCCLUSION;
|
2024-05-09 00:18:50 +00:00
|
|
|
} 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;
|
|
|
|
} else if (name == "Invert X-axis") {
|
|
|
|
// Fix Incorrect Name
|
|
|
|
new_name = "Invert Y-axis";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
original(options_pane, group_id, &new_name, option);
|
|
|
|
|
|
|
|
// Add 3D Anaglyph
|
2024-05-17 06:52:55 +00:00
|
|
|
if (option == &Options_Option::GRAPHICS) {
|
2024-05-09 00:18:50 +00:00
|
|
|
std::string cpp_string = "3D Anaglyph";
|
2024-05-17 06:52:55 +00:00
|
|
|
original(options_pane, group_id, &cpp_string, &Options_Option::ANAGLYPH);
|
2024-05-09 00:18:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add Peaceful Mode
|
2024-05-17 06:52:55 +00:00
|
|
|
if (option == &Options_Option::SERVER_VISIBLE) {
|
2024-05-09 00:18:50 +00:00
|
|
|
std::string cpp_string = "Peaceful mode";
|
2024-05-17 06:52:55 +00:00
|
|
|
original(options_pane, group_id, &cpp_string, &Options_Option::DIFFICULTY);
|
2024-05-09 00:18:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add Missing Options To Options::getBooleanValue
|
|
|
|
static bool Options_getBooleanValue_injection(Options_getBooleanValue_t original, Options *options, Options_Option *option) {
|
|
|
|
// Check
|
2024-05-17 06:52:55 +00:00
|
|
|
if (option == &Options_Option::GRAPHICS) {
|
2024-05-09 00:18:50 +00:00
|
|
|
return options->fancy_graphics;
|
2024-05-17 06:52:55 +00:00
|
|
|
} else if (option == &Options_Option::DIFFICULTY) {
|
2024-05-09 00:18:50 +00:00
|
|
|
return options->game_difficulty == 0;
|
|
|
|
} else {
|
|
|
|
// Call Original Method
|
|
|
|
return original(options, option);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix Difficulty When Toggling
|
|
|
|
static void OptionButton_toggle_Options_save_injection(Options *self) {
|
|
|
|
// Fix Value
|
|
|
|
if (self->game_difficulty == 1) {
|
|
|
|
// Disable Peaceful
|
|
|
|
self->game_difficulty = 2;
|
|
|
|
} else if (self->game_difficulty == 3) {
|
|
|
|
// Switch To Peaceful
|
|
|
|
self->game_difficulty = 0;
|
|
|
|
}
|
|
|
|
// Call Original Method
|
2024-05-15 09:02:19 +00:00
|
|
|
self->save();
|
2024-05-09 00:18:50 +00:00
|
|
|
}
|
|
|
|
|
2024-05-09 05:25:53 +00:00
|
|
|
// Add "Reborn" Info Button
|
|
|
|
#define INFO_BUTTON_ID 99
|
|
|
|
static void OptionsScreen_init_injection(OptionsScreen_init_t original, OptionsScreen *self) {
|
|
|
|
// Call Original Method
|
|
|
|
original(self);
|
|
|
|
|
|
|
|
// Add Button
|
2024-09-21 01:30:47 +00:00
|
|
|
Touch_TButton *button = Touch_TButton::allocate();
|
2024-05-09 05:25:53 +00:00
|
|
|
ALLOC_CHECK(button);
|
|
|
|
std::string name = "Reborn";
|
2024-07-15 07:05:05 +00:00
|
|
|
button->constructor(INFO_BUTTON_ID, name);
|
2024-05-09 05:25:53 +00:00
|
|
|
self->rendered_buttons.push_back((Button *) button);
|
|
|
|
self->selectable_buttons.push_back((Button *) button);
|
|
|
|
}
|
|
|
|
static void OptionsScreen_setupPositions_injection(OptionsScreen_setupPositions_t original, OptionsScreen *self) {
|
|
|
|
// Call Original Method
|
|
|
|
original(self);
|
|
|
|
|
|
|
|
// Find Button
|
2024-09-21 01:30:47 +00:00
|
|
|
const Button *prevButton = nullptr;
|
2024-05-09 05:25:53 +00:00
|
|
|
Button *button = nullptr;
|
|
|
|
for (Button *x : self->selectable_buttons) {
|
|
|
|
if (x->id == INFO_BUTTON_ID) {
|
|
|
|
button = x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prevButton = x;
|
|
|
|
}
|
|
|
|
if (button == nullptr || prevButton == nullptr) {
|
|
|
|
IMPOSSIBLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup Button
|
|
|
|
button->width = prevButton->width;
|
|
|
|
button->height = prevButton->height;
|
|
|
|
button->x = prevButton->x;
|
|
|
|
button->y = prevButton->y + prevButton->height;
|
|
|
|
}
|
|
|
|
static void OptionsScreen_buttonClicked_injection(OptionsScreen_buttonClicked_t original, OptionsScreen *self, Button *button) {
|
|
|
|
// Check ID
|
|
|
|
if (button->id == INFO_BUTTON_ID) {
|
|
|
|
// Show Screen
|
|
|
|
self->minecraft->setScreen(_create_options_info_screen());
|
|
|
|
} else {
|
|
|
|
// Call Original Method
|
|
|
|
original(self, button);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void OptionsScreen_removed_injection(OptionsScreen_removed_t original, OptionsScreen *self) {
|
|
|
|
// Delete Button
|
|
|
|
Button *button = nullptr;
|
|
|
|
for (Button *x : self->selectable_buttons) {
|
|
|
|
if (x->id == INFO_BUTTON_ID) {
|
|
|
|
button = x;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (button == nullptr) {
|
|
|
|
IMPOSSIBLE();
|
|
|
|
}
|
|
|
|
button->destructor_deleting();
|
|
|
|
|
|
|
|
// Call Original Method
|
|
|
|
original(self);
|
|
|
|
}
|
|
|
|
|
2024-05-09 00:18:50 +00:00
|
|
|
// Init
|
|
|
|
void _init_options_ui() {
|
|
|
|
// Fix Options Screen
|
|
|
|
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
|
|
|
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(OptionsPane_unknown_toggle_creating_function, OptionsPane_unknown_toggle_creating_function_injection);
|
|
|
|
|
|
|
|
// Add Missing Options To Options::getBooleanValue
|
|
|
|
overwrite_calls(Options_getBooleanValue, Options_getBooleanValue_injection);
|
|
|
|
|
|
|
|
// Fix Difficulty When Toggling
|
|
|
|
overwrite_call((void *) 0x1cd00, (void *) OptionButton_toggle_Options_save_injection);
|
|
|
|
}
|
2024-05-09 05:25:53 +00:00
|
|
|
|
|
|
|
// Info Button
|
2024-05-09 06:06:24 +00:00
|
|
|
if (feature_has("Add Reborn Info To Options", server_disabled)) {
|
2024-05-09 05:25:53 +00:00
|
|
|
// Add Button
|
2024-05-24 08:44:53 +00:00
|
|
|
overwrite_calls(OptionsScreen_init, OptionsScreen_init_injection);
|
2024-05-09 05:25:53 +00:00
|
|
|
// Position Button
|
2024-05-24 08:44:53 +00:00
|
|
|
overwrite_calls(OptionsScreen_setupPositions, OptionsScreen_setupPositions_injection);
|
2024-05-09 05:25:53 +00:00
|
|
|
// Handle Click
|
2024-05-24 08:44:53 +00:00
|
|
|
overwrite_calls(OptionsScreen_buttonClicked, OptionsScreen_buttonClicked_injection);
|
2024-05-09 05:25:53 +00:00
|
|
|
// Cleanup
|
2024-05-24 08:44:53 +00:00
|
|
|
overwrite_calls(OptionsScreen_removed, OptionsScreen_removed_injection);
|
2024-05-09 05:25:53 +00:00
|
|
|
}
|
2024-05-15 09:02:19 +00:00
|
|
|
}
|