Attack Of The Templates!

This commit is contained in:
TheBrokenRail 2024-05-18 18:58:39 -04:00
parent 97bc124d72
commit b129f0a503
9 changed files with 159 additions and 193 deletions

@ -1 +1 @@
Subproject commit fbb9b6d6da1a9dfa9290d420d1b2c34f91026111
Subproject commit eb49f25fa45842ebff448cbadd347c883e66efb6

View File

@ -241,6 +241,7 @@ void setup_crash_report() {
// Close Log File
reborn_close_log();
unsetenv(MCPI_LOG_ENV);
// Show Crash Log
#ifndef MCPI_HEADLESS_MODE

View File

@ -1,8 +1,6 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// Patching Functions
@ -12,74 +10,127 @@ void reborn_init_patch();
// Replace Call Located At start With A Call To target
void _overwrite_call(const char *file, int line, void *start, void *target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target)
#define overwrite_call(...) \
_overwrite_call(__FILE__, __LINE__, __VA_ARGS__)
#define _setup_fancy_overwrite(start, name, target) \
static name##_t _original_for_##target = start; \
static name##_t _helper_for_##target = __overwrite_helper_for_##name(target, _original_for_##target)
// Make Sure Function Is Only Called Once
template <int>
static void _only_call_once() {
static bool _has_run = false;
if (_has_run) {
IMPOSSIBLE();
}
_has_run = true;
}
// Replace All Calls To Method start With target
void *_overwrite_calls(const char *file, int line, void *start, void *target);
#define overwrite_calls_manual(start, target) _overwrite_calls(__FILE__, __LINE__, start, target)
#define overwrite_calls(start, target) \
{ \
_setup_fancy_overwrite(start, start, target); \
start = (start##_t) overwrite_calls_manual((void *) start, (void *) _helper_for_##target); \
}
void *_overwrite_calls_manual(const char *file, int line, void *start, void *target);
#define overwrite_calls_manual(...) \
_overwrite_calls_manual(__FILE__, __LINE__, __VA_ARGS__)
template <int call_id, typename start_t, typename overwrite_t>
static void _overwrite_calls(const char *file, int line, start_t (*create_helper)(overwrite_t, start_t), start_t &start, overwrite_t target) {
_only_call_once<call_id>();
start_t helper = create_helper(target, start);
start = (start_t) _overwrite_calls_manual(file, line, (void *) start, (void *) helper);
}
#define overwrite_calls(start, ...) \
_overwrite_calls< \
__COUNTER__, \
start##_t, \
__overwrite_##start##_t \
>( \
__FILE__, __LINE__, \
__create_overwrite_helper_for_##start, \
start, \
__VA_ARGS__ \
)
// Replace All Calls To Virtual Method start With target
#define _check_if_method_is_new(name) \
{ \
if (!__is_new_method_##name()) { \
ERR("Method Is Not \"New\""); \
} \
}
#define overwrite_virtual_calls(start, target) \
{ \
_check_if_method_is_new(start); \
_setup_fancy_overwrite(*start##_vtable_addr, start, target); \
overwrite_calls_manual((void *) *start##_vtable_addr, (void *) _helper_for_##target); \
template <int call_id, typename start_t, typename overwrite_t>
static void _overwrite_virtual_calls(const char *file, int line, start_t (*create_helper)(overwrite_t, start_t), bool (*is_overwritable)(), start_t start, overwrite_t target) {
_only_call_once<call_id>();
if (!is_overwritable()) {
ERR("Virtual Method Is Not Overwritable");
}
start_t helper = create_helper(target, start);
_overwrite_calls_manual(file, line, (void *) start, (void *) helper);
}
#define overwrite_virtual_calls(start, ...) \
_overwrite_virtual_calls< \
__COUNTER__, \
start##_t, \
__overwrite_##start##_t \
>( \
__FILE__, __LINE__, \
__create_overwrite_helper_for_##start, \
__is_overwritable_##start, \
*start##_vtable_addr, \
__VA_ARGS__ \
)
// Replace All Calls To start With target Within [to, from)
void _overwrite_calls_within(const char *file, int line, void *from, void *to, void *start, void *target);
#define overwrite_calls_within_manual(from, to, start, target) _overwrite_calls_within(__FILE__, __LINE__, from, to, start, target)
#define overwrite_calls_within(from, to, start, target) \
{ \
start##_t type_check = target; \
overwrite_calls_within_manual(from, to, (void *) start, (void *) type_check); \
}
void _overwrite_calls_within_manual(const char *file, int line, void *from, void *to, void *start, void *target);
#define overwrite_calls_within_manual(...) \
_overwrite_calls_within(__FILE__, __LINE__, __VA_ARGS__)
template <typename start_t>
void _overwrite_calls_within(const char *file, int line, void *from, void *to, start_t start, start_t target) {
_overwrite_calls_within_manual(file, line, from, to, (void *) start, (void *) target);
}
#define overwrite_calls_within(from, to, start, ...) \
_overwrite_calls_within< \
start##_t \
>( \
__FILE__, __LINE__, \
from, to, \
start, \
__VA_ARGS__ \
)
// Get Target Address From BL Instruction
void *extract_from_bl_instruction(unsigned char *from);
// Replace Method start With target
void _overwrite(const char *file, int line, void *start, void *target);
#define overwrite_manual(start, target) _overwrite(__FILE__, __LINE__, (void *) start, (void *) target)
#define overwrite(start, target) \
{ \
start##_t type_check = target; \
overwrite_manual((void *) start, (void *) type_check); \
}
void _overwrite_manual(const char *file, int line, void *start, void *target);
#define overwrite_manual(...) \
_overwrite(__FILE__, __LINE__, __VA_ARGS__)
template <typename start_t>
void _overwrite(const char *file, int line, start_t start, start_t target) {
_overwrite_manual(file, line, (void *) start, (void *) target);
}
#define overwrite(start, ...) \
_overwrite< \
start##_t \
>( \
__FILE__, __LINE__, \
start, \
__VA_ARGS__ \
)
// Patch Instruction
void _patch(const char *file, int line, void *start, unsigned char patch[4]);
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch)
#define patch(...) \
_patch(__FILE__, __LINE__, __VA_ARGS__)
// Patch 4 Bytes Of Data
void _patch_address(const char *file, int line, void *start, void *target);
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, (void *) start, (void *) target)
#define patch_address(...) \
_patch_address(__FILE__, __LINE__, __VA_ARGS__)
// Patch VTable Entry
// This does not affect sub-classes.
#define patch_vtable(start, target) \
{ \
start##_t type_check = target; \
patch_address(start##_vtable_addr, (void *) type_check); \
}
#endif
#ifdef __cplusplus
template <typename start_t>
void _patch_vtable(const char *file, int line, start_t *start, start_t target) {
_patch_address(file, line, (void *) start, (void *) target);
}
#define patch_vtable(start, ...) \
_patch_vtable< \
start##_t \
>( \
__FILE__, __LINE__, \
start##_vtable_addr, \
__VA_ARGS__ \
)
#endif
#endif

View File

@ -77,7 +77,7 @@ static int _overwrite_calls_within_internal(const char *file, int line, void *fr
#define TEXT_END 0x1020c0
// Overwrite All B(L) Intrusctions That Target The Specified Address
#define NO_CALLSITE_ERROR "(%s:%i) Unable To Find Callsites For %p"
void *_overwrite_calls(const char *file, int line, void *start, void *target) {
void *_overwrite_calls_manual(const char *file, int line, void *start, void *target) {
// Add New Target To Code Block
void *code_block = update_code_block(target);
@ -97,7 +97,7 @@ void *_overwrite_calls(const char *file, int line, void *start, void *target) {
// Return
return code_block;
}
void _overwrite_calls_within(const char *file, int line, void *from /* inclusive */, void *to /* exclusive */, void *target, void *replacement) {
void _overwrite_calls_within_manual(const char *file, int line, void *from /* inclusive */, void *to /* exclusive */, void *target, void *replacement) {
// Add New Target To Code Block
void *code_block = update_code_block(replacement);
@ -113,7 +113,7 @@ void _overwrite_calls_within(const char *file, int line, void *from /* inclusive
}
// Overwrite Function
void _overwrite(const char *file, int line, void *start, void *target) {
void _overwrite_manual(const char *file, int line, void *start, void *target) {
// Replace the function's start with a call
// to the replacement function.
_overwrite_call_internal(file, line, start, target, 1);

View File

@ -8,21 +8,53 @@ extern "C" {
int32_t misc_get_real_selected_slot(Player *player);
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height);
typedef void (*misc_update_function_Minecraft_t)(Minecraft *obj);
void misc_run_on_update(misc_update_function_Minecraft_t function); // obj == Minecraft *
void misc_run_on_tick(misc_update_function_Minecraft_t function); // obj == Minecraft *
typedef void (*misc_update_function_Recipes_t)(Recipes *obj);
void misc_run_on_recipes_setup(misc_update_function_Recipes_t function); // obj == Recipes *
typedef void (*misc_update_function_FurnaceRecipes_t)(FurnaceRecipes *obj);
void misc_run_on_furnace_recipes_setup(misc_update_function_FurnaceRecipes_t function); // obj == FurnaceRecipes *
typedef void (*misc_update_function_FillingContainer_t)(FillingContainer *obj);
void misc_run_on_creative_inventory_setup(misc_update_function_FillingContainer_t function); // obj == FillingContainer *
typedef void (*misc_update_function_void_t)(void *obj);
void misc_run_on_tiles_setup(misc_update_function_void_t function); // obj == NULL
void misc_run_on_items_setup(misc_update_function_void_t function); // obj == NULL
void misc_run_on_language_setup(misc_update_function_void_t function); // obj == NULL
typedef bool (*misc_update_function_key_press_t)(Minecraft *minecrtaft, int key);
void misc_run_on_game_key_press(misc_update_function_key_press_t function); // In-Game Key Presses Only
extern bool is_in_chat;
}
}
#define misc_run_on_update(...) \
overwrite_virtual_calls(Minecraft_update, [](Minecraft_update_t _original, Minecraft *_self) { \
_original(_self); \
(__VA_ARGS__)(_self); \
})
#define misc_run_on_tick(...) \
overwrite_calls(Minecraft_tick, [](Minecraft_tick_t _original, Minecraft *_self, int _tick, int _max_ticks) { \
_original(_self, _tick, _max_ticks); \
(__VA_ARGS__)(_self); \
})
#define misc_run_on_recipes_setup(...) \
overwrite_calls(Recipes_constructor, [](Recipes_constructor_t _original, Recipes *_self) { \
_original(_self); \
(__VA_ARGS__)(_self); \
return _self; \
})
#define misc_run_on_furnace_recipes_setup(...) \
overwrite_calls(FurnaceRecipes_constructor, [](FurnaceRecipes_constructor_t _original, FurnaceRecipes *_self) { \
_original(_self); \
(__VA_ARGS__)(_self); \
return _self; \
})
#define misc_run_on_tiles_setup(...) \
overwrite_calls(Tile_initTiles, [](Tile_initTiles_t _original) { \
(__VA_ARGS__)(); \
_original(); \
})
#define misc_run_on_items_setup(...) \
overwrite_calls(Item_initItems, [](Item_initItems_t _original) { \
_original(); \
(__VA_ARGS__)(); \
})
#define misc_run_on_language_setup(...) \
overwrite_calls(I18n_loadLanguage, [](I18n_loadLanguage_t _original, AppPlatform *_self, std::string _language_name) { \
_original(_self, _language_name); \
(__VA_ARGS__)(); \
})
#define misc_run_on_game_key_press(...) \
overwrite_calls(Gui_handleKeyPressed, [](Gui_handleKeyPressed_t _original, Gui *_self, int _key) { \
if ((__VA_ARGS__)(_self->minecraft, _key)) { \
return; \
} \
_original(_self, _key); \
})

View File

@ -207,7 +207,7 @@ static FoodItem *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y,
// Return
return item;
}
static void Item_initItems_injection(__attribute__((unused)) void *null) {
static void Item_initItems_injection() {
bucket = create_bucket(69, 10, 4, "bucket");
}
@ -340,7 +340,7 @@ static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *
}
// Add the bucket name to the language file
static void Language_injection(__attribute__((unused)) void *null) {
static void Language_injection() {
I18n::_strings.insert(std::make_pair("item.bucketMilk.name", "Milk Bucket"));
}

View File

@ -153,7 +153,7 @@ static void make_cake() {
cake->setDescriptionId(&name);
}
static void Tile_initTiles_injection(__attribute__((unused)) void *null) {
static void Tile_initTiles_injection() {
make_cake();
}

View File

@ -27,56 +27,6 @@
} \
}
// Run Functions On Update
SETUP_CALLBACK(update, Minecraft);
// Handle Custom Update Behavior
static void Minecraft_update_injection(Minecraft_update_t original, Minecraft *minecraft) {
// Call Original Method
original(minecraft);
// Run Functions
handle_misc_update(minecraft);
}
// Run Functions On Tick
SETUP_CALLBACK(tick, Minecraft);
// Handle Custom Tick Behavior
static void Minecraft_tick_injection(Minecraft_tick_t original, Minecraft *minecraft, int32_t param_1, int32_t param_2) {
// Call Original Method
original(minecraft, param_1, param_2);
// Run Functions
handle_misc_tick(minecraft);
}
// Run Functions On Recipes Setup
SETUP_CALLBACK(recipes_setup, Recipes);
// Handle Custom Recipes Setup Behavior
static Recipes *Recipes_injection(Recipes_constructor_t original, Recipes *recipes) {
// Call Original Method
original(recipes);
// Run Functions
handle_misc_recipes_setup(recipes);
// Return
return recipes;
}
// Run Functions On Furnace Recipes Setup
SETUP_CALLBACK(furnace_recipes_setup, FurnaceRecipes);
// Handle Custom Furnace Recipes Setup Behavior
static FurnaceRecipes *FurnaceRecipes_injection(FurnaceRecipes_constructor_t original, FurnaceRecipes *recipes) {
// Call Original Method
original(recipes);
// Run Functions
handle_misc_furnace_recipes_setup(recipes);
// Return
return recipes;
}
// Run Functions On Creative Inventory Setup
SETUP_CALLBACK(creative_inventory_setup, FillingContainer);
// Handle Custom Creative Inventory Setup Behavior
@ -88,60 +38,6 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
handle_misc_creative_inventory_setup(filling_container);
}
// Run Functions On Tiles Setup
SETUP_CALLBACK(tiles_setup, void);
// Handle Custom Tiles Setup Behavior
static void Tile_initTiles_injection(Tile_initTiles_t original) {
// Run Functions
handle_misc_tiles_setup(nullptr);
// Call Original Method
original();
}
// Run Functions On Items Setup
SETUP_CALLBACK(items_setup, void);
// Handle Custom Items Setup Behavior
static void Item_initItems_injection(Item_initItems_t original) {
// Call Original Method
original();
// Run Functions
handle_misc_items_setup(nullptr);
}
// Run Functions On Language Setup
SETUP_CALLBACK(language_setup, void);
// Handle Custom Items Setup Behavior
static void I18n_loadLanguage_injection(I18n_loadLanguage_t original, AppPlatform *app, std::string language_name) {
// Call Original Method
original(app, std::move(language_name));
// Run Functions
handle_misc_language_setup(nullptr);
}
// Run Functions On GUI Key Press
STORE_CALLBACK(game_key_press, key_press)
static bool handle_misc_game_key_press(Minecraft *minecraft, int key) {
for (misc_update_function_key_press_t function : get_misc_game_key_press_functions()) {
if (function(minecraft, key)) {
return true;
}
}
return false;
}
// Handle Key Presses
static void Gui_handleKeyPressed_injection(Gui_handleKeyPressed_t original, Gui *self, int key) {
// Run Functions
if (handle_misc_game_key_press(self->minecraft, key)) {
return;
}
// Call Original Method
original(self, key);
}
// Render Fancy Background
void misc_render_background(int color, Minecraft *minecraft, int x, int y, int width, int height) {
// https://github.com/ReMinecraftPE/mcpe/blob/f0d65eaecec1b3fe9c2f2b251e114a890c54ab77/source/client/gui/components/RolledSelectionList.cpp#L169-L179
@ -166,20 +62,6 @@ void misc_render_background(int color, Minecraft *minecraft, int x, int y, int w
// Init
void _init_misc_api() {
// Handle Custom Update Behavior
overwrite_virtual_calls(Minecraft_update, Minecraft_update_injection);
// Handle Custom Tick Behavior
overwrite_calls(Minecraft_tick, Minecraft_tick_injection);
// Handle Custom Recipe Setup Behavior
overwrite_calls(Recipes_constructor, Recipes_injection);
overwrite_calls(FurnaceRecipes_constructor, FurnaceRecipes_injection);
// Handle Custom Creative Inventory Setup Behavior
overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection);
// Handle Custom Item/Tile Init Behavior
overwrite_calls(Tile_initTiles, Tile_initTiles_injection);
overwrite_calls(Item_initItems, Item_initItems_injection);
// Handle Custom Language Entries
overwrite_calls(I18n_loadLanguage, I18n_loadLanguage_injection);
// Handle Key Presses
overwrite_calls(Gui_handleKeyPressed, Gui_handleKeyPressed_injection);
}

View File

@ -822,10 +822,10 @@ void init_misc() {
#ifdef MCPI_HEADLESS_MODE
// Don't Render Game In Headless Mode
overwrite_manual(GameRenderer_render, nop);
overwrite_manual(NinecraftApp_initGLStates, nop);
overwrite_manual(Gui_onConfigChanged, nop);
overwrite_manual(LevelRenderer_generateSky, nop);
overwrite_manual((void *) GameRenderer_render, (void *) nop);
overwrite_manual((void *) NinecraftApp_initGLStates, (void *) nop);
overwrite_manual((void *) Gui_onConfigChanged, (void *) nop);
overwrite_manual((void *) LevelRenderer_generateSky, (void *) nop);
#else
// Improved Cursor Rendering
if (feature_has("Improved Cursor Rendering", server_disabled)) {
@ -849,7 +849,7 @@ void init_misc() {
// Remove Forced GUI Lag
if (feature_has("Remove Forced GUI Lag (Can Break Joining Servers)", server_enabled)) {
overwrite_manual(Common_sleepMs, nop);
overwrite_manual((void *) Common_sleepMs, (void *) nop);
}
#ifndef MCPI_HEADLESS_MODE