From 68519f06fdedb3e40b774cbfa861bf143206c7d9 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sun, 10 Jul 2022 10:37:19 -0400 Subject: [PATCH] Add Buckets --- CMakeLists.txt | 9 +- example-mods/expanded-creative/CMakeLists.txt | 2 +- .../expanded-creative/expanded-creative.cpp | 14 +- launcher/src/client/available-feature-flags | 1 + media-layer/core/src/audio/api.cpp | 36 +- mods/CMakeLists.txt | 11 +- mods/include/mods/init/init.h | 1 + mods/include/mods/misc/misc.h | 7 + mods/src/bucket/README.md | 2 + mods/src/bucket/bucket.cpp | 310 ++++++++++++++++++ mods/src/creative/creative.cpp | 9 +- mods/src/init/init.c | 1 + mods/src/input/drop.cpp | 10 +- mods/src/misc/api.cpp | 100 +++--- mods/src/misc/misc.c | 17 + mods/src/sound/sound.cpp | 6 +- symbols/include/symbols/minecraft.h | 112 +++++-- 17 files changed, 530 insertions(+), 118 deletions(-) create mode 100644 mods/src/bucket/README.md create mode 100644 mods/src/bucket/bucket.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d3ba8abf8..22b334fd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,9 +137,14 @@ add_subdirectory(dependencies) # Warnings add_compile_options(-Wall -Wextra -Werror -Wpointer-arith -Wshadow -Wnull-dereference) -if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0) +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") # Prevents False Positives - add_compile_options(-Wno-stringop-overflow) + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 10.0) + add_compile_options(-Wno-stringop-overflow) + endif() + if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 11.0) + add_compile_options(-Wno-array-bounds -Wno-stringop-overread) + endif() endif() add_link_options(-Wl,--no-undefined) add_definitions(-D_GNU_SOURCE) diff --git a/example-mods/expanded-creative/CMakeLists.txt b/example-mods/expanded-creative/CMakeLists.txt index 9a50be0ce..258f3e837 100644 --- a/example-mods/expanded-creative/CMakeLists.txt +++ b/example-mods/expanded-creative/CMakeLists.txt @@ -12,4 +12,4 @@ include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cma # Build add_library(expanded-creative SHARED expanded-creative.cpp) -target_link_libraries(expanded-creative mods-headers reborn-patch symbols) +target_link_libraries(expanded-creative mods-headers reborn-patch symbols misc) diff --git a/example-mods/expanded-creative/expanded-creative.cpp b/example-mods/expanded-creative/expanded-creative.cpp index d3f219645..45c562d44 100644 --- a/example-mods/expanded-creative/expanded-creative.cpp +++ b/example-mods/expanded-creative/expanded-creative.cpp @@ -3,14 +3,11 @@ #include #include #include +#include // The Actual Mod -static FillingContainer_addItem_t original_mod; -static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, ItemInstance *item_instance) { - // Call Original Modified Method - int32_t ret = (*original_mod)(filling_container, item_instance); - +static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) { ItemInstance *fire_instance = new ItemInstance; ALLOC_CHECK(fire_instance); fire_instance->count = 255; @@ -633,9 +630,6 @@ static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(un chickenRaw_instance->auxiliary = 0; chickenRaw_instance->id = 365; (*FillingContainer_addItem)(filling_container, chickenRaw_instance); - - // Return - return ret; } // Init @@ -645,7 +639,5 @@ HOOK(init_creative, void, ()) { INFO("Loading Expanded Creative Mod"); - void *point = (void *) 0x8e0fc; - original_mod = (FillingContainer_addItem_t) extract_from_bl_instruction((unsigned char *) point); - overwrite_call(point, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection); + misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection); } diff --git a/launcher/src/client/available-feature-flags b/launcher/src/client/available-feature-flags index 8011b73fc..6ef64a515 100644 --- a/launcher/src/client/available-feature-flags +++ b/launcher/src/client/available-feature-flags @@ -38,3 +38,4 @@ TRUE Force Touch GUI Button Behavior TRUE Improved Button Hover Behavior TRUE Implement Create World Dialog TRUE Remove Forced GUI Lag +TRUE Add Buckets diff --git a/media-layer/core/src/audio/api.cpp b/media-layer/core/src/audio/api.cpp index 60d5aee93..bdc70aacc 100644 --- a/media-layer/core/src/audio/api.cpp +++ b/media-layer/core/src/audio/api.cpp @@ -11,17 +11,11 @@ #include "api.h" // Store Audio Sources -static std::vector &get_sources() { - static std::vector sources; - return sources; -} +static std::vector sources; // Store Idle Audio Sources #define MAX_IDLE_SOURCES 50 -static std::vector &get_idle_sources() { - static std::vector sources; - return sources; -} +static std::vector idle_sources; // Error Checking #define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError()) @@ -36,17 +30,17 @@ static std::vector &get_idle_sources() { // Delete Sources void _media_audio_delete_sources() { if (_media_audio_is_loaded()) { - for (ALuint source : get_idle_sources()) { + for (ALuint source : idle_sources) { alDeleteSources(1, &source); AL_ERROR_CHECK(); } - for (ALuint source : get_sources()) { + for (ALuint source : sources) { alDeleteSources(1, &source); AL_ERROR_CHECK(); } } - get_idle_sources().clear(); - get_sources().clear(); + idle_sources.clear(); + sources.clear(); } // Update Listener @@ -68,8 +62,8 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) { AL_ERROR_CHECK(); // Clear Finished Sources - std::vector::iterator it = get_sources().begin(); - while (it != get_sources().end()) { + std::vector::iterator it = sources.begin(); + while (it != sources.end()) { ALuint source = *it; bool remove = false; // Check @@ -81,8 +75,8 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) { if (source_state != AL_PLAYING) { // Finished Playing remove = true; - if (get_idle_sources().size() < MAX_IDLE_SOURCES) { - get_idle_sources().push_back(source); + if (idle_sources.size() < MAX_IDLE_SOURCES) { + idle_sources.push_back(source); } else { alDeleteSources(1, &source); AL_ERROR_CHECK(); @@ -94,7 +88,7 @@ void media_audio_update(float volume, float x, float y, float z, float yaw) { } // Remove If Needed if (remove) { - it = get_sources().erase(it); + it = sources.erase(it); } else { ++it; } @@ -111,10 +105,10 @@ void media_audio_play(const char *source, const char *name, float x, float y, fl if (volume > 0.0f && buffer) { // Get Source ALuint al_source; - if (get_idle_sources().size() > 0) { + if (idle_sources.size() > 0) { // Use Idle Source - al_source = get_idle_sources().back(); - get_idle_sources().pop_back(); + al_source = idle_sources.back(); + idle_sources.pop_back(); } else { // Create Source alGenSources(1, &al_source); @@ -160,7 +154,7 @@ void media_audio_play(const char *source, const char *name, float x, float y, fl // Play alSourcePlay(al_source); AL_ERROR_CHECK(); - get_sources().push_back(al_source); + sources.push_back(al_source); } } } diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index a6f914837..ddd8f054c 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -29,7 +29,7 @@ add_library(chat SHARED src/chat/chat.cpp src/chat/ui.c) target_link_libraries(chat mods-headers reborn-patch symbols feature) add_library(creative SHARED src/creative/creative.cpp) -target_link_libraries(creative mods-headers reborn-patch symbols feature) +target_link_libraries(creative mods-headers reborn-patch symbols feature misc) add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/ui.cpp) target_link_libraries(game-mode mods-headers reborn-patch symbols feature) @@ -54,7 +54,7 @@ else() target_link_libraries(camera mods-headers reborn-patch symbols media-layer-core feature home) add_library(input SHARED src/input/input.cpp src/input/bow.c src/input/attack.c src/input/toggle.c src/input/misc.c src/input/drop.cpp) - target_link_libraries(input mods-headers reborn-patch symbols creative feature media-layer-core) + target_link_libraries(input mods-headers reborn-patch symbols creative feature misc media-layer-core) add_library(sign SHARED src/sign/sign.cpp) target_link_libraries(sign mods-headers reborn-patch symbols feature input) @@ -84,6 +84,9 @@ target_link_libraries(misc mods-headers reborn-patch symbols media-layer-core fe add_library(options SHARED src/options/options.c src/options/options.cpp) target_link_libraries(options mods-headers reborn-patch symbols feature home) +add_library(bucket SHARED src/bucket/bucket.cpp) +target_link_libraries(bucket mods-headers reborn-patch symbols feature misc) + add_library(home SHARED src/home/home.c) target_link_libraries(home mods-headers reborn-patch symbols) @@ -91,7 +94,7 @@ add_library(test SHARED src/test/test.c) target_link_libraries(test mods-headers reborn-patch home) add_library(init SHARED src/init/init.c) -target_link_libraries(init mods-headers compat game-mode misc death options chat creative home version test media-layer-core) +target_link_libraries(init mods-headers compat game-mode misc death options chat creative bucket home version test media-layer-core) if(MCPI_SERVER_MODE) target_link_libraries(init server) else() @@ -99,7 +102,7 @@ else() endif() ## Install Mods -set(MODS_TO_INSTALL init compat readdir feature game-mode misc override death options chat creative home version test) +set(MODS_TO_INSTALL init compat readdir feature game-mode misc override death options chat creative bucket home version test) if(MCPI_SERVER_MODE) list(APPEND MODS_TO_INSTALL server) else() diff --git a/mods/include/mods/init/init.h b/mods/include/mods/init/init.h index 3b17ac8db..2b4793e50 100644 --- a/mods/include/mods/init/init.h +++ b/mods/include/mods/init/init.h @@ -27,6 +27,7 @@ void init_misc(); void init_death(); void init_options(); void init_chat(); +void init_bucket(); void init_home(); #ifndef MCPI_SERVER_MODE void init_benchmark(); diff --git a/mods/include/mods/misc/misc.h b/mods/include/mods/misc/misc.h index 4c66d8dc7..9e08cfcc3 100644 --- a/mods/include/mods/misc/misc.h +++ b/mods/include/mods/misc/misc.h @@ -1,14 +1,21 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif +int32_t misc_get_real_selected_slot(unsigned char *player); + typedef void (*misc_update_function_t)(unsigned char *obj); void misc_run_on_update(misc_update_function_t function); // obj == Minecraft * void misc_run_on_tick(misc_update_function_t function); // obj == Minecraft * void misc_run_on_recipes_setup(misc_update_function_t function); // obj == Recipes * void misc_run_on_furnace_recipes_setup(misc_update_function_t function); // obj == FurnaceRecipes * +void misc_run_on_creative_inventory_setup(misc_update_function_t function); // obj == FillingContainer * +void misc_run_on_tiles_setup(misc_update_function_t function); // obj == NULL +void misc_run_on_items_setup(misc_update_function_t function); // obj == NULL void Level_saveLevelData_injection(unsigned char *level); diff --git a/mods/src/bucket/README.md b/mods/src/bucket/README.md new file mode 100644 index 000000000..5a8ddd824 --- /dev/null +++ b/mods/src/bucket/README.md @@ -0,0 +1,2 @@ +# ``bucket`` Mod +This mod adds buckets. diff --git a/mods/src/bucket/bucket.cpp b/mods/src/bucket/bucket.cpp new file mode 100644 index 000000000..82c3036c8 --- /dev/null +++ b/mods/src/bucket/bucket.cpp @@ -0,0 +1,310 @@ +#include +#include + +#include +#include +#include + +// Items +unsigned char *bucket = NULL; + +// Description And Texture +static std::string BucketItem_getDescriptionId(__attribute__((unused)) unsigned char *item, const ItemInstance *item_instance) { + if (item_instance->auxiliary == *(int32_t *) (*Tile_water + Tile_id_property_offset)) { + return "item.bucketWater"; + } else if (item_instance->auxiliary == *(int32_t *) (*Tile_lava + Tile_id_property_offset)) { + return "item.bucketLava"; + } else { + return "item.bucket"; + } +} +static int32_t BucketItem_getIcon(__attribute__((unused)) unsigned char *item, int32_t auxiliary) { + if (auxiliary == *(int32_t *) (*Tile_water + Tile_id_property_offset)) { + return 75; + } else if (auxiliary == *(int32_t *) (*Tile_lava + Tile_id_property_offset)) { + return 76; + } else { + return 74; + } +} + +// Use Bucket +static int32_t BucketItem_useOn(__attribute__((unused)) unsigned char *item, ItemInstance *item_instance, unsigned char *player, unsigned char *level, int32_t x, int32_t y, int32_t z, int32_t hit_side, __attribute__((unused)) float hit_x, __attribute__((unused)) float hit_y, __attribute__((unused)) float hit_z) { + if (item_instance->count < 1) { + return 0; + } + if (item_instance->auxiliary == 0) { + // Empty Bucket + int32_t new_auxiliary = 0; + int32_t tile = (*Level_getTile)(level, x, y, z); + if (tile == *(int32_t *) (*Tile_calmWater + Tile_id_property_offset)) { + new_auxiliary = *(int32_t *) (*Tile_water + Tile_id_property_offset); + } else if (tile == *(int32_t *) (*Tile_calmLava + Tile_id_property_offset)) { + new_auxiliary = *(int32_t *) (*Tile_water + Tile_id_property_offset); + } + if (new_auxiliary != 0) { + // Valid + bool success = false; + if (item_instance->count == 1) { + item_instance->auxiliary = new_auxiliary; + success = true; + } else { + ItemInstance new_item; + new_item.id = *(int32_t *) (bucket + Item_id_property_offset); + new_item.count = 1; + new_item.auxiliary = new_auxiliary; + unsigned char *inventory = *(unsigned char **) (player + Player_inventory_property_offset); + unsigned char *inventory_vtable = *(unsigned char **) inventory; + FillingContainer_add_t FillingContainer_add = *(FillingContainer_add_t *) (inventory_vtable + FillingContainer_add_vtable_offset); + if ((*FillingContainer_add)(inventory, &new_item)) { + // Added To Inventory + success = true; + item_instance->count -= 1; + } + } + if (success) { + (*Level_setTileAndData)(level, x, y, z, 0, 0); + return 1; + } else { + return 0; + } + } else { + // Invalid + return 0; + } + } else { + // Place + switch (hit_side) { + case 0: { + y -= 1; + break; + } + case 1: { + y += 1; + break; + } + case 2: { + z -= 1; + break; + } + case 3: { + z += 1; + break; + } + case 4: { + x -= 1; + break; + } + case 5: { + x += 1; + break; + } + } + // Get Current Tile + bool valid = false; + unsigned char *material = (*Level_getMaterial)(level, x, y, z); + if (material != NULL) { + unsigned char *material_vtable = *(unsigned char **) material; + Material_isSolid_t Material_isSolid = *(Material_isSolid_t *) (material_vtable + Material_isSolid_vtable_offset); + valid = !(*Material_isSolid)(material); + } + if (valid) { + (*Level_setTileAndData)(level, x, y, z, item_instance->auxiliary, 0); + item_instance->auxiliary = 0; + return 1; + } else { + return 0; + } + } +} + +// Bucket VTable +static unsigned char *get_bucket_vtable() { + static unsigned char *vtable = NULL; + if (vtable == NULL) { + // Init + vtable = (unsigned char *) malloc(ITEM_VTABLE_SIZE); + ALLOC_CHECK(vtable); + // Copy Old VTable + memcpy((void *) vtable, (void *) Item_vtable, ITEM_VTABLE_SIZE); + + // Modify + *(Item_getDescriptionId_t *) (vtable + Item_getDescriptionId_vtable_offset) = BucketItem_getDescriptionId; + *(Item_getIcon_t *) (vtable + Item_getIcon_vtable_offset) = BucketItem_getIcon; + *(Item_useOn_t *) (vtable + Item_useOn_vtable_offset) = BucketItem_useOn; + } + return vtable; +} +__attribute__((destructor)) static void free_bucket_vtable() { + free(get_bucket_vtable()); +} + +// Create Items +static unsigned char *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, const char *name) { + // Construct + unsigned char *item = (unsigned char *) ::operator new(ITEM_SIZE); + ALLOC_CHECK(item); + (*Item)(item, id); + + // Set VTable + *(unsigned char **) item = get_bucket_vtable(); + + // Get Functions + unsigned char *vtable = *(unsigned char **) item; + Item_setIcon_t Item_setIcon = *(Item_setIcon_t *) (vtable + Item_setIcon_vtable_offset); + Item_setDescriptionId_t Item_setDescriptionId = *(Item_setDescriptionId_t *) (vtable + Item_setDescriptionId_vtable_offset); + + // Setup + (*Item_setIcon)(item, texture_x, texture_y); + (*Item_setDescriptionId)(item, name); + *(int32_t *) (item + Item_is_stacked_by_data_property_offset) = 1; + *(int32_t *) (item + Item_category_property_offset) = 2; + *(int32_t *) (item + Item_max_damage_property_offset) = 0; + *(int32_t *) (item + Item_max_stack_size_property_offset) = 1; + + // Return + return item; +} +static void Item_initItems_injection(__attribute__((unused)) unsigned char *null) { + bucket = create_bucket(69, 10, 4, "bucket"); +} + +// Change Max Stack Size Based On Auxiliary +static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instance) { + if (item_instance->id == *(int32_t *) (bucket + Item_id_property_offset) && item_instance->auxiliary == 0) { + // Custom Value + return 16; + } else { + // Call Original Method + return (*ItemInstance_getMaxStackSize)(item_instance); + } +} + +// Creative Inventory +static void inventory_add_item(unsigned char *inventory, unsigned char *item, int32_t auxiliary) { + ItemInstance *item_instance = new ItemInstance; + ALLOC_CHECK(item_instance); + item_instance = (*ItemInstance_constructor_item_extra)(item_instance, item, 1, auxiliary); + (*FillingContainer_addItem)(inventory, item_instance); +} +static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) { + inventory_add_item(filling_container, bucket, 0); + inventory_add_item(filling_container, bucket, *(int32_t *) (*Tile_water + Tile_id_property_offset)); + inventory_add_item(filling_container, bucket, *(int32_t *) (*Tile_lava + Tile_id_property_offset)); +} + +// Make Liquids Selectable +static bool is_holding_bucket = false; +static void Mob_pick_Level_clip_injection(unsigned char *level, unsigned char *param_1, unsigned char *param_2, bool param_3, __attribute__((unused)) bool clip_liquids) { + // Call Original Method + (*Level_clip)(level, param_1, param_2, param_3, is_holding_bucket); +} +static void handle_tick(unsigned char *minecraft) { + unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset); + if (player != NULL) { + // Get Selected Slot + int32_t selected_slot = misc_get_real_selected_slot(player); + unsigned char *inventory = *(unsigned char **) (player + Player_inventory_property_offset); + + // Prepare + unsigned char *inventory_vtable = *(unsigned char **) inventory; + FillingContainer_getItem_t FillingContainer_getItem = *(FillingContainer_getItem_t *) (inventory_vtable + FillingContainer_getItem_vtable_offset); + + // Get Item + ItemInstance *inventory_item = (*FillingContainer_getItem)(inventory, selected_slot); + // Check + is_holding_bucket = inventory_item != NULL && inventory_item->id == (*(int32_t *) (bucket + Item_id_property_offset)) && inventory_item->auxiliary == 0; + } +} + +// Prevent Breaking Liquid +static bool is_calm_liquid(int32_t id) { + if (id == *(int32_t *) (*Tile_calmWater + Tile_id_property_offset)) { + return true; + } else if (id == *(int32_t *) (*Tile_calmLava + Tile_id_property_offset)) { + return true; + } else { + return false; + } +} +static void Minecraft_handleMouseDown_injection(unsigned char *minecraft, int param_1, bool can_destroy) { + // Check + unsigned char *level = *(unsigned char **) (minecraft + Minecraft_level_property_offset); + if (level != NULL) { + int32_t x = *(int32_t *) (minecraft + Minecraft_targeted_x_property_offset); + int32_t y = *(int32_t *) (minecraft + Minecraft_targeted_y_property_offset); + int32_t z = *(int32_t *) (minecraft + Minecraft_targeted_z_property_offset); + int32_t tile = (*Level_getTile)(level, x, y, z); + if (is_calm_liquid(tile)) { + can_destroy = false; + } + } + + // Call Original Method + (*Minecraft_handleMouseDown)(minecraft, param_1, can_destroy); +} + +// Custom Crafting Recipes +static void Recipes_injection(unsigned char *recipes) { + // Add + Recipes_Type type1 = { + .item = 0, + .tile = 0, + .instance = { + .count = 3, + .id = 265, + .auxiliary = 0 + }, + .letter = '#' + }; + ItemInstance result = { + .count = 1, + .id = (*(int32_t *) (bucket + Item_id_property_offset)), + .auxiliary = 0 + }; + (*Recipes_addShapedRecipe_2)(recipes, result, "# #", " # ", {type1}); +} + +// Custom Furnace Fuel +static int32_t FurnaceTileEntity_getBurnDuration_injection(ItemInstance const& item_instance) { + if (item_instance.count > 0 && item_instance.id == (*(int32_t *) (bucket + Item_id_property_offset)) && item_instance.auxiliary == (*(int32_t *) (*Tile_lava + Tile_id_property_offset))) { + return 20000; + } else { + // Call Original Method + return (*FurnaceTileEntity_getBurnDuration)(item_instance); + } +} +static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *item_instance) { + // Replace Lava Bucket With Empty Bucket When It Burns Out + if (item_instance->id == (*(int32_t *) (bucket + Item_id_property_offset))) { + item_instance->auxiliary = 0; + } else { + // Original Behavior + item_instance->count = 0; + item_instance->id = 0; + item_instance->auxiliary = 0; + } +} + +// Init +void init_bucket() { + // Add Buckets + if (feature_has("Add Buckets", server_enabled)) { + // Add Items + misc_run_on_items_setup(Item_initItems_injection); + // Change Max Stack Size Based On Auxiliary + overwrite_calls((void *) ItemInstance_getMaxStackSize, (void *) ItemInstance_getMaxStackSize_injection); + // Creative Inventory + misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection); + // Make Liquids Selectable + overwrite_call((void *) 0x7f5b0, (void *) Mob_pick_Level_clip_injection); + misc_run_on_tick(handle_tick); + // Prevent Breaking Liquid + overwrite_calls((void *) Minecraft_handleMouseDown, (void *) Minecraft_handleMouseDown_injection); + // Custom Crafting Recipes + misc_run_on_recipes_setup(Recipes_injection); + // Custom Furnace Fuel + overwrite_calls((void *) FurnaceTileEntity_getBurnDuration, (void *) FurnaceTileEntity_getBurnDuration_injection); + overwrite_call((void *) 0xd351c, (void *) FurnaceTileEntity_tick_ItemInstance_setNull_injection); + } +} diff --git a/mods/src/creative/creative.cpp b/mods/src/creative/creative.cpp index 53e8e1b1f..30a6df065 100644 --- a/mods/src/creative/creative.cpp +++ b/mods/src/creative/creative.cpp @@ -16,10 +16,7 @@ static void inventory_add_item(unsigned char *inventory, unsigned char *item, bo } // Expand Creative Inventory -static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, ItemInstance *item_instance) { - // Call Original Method - int32_t ret = (*FillingContainer_addItem)(filling_container, item_instance); - +static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) { // Add Items inventory_add_item(filling_container, *Item_flintAndSteel, false); inventory_add_item(filling_container, *Item_snowball, false); @@ -79,8 +76,6 @@ static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(un new_item_instance = (*ItemInstance_constructor_tile_extra)(new_item_instance, *Tile_stoneSlab, 1, 6); (*FillingContainer_addItem)(filling_container, new_item_instance); } - - return ret; } #endif @@ -111,7 +106,7 @@ void init_creative() { // Add Extra Items To Creative Inventory (Only Replace Specific Function Call) if (feature_has("Expand Creative Inventory", server_enabled)) { #ifndef MCPI_SERVER_MODE - overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection); + misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection); #endif // Use AuxDataTileItem by default instead of TileItem, so tiles in the Creative diff --git a/mods/src/init/init.c b/mods/src/init/init.c index 64772ff8d..129030bc0 100644 --- a/mods/src/init/init.c +++ b/mods/src/init/init.c @@ -27,6 +27,7 @@ __attribute__((constructor)) static void init() { init_death(); init_options(); init_chat(); + init_bucket(); init_home(); #ifndef MCPI_SERVER_MODE init_benchmark(); diff --git a/mods/src/input/drop.cpp b/mods/src/input/drop.cpp index 939299be8..7038cbefd 100644 --- a/mods/src/input/drop.cpp +++ b/mods/src/input/drop.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // Enable Item Dropping static int enable_drop = 0; @@ -29,8 +30,8 @@ static void _handle_drop(unsigned char *minecraft) { unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset); if (player != NULL) { // Get Selected Slot + int32_t selected_slot = misc_get_real_selected_slot(player); unsigned char *inventory = *(unsigned char **) (player + Player_inventory_property_offset); - int32_t selected_slot = *(int32_t *) (inventory + Inventory_selectedSlot_property_offset); // Prepare unsigned char *player_vtable = *(unsigned char **) player; @@ -38,13 +39,6 @@ static void _handle_drop(unsigned char *minecraft) { unsigned char *inventory_vtable = *(unsigned char **) inventory; FillingContainer_getItem_t FillingContainer_getItem = *(FillingContainer_getItem_t *) (inventory_vtable + FillingContainer_getItem_vtable_offset); - // Linked Slots - int32_t linked_slots_length = *(int32_t *) (inventory + FillingContainer_linked_slots_length_property_offset); - if (selected_slot < linked_slots_length) { - int32_t *linked_slots = *(int32_t **) (inventory + FillingContainer_linked_slots_property_offset); - selected_slot = linked_slots[selected_slot]; - } - // Get Item ItemInstance *inventory_item = (*FillingContainer_getItem)(inventory, selected_slot); // Check diff --git a/mods/src/misc/api.cpp b/mods/src/misc/api.cpp index 7ab075758..bc2e88a8b 100644 --- a/mods/src/misc/api.cpp +++ b/mods/src/misc/api.cpp @@ -6,88 +6,103 @@ #include #include "misc-internal.h" +// Callbacks +#define SETUP_CALLBACK(name) \ + static std::vector &get_misc_##name##_functions() { \ + static std::vector functions; \ + return functions; \ + } \ + static void handle_misc_##name(unsigned char *obj) { \ + for (misc_update_function_t function : get_misc_##name##_functions()) { \ + (*function)(obj); \ + } \ + } \ + void misc_run_on_##name(misc_update_function_t function) { \ + get_misc_##name##_functions().push_back(function); \ + } + // Run Functions On Update -static std::vector &get_misc_update_functions() { - static std::vector functions; - return functions; -} -void misc_run_on_update(misc_update_function_t function) { - get_misc_update_functions().push_back(function); -} +SETUP_CALLBACK(update); // Handle Custom Update Behavior static void Minecraft_update_injection(unsigned char *minecraft) { // Call Original Method (*Minecraft_update)(minecraft); // Run Functions - for (misc_update_function_t function : get_misc_update_functions()) { - (*function)(minecraft); - } + handle_misc_update(minecraft); } // Run Functions On Tick -static std::vector &get_misc_tick_functions() { - static std::vector functions; - return functions; -} -void misc_run_on_tick(misc_update_function_t function) { - get_misc_tick_functions().push_back(function); -} +SETUP_CALLBACK(tick); // Handle Custom Tick Behavior static void Minecraft_tick_injection(unsigned char *minecraft, int32_t param_1, int32_t param_2) { // Call Original Method (*Minecraft_tick)(minecraft, param_1, param_2); // Run Functions - for (misc_update_function_t function : get_misc_tick_functions()) { - (*function)(minecraft); - } + handle_misc_tick(minecraft); } // Run Functions On Recipes Setup -static std::vector &get_misc_recipes_setup_functions() { - static std::vector functions; - return functions; -} -void misc_run_on_recipes_setup(misc_update_function_t function) { - get_misc_recipes_setup_functions().push_back(function); -} +SETUP_CALLBACK(recipes_setup); // Handle Custom Recipes Setup Behavior static unsigned char *Recipes_injection(unsigned char *recipes) { // Call Original Method (*Recipes)(recipes); // Run Functions - for (misc_update_function_t function : get_misc_recipes_setup_functions()) { - (*function)(recipes); - } + handle_misc_recipes_setup(recipes); // Return return recipes; } // Run Functions On Furnace Recipes Setup -static std::vector &get_misc_furnace_recipes_setup_functions() { - static std::vector functions; - return functions; -} -void misc_run_on_furnace_recipes_setup(misc_update_function_t function) { - get_misc_furnace_recipes_setup_functions().push_back(function); -} +SETUP_CALLBACK(furnace_recipes_setup); // Handle Custom Furnace Recipes Setup Behavior static unsigned char *FurnaceRecipes_injection(unsigned char *recipes) { // Call Original Method (*FurnaceRecipes)(recipes); // Run Functions - for (misc_update_function_t function : get_misc_furnace_recipes_setup_functions()) { - (*function)(recipes); - } + handle_misc_furnace_recipes_setup(recipes); // Return return recipes; } +// Run Functions On Creative Inventory Setup +SETUP_CALLBACK(creative_inventory_setup); +// Handle Custom Creative Inventory Setup Behavior +static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container, ItemInstance *item_instance) { + // Call Original Method + (*FillingContainer_addItem)(filling_container, item_instance); + // Run Functions + handle_misc_creative_inventory_setup(filling_container); +} + +// Run Functions On Tiles Setup +SETUP_CALLBACK(tiles_setup); +// Handle Custom Tiles Setup Behavior +static void Tile_initTiles_injection() { + // Run Functions + handle_misc_tiles_setup(NULL); + + // Call Original Method + (*Tile_initTiles)(); +} + +// Run Functions On Items Setup +SETUP_CALLBACK(items_setup); +// Handle Custom Items Setup Behavior +static void Item_initItems_injection() { + // Run Functions + handle_misc_items_setup(NULL); + + // Call Original Method + (*Item_initItems)(); +} + // Init void _init_misc_api() { // Handle Custom Update Behavior @@ -97,4 +112,9 @@ void _init_misc_api() { // Handle Custom Recipe Setup Behavior overwrite_calls((void *) Recipes, (void *) Recipes_injection); overwrite_calls((void *) FurnaceRecipes, (void *) 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((void *) Tile_initTiles, (void *) Tile_initTiles_injection); + overwrite_calls((void *) Item_initItems, (void *) Item_initItems_injection); } diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c index f706229d7..44d24cd59 100644 --- a/mods/src/misc/misc.c +++ b/mods/src/misc/misc.c @@ -204,6 +204,23 @@ static void GameRenderer_render_injection(unsigned char *game_renderer, float pa } } +// Get Real Selected Slot +int32_t misc_get_real_selected_slot(unsigned char *player) { + // Get Selected Slot + unsigned char *inventory = *(unsigned char **) (player + Player_inventory_property_offset); + int32_t selected_slot = *(int32_t *) (inventory + Inventory_selectedSlot_property_offset); + + // Linked Slots + int32_t linked_slots_length = *(int32_t *) (inventory + FillingContainer_linked_slots_length_property_offset); + if (selected_slot < linked_slots_length) { + int32_t *linked_slots = *(int32_t **) (inventory + FillingContainer_linked_slots_property_offset); + selected_slot = linked_slots[selected_slot]; + } + + // Return + return selected_slot; +} + // Init static void nop() { } diff --git a/mods/src/sound/sound.cpp b/mods/src/sound/sound.cpp index a593afd2e..82450a9ff 100644 --- a/mods/src/sound/sound.cpp +++ b/mods/src/sound/sound.cpp @@ -113,9 +113,9 @@ static void SoundEngine_init_injection(unsigned char *sound_engine, unsigned cha void init_sound() { // Implement Sound Engine if (feature_has("Implement Sound Engine", server_disabled)) { - overwrite_calls((void *) SoundEngine_playUI, (void *) SoundEngine_playUI_injection); - overwrite_calls((void *) SoundEngine_play, (void *) SoundEngine_play_injection); - overwrite_calls((void *) SoundEngine_update, (void *) SoundEngine_update_injection); + overwrite((void *) SoundEngine_playUI, (void *) SoundEngine_playUI_injection); + overwrite((void *) SoundEngine_play, (void *) SoundEngine_play_injection); + overwrite((void *) SoundEngine_update, (void *) SoundEngine_update_injection); overwrite_calls((void *) SoundEngine_init, (void *) SoundEngine_init_injection); } } diff --git a/symbols/include/symbols/minecraft.h b/symbols/include/symbols/minecraft.h index cc460cda9..8d40ed101 100644 --- a/symbols/include/symbols/minecraft.h +++ b/symbols/include/symbols/minecraft.h @@ -184,6 +184,9 @@ static Minecraft_getCreator_t Minecraft_getCreator = (Minecraft_getCreator_t) 0x typedef unsigned char *(*Minecraft_getLevelSource_t)(unsigned char *minecraft); static Minecraft_getLevelSource_t Minecraft_getLevelSource = (Minecraft_getLevelSource_t) 0x16e84; +typedef void (*Minecraft_handleMouseDown_t)(unsigned char *minecraft, int param_1, bool can_destroy); +static Minecraft_handleMouseDown_t Minecraft_handleMouseDown = (Minecraft_handleMouseDown_t) 0x1584c; + static uint32_t Minecraft_screen_width_property_offset = 0x20; // int32_t static uint32_t Minecraft_network_handler_property_offset = 0x174; // NetEventCallback * static uint32_t Minecraft_rak_net_instance_property_offset = 0x170; // RakNetInstance * @@ -199,6 +202,9 @@ static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen * static uint32_t Minecraft_gui_property_offset = 0x198; // Gui static uint32_t Minecraft_pov_property_offset = 0x150; // Mob * static uint32_t Minecraft_perf_renderer_property_offset = 0xcbc; // PerfRenderer * +static uint32_t Minecraft_targeted_x_property_offset = 0xc3c; // int32_t +static uint32_t Minecraft_targeted_y_property_offset = 0xc40; // int32_t +static uint32_t Minecraft_targeted_z_property_offset = 0xc44; // int32_t // GameRenderer @@ -291,25 +297,6 @@ typedef int32_t (*MouseBuildInput_tickBuild_t)(unsigned char *mouse_build_input, static MouseBuildInput_tickBuild_t MouseBuildInput_tickBuild = (MouseBuildInput_tickBuild_t) 0x17c98; static void *MouseBuildInput_tickBuild_vtable_addr = (void *) 0x102564; -// Item - -static uint32_t Item_is_stacked_by_data_property_offset = 0x19; // unsigned char / bool -static uint32_t Item_category_property_offset = 0x10; // int32_t -static uint32_t Item_max_damage_property_offset = 0x8; // int32_t - -// TileItem - -typedef unsigned char *(*TileItem_t)(unsigned char *tile_item, int32_t id); -static TileItem_t TileItem = (TileItem_t) 0xce3a4; - -// AuxDataTileItem - -#define AUX_DATA_TILE_ITEM_SIZE 0x2c - -static unsigned char *AuxDataTileItem_vtable = (unsigned char *) 0x114a58; - -static uint32_t AuxDataTileItem_icon_tile_property_offset = 0x28; // Tile * - // ItemInstance typedef struct { @@ -326,6 +313,50 @@ typedef ItemInstance *(*ItemInstance_constructor_extra_t)(ItemInstance *item_ins static ItemInstance_constructor_extra_t ItemInstance_constructor_tile_extra = (ItemInstance_constructor_extra_t) 0x99918; static ItemInstance_constructor_extra_t ItemInstance_constructor_item_extra = (ItemInstance_constructor_extra_t) 0x99960; +typedef int32_t (*ItemInstance_getMaxStackSize_t)(ItemInstance *item_instance); +static ItemInstance_getMaxStackSize_t ItemInstance_getMaxStackSize = (ItemInstance_getMaxStackSize_t) 0x99ac8; + +// Item + +#define ITEM_SIZE 0x24 +#define ITEM_VTABLE_SIZE 0x98 + +static unsigned char *Item_vtable = (unsigned char *) 0x10f128; + +typedef void (*Item_initItems_t)(); +static Item_initItems_t Item_initItems = (Item_initItems_t) 0x94ed0; + +typedef unsigned char *(*Item_t)(unsigned char *item, int32_t id); +static Item_t Item = (Item_t) 0x99488; + +typedef void (*Item_setIcon_t)(unsigned char *item, int32_t texture_x, int32_t texture_y); +static uint32_t Item_setIcon_vtable_offset = 0x18; + +typedef int32_t (*Item_getIcon_t)(unsigned char *item, int32_t auxiliary); +static uint32_t Item_getIcon_vtable_offset = 0x14; + +typedef int32_t (*Item_useOn_t)(unsigned char *item, ItemInstance *item_instance, unsigned char *player, unsigned char *level, int32_t x, int32_t y, int32_t z, int32_t hit_side, float hit_x, float hit_y, float hit_z); +static uint32_t Item_useOn_vtable_offset = 0x20; + +static uint32_t Item_id_property_offset = 0x4; // int32_t +static uint32_t Item_is_stacked_by_data_property_offset = 0x19; // unsigned char / bool +static uint32_t Item_category_property_offset = 0x10; // int32_t +static uint32_t Item_max_damage_property_offset = 0x8; // int32_t +static uint32_t Item_max_stack_size_property_offset = 0x14; // int32_t + +// TileItem + +typedef unsigned char *(*TileItem_t)(unsigned char *tile_item, int32_t id); +static TileItem_t TileItem = (TileItem_t) 0xce3a4; + +// AuxDataTileItem + +#define AUX_DATA_TILE_ITEM_SIZE 0x2c + +static unsigned char *AuxDataTileItem_vtable = (unsigned char *) 0x114a58; + +static uint32_t AuxDataTileItem_icon_tile_property_offset = 0x28; // Tile * + // Entity static uint32_t Entity_x_property_offset = 0x4; // float @@ -426,8 +457,22 @@ static Level_saveLevelData_t Level_saveLevelData = (Level_saveLevelData_t) 0xa2e typedef void (*Level_setTileAndData_t)(unsigned char *level, int32_t x, int32_t y, int32_t z, int32_t id, int32_t data); static Level_setTileAndData_t Level_setTileAndData = (Level_setTileAndData_t) 0xa38b4; +typedef int32_t (*Level_getTile_t)(unsigned char *level, int32_t x, int32_t y, int32_t z); +static Level_getTile_t Level_getTile = (Level_getTile_t) 0xa3380; + +typedef unsigned char *(*Level_getMaterial_t)(unsigned char *level, int32_t x, int32_t y, int32_t z); +static Level_getMaterial_t Level_getMaterial = (Level_getMaterial_t) 0xa27f8; + +typedef void (*Level_clip_t)(unsigned char *level, unsigned char *param_1, unsigned char *param_2, bool param_3, bool clip_liquids); +static Level_clip_t Level_clip = (Level_clip_t) 0xa3db0; + static uint32_t Level_players_property_offset = 0x60; // std::vector +// Material + +typedef bool (*Material_isSolid_t)(unsigned char *material); +static uint32_t Material_isSolid_vtable_offset = 0x8; + // LevelRenderer typedef void (*LevelRenderer_render_t)(unsigned char *level_renderer, unsigned char *mob, int param_1, float delta); @@ -557,7 +602,7 @@ static uint32_t Touch_SelectWorldScreen_world_created_property_offset = 0x151; / // FillingContainer -typedef int32_t (*FillingContainer_addItem_t)(unsigned char *filling_container, ItemInstance *item_instance); +typedef void (*FillingContainer_addItem_t)(unsigned char *filling_container, ItemInstance *item_instance); static FillingContainer_addItem_t FillingContainer_addItem = (FillingContainer_addItem_t) 0x92aa0; typedef ItemInstance *(*FillingContainer_getItem_t)(unsigned char *filling_container, int32_t slot); @@ -566,6 +611,9 @@ static uint32_t FillingContainer_getItem_vtable_offset = 0x8; typedef void (*FillingContainer_setItem_t)(unsigned char *filling_container, int32_t slot, ItemInstance *item_instance); static uint32_t FillingContainer_setItem_vtable_offset = 0xc; +typedef bool (*FillingContainer_add_t)(unsigned char *filling_container, ItemInstance *item_instance); +static uint32_t FillingContainer_add_vtable_offset = 0x30; + typedef void (*FillingContainer_clearSlot_t)(unsigned char *filling_container, int32_t slot); static FillingContainer_clearSlot_t FillingContainer_clearSlot = (FillingContainer_clearSlot_t) 0x922f8; @@ -766,6 +814,14 @@ struct ConnectedClient { typedef unsigned char *(*Tile_setDescriptionId_t)(unsigned char *tile, std::string const& description_id); static uint32_t Tile_setDescriptionId_vtable_offset = 0xe0; +// Item + +typedef void (*Item_setDescriptionId_t)(unsigned char *item, std::string const& name); +static uint32_t Item_setDescriptionId_vtable_offset = 0x6c; + +typedef std::string (*Item_getDescriptionId_t)(unsigned char *item, const ItemInstance *item_instance); +static uint32_t Item_getDescriptionId_vtable_offset = 0x7c; + // AppPlatform typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& path, int32_t width, int32_t height); @@ -870,14 +926,28 @@ static Textures_loadAndBindTexture_t Textures_loadAndBindTexture = (Textures_loa // Recipes -typedef void (*Recipes_addShapelessRecipe_t)(unsigned char *recipes, ItemInstance const& result, std::vector const& param_2); +typedef void (*Recipes_addShapelessRecipe_t)(unsigned char *recipes, ItemInstance const& result, std::vector const& ingredients); static Recipes_addShapelessRecipe_t Recipes_addShapelessRecipe = (Recipes_addShapelessRecipe_t) 0x9c3dc; +typedef void (*Recipes_addShapedRecipe_1_t)(unsigned char *recipes, ItemInstance const& result, std::string const& line_1, std::vector const& ingredients); +static Recipes_addShapedRecipe_1_t Recipes_addShapedRecipe_1 = (Recipes_addShapedRecipe_1_t) 0x9ca74; + +typedef void (*Recipes_addShapedRecipe_2_t)(unsigned char *recipes, ItemInstance const& result, std::string const& line_1, std::string const& line_2, std::vector const& ingredients); +static Recipes_addShapedRecipe_2_t Recipes_addShapedRecipe_2 = (Recipes_addShapedRecipe_2_t) 0x9ca24; + +typedef void (*Recipes_addShapedRecipe_3_t)(unsigned char *recipes, ItemInstance const& result, std::string const& line_1, std::string const& line_2, std::string const& line_3, std::vector const& ingredients); +static Recipes_addShapedRecipe_3_t Recipes_addShapedRecipe_3 = (Recipes_addShapedRecipe_3_t) 0x9c9d0; + // FurnaceRecipes typedef void (*FurnaceRecipes_addFurnaceRecipe_t)(unsigned char *recipes, int32_t input_item_id, ItemInstance const& result); static FurnaceRecipes_addFurnaceRecipe_t FurnaceRecipes_addFurnaceRecipe = (FurnaceRecipes_addFurnaceRecipe_t) 0xa0714; +// FurnaceTileEntity + +typedef int32_t (*FurnaceTileEntity_getBurnDuration_t)(ItemInstance const& item_instance); +static FurnaceTileEntity_getBurnDuration_t FurnaceTileEntity_getBurnDuration = (FurnaceTileEntity_getBurnDuration_t) 0xd33f8; + #endif #pragma GCC diagnostic pop