From f78a4e47aced1c9c4703fc2edad262f2cbdd999a Mon Sep 17 00:00:00 2001 From: Bigjango13 Date: Sat, 27 Jan 2024 16:00:44 -0500 Subject: [PATCH] Add buckets of milk - Milk Buckets can be obtained by using an empty bucket on a cow - They can be drunk, but they don't heal you - Adds the `misc_run_on_language_setup` function - Changes `misc_run_on_tile_setup` and `misc_run_on_item_setup` to run after the original function is called - Fix used items transferring durability - Add more symbols --- dependencies/symbol-processor/src | 2 +- mods/include/mods/misc/misc.h | 1 + mods/src/bucket/bucket.cpp | 127 +++++++++++++----- mods/src/misc/api.cpp | 26 +++- mods/src/misc/misc.c | 17 +++ symbols/CMakeLists.txt | 7 +- symbols/src/entity/Entity.def | 1 + symbols/src/entity/{ => animal}/AgableMob.def | 0 symbols/src/entity/{ => animal}/Animal.def | 0 symbols/src/entity/animal/Cow.def | 3 + symbols/src/entity/player/Player.def | 12 +- symbols/src/item/FoodItem.def | 7 + symbols/src/item/Item.def | 12 +- symbols/src/misc/I18n.def | 3 + .../src/network/raknet/RakNet_BitStream.def | 11 ++ 15 files changed, 186 insertions(+), 43 deletions(-) rename symbols/src/entity/{ => animal}/AgableMob.def (100%) rename symbols/src/entity/{ => animal}/Animal.def (100%) create mode 100644 symbols/src/entity/animal/Cow.def create mode 100644 symbols/src/item/FoodItem.def create mode 100644 symbols/src/misc/I18n.def diff --git a/dependencies/symbol-processor/src b/dependencies/symbol-processor/src index 0b696bd..ea31be1 160000 --- a/dependencies/symbol-processor/src +++ b/dependencies/symbol-processor/src @@ -1 +1 @@ -Subproject commit 0b696bd55b31416929d0a29d84ad50ab5ba0ceae +Subproject commit ea31be1cb2b43decb9c906215f80ff20efd2b479 diff --git a/mods/include/mods/misc/misc.h b/mods/include/mods/misc/misc.h index 291384b..6fe20c1 100644 --- a/mods/include/mods/misc/misc.h +++ b/mods/include/mods/misc/misc.h @@ -22,6 +22,7 @@ void misc_run_on_creative_inventory_setup(misc_update_function_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 void Level_saveLevelData_injection(Level *level); diff --git a/mods/src/bucket/bucket.cpp b/mods/src/bucket/bucket.cpp index 1645bad..0c0cf33 100644 --- a/mods/src/bucket/bucket.cpp +++ b/mods/src/bucket/bucket.cpp @@ -6,31 +6,57 @@ #include // Items -Item *bucket = NULL; +FoodItem *bucket = NULL; // Description And Texture -static std::string BucketItem_getDescriptionId(__attribute__((unused)) Item *item, ItemInstance *item_instance) { +static std::string BucketItem_getDescriptionId(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance) { if (item_instance->auxiliary == Tile_water->id) { return "item.bucketWater"; } else if (item_instance->auxiliary == Tile_lava->id) { return "item.bucketLava"; + } else if (item_instance->auxiliary == 1) { + return "item.bucketMilk"; } else { return "item.bucket"; } } -static int32_t BucketItem_getIcon(__attribute__((unused)) Item *item, int32_t auxiliary) { +static int32_t BucketItem_getIcon(__attribute__((unused)) FoodItem *item, int32_t auxiliary) { if (auxiliary == Tile_water->id) { return 75; } else if (auxiliary == Tile_lava->id) { return 76; + } else if (auxiliary == 1) { + return 77; } else { return 74; } } +// Filling +static bool fill_bucket(ItemInstance *item_instance, Player *player, int new_auxiliary) { + bool success = false; + if (item_instance->count == 1) { + item_instance->auxiliary = new_auxiliary; + success = true; + } else { + ItemInstance new_item; + new_item.id = bucket->id; + new_item.count = 1; + new_item.auxiliary = new_auxiliary; + Inventory *inventory = player->inventory; + if (inventory->vtable->add(inventory, &new_item)) { + // Added To Inventory + success = true; + item_instance->count -= 1; + } + } + return success; +} + + // Use Bucket -static int32_t BucketItem_useOn(__attribute__((unused)) Item *item, ItemInstance *item_instance, Player *player, Level *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) { +static int32_t BucketItem_useOn(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance, Player *player, Level *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 || item_instance->auxiliary == 1) { return 0; } else if (item_instance->auxiliary == 0) { // Empty Bucket @@ -43,23 +69,7 @@ static int32_t BucketItem_useOn(__attribute__((unused)) Item *item, ItemInstance } 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 = bucket->id; - new_item.count = 1; - new_item.auxiliary = new_auxiliary; - Inventory *inventory = player->inventory; - if (inventory->vtable->add(inventory, &new_item)) { - // Added To Inventory - success = true; - item_instance->count -= 1; - } - } - if (success) { + if (fill_bucket(item_instance, player, new_auxiliary)) { Level_setTileAndData(level, x, y, z, 0, 0); return 1; } else { @@ -116,28 +126,64 @@ static int32_t BucketItem_useOn(__attribute__((unused)) Item *item, ItemInstance } } +static int BucketItem_getUseDuration(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance) { + if (item_instance->auxiliary == 1) { + return 0x20; + } + return 0; +} + +static void BucketItem_useTimeDepleted(FoodItem *item, uchar *param_1, ItemInstance *item_instance, Level *level, Player *player) { + if (item_instance->auxiliary == 1) { + (*FoodItem_useTimeDepleted_vtable_addr)(item, param_1, item_instance, level, player); + // Set it to a empty bucket + item_instance->auxiliary = 0; + item_instance->count = 1; + } +} + +static int BucketItem_getUseAnimation(__attribute__((unused)) FoodItem *item) { + return 2; +} + +static bool BucketItem_isFood(__attribute__((unused)) FoodItem *item) { + return true; +} + +static ItemInstance *BucketItem_use(FoodItem *item, ItemInstance *item_instance, __attribute__((unused)) Level *level, Player *player) { + if (item_instance->auxiliary == 1) { + return (*FoodItem_use_vtable_addr)(item, item_instance, level, player); + } + return item_instance; +} + // Bucket VTable -static Item_vtable *get_bucket_vtable() { - static Item_vtable *vtable = NULL; +static FoodItem_vtable *get_bucket_vtable() { + static FoodItem_vtable *vtable = NULL; if (vtable == NULL) { // Init - vtable = dup_Item_vtable(Item_vtable_base); + vtable = dup_FoodItem_vtable(FoodItem_vtable_base); ALLOC_CHECK(vtable); // Modify vtable->getDescriptionId = BucketItem_getDescriptionId; vtable->getIcon = BucketItem_getIcon; vtable->useOn = BucketItem_useOn; + vtable->getUseDuration = BucketItem_getUseDuration; + vtable->useTimeDepleted = BucketItem_useTimeDepleted; + vtable->getUseAnimation = BucketItem_getUseAnimation; + vtable->isFood = BucketItem_isFood; + vtable->use = BucketItem_use; } return vtable; } // Create Items -static Item *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) { +static FoodItem *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) { // Construct - Item *item = alloc_Item(); + FoodItem *item = alloc_FoodItem(); ALLOC_CHECK(item); - Item_constructor(item, id); + Item_constructor((Item *) item, id); // Set VTable item->vtable = get_bucket_vtable(); @@ -149,6 +195,7 @@ static Item *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std item->category = 2; item->max_damage = 0; item->max_stack_size = 1; + item->nutrition = 0; // Return return item; @@ -168,17 +215,29 @@ static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instanc } } +// Milking +bool Cow_interact_injection(Cow *self, Player *player) { + ItemInstance *item = Inventory_getSelected(player->inventory); + if (item && item->id == bucket->id && item->auxiliary == 0) { + // Fill with milk + fill_bucket(item, player, 1); + return true; + } + return Cow_interact_non_virtual(self, player); +} + // Creative Inventory -static void inventory_add_item(FillingContainer *inventory, Item *item, int32_t auxiliary) { +static void inventory_add_item(FillingContainer *inventory, FoodItem *item, int32_t auxiliary) { ItemInstance *item_instance = new ItemInstance; ALLOC_CHECK(item_instance); - item_instance = ItemInstance_constructor_item_extra(item_instance, item, 1, auxiliary); + item_instance = ItemInstance_constructor_item_extra(item_instance, (Item *) item, 1, auxiliary); FillingContainer_addItem(inventory, item_instance); } static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) { inventory_add_item(filling_container, bucket, 0); inventory_add_item(filling_container, bucket, Tile_water->id); inventory_add_item(filling_container, bucket, Tile_lava->id); + inventory_add_item(filling_container, bucket, 1); } // Make Liquids Selectable @@ -273,6 +332,10 @@ static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance * } } +static void Language_injection(__attribute__((unused)) void *null) { + I18n__strings.insert(std::make_pair("item.bucketMilk.name", "Milk Bucket")); +} + // Init void init_bucket() { // Add Buckets @@ -281,6 +344,8 @@ void init_bucket() { misc_run_on_items_setup(Item_initItems_injection); // Change Max Stack Size Based On Auxiliary overwrite_calls((void *) ItemInstance_getMaxStackSize, (void *) ItemInstance_getMaxStackSize_injection); + // Enable milking + patch_address((void *) Cow_interact_vtable_addr, (void *) Cow_interact_injection); // Creative Inventory misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection); // Make Liquids Selectable @@ -293,5 +358,7 @@ void init_bucket() { // Custom Furnace Fuel overwrite_calls((void *) FurnaceTileEntity_getBurnDuration, (void *) FurnaceTileEntity_getBurnDuration_injection); overwrite_call((void *) 0xd351c, (void *) FurnaceTileEntity_tick_ItemInstance_setNull_injection); + // Language for milk + misc_run_on_language_setup(Language_injection); } } diff --git a/mods/src/misc/api.cpp b/mods/src/misc/api.cpp index d8ec95a..6e5a7b7 100644 --- a/mods/src/misc/api.cpp +++ b/mods/src/misc/api.cpp @@ -77,6 +77,7 @@ SETUP_CALLBACK(creative_inventory_setup, FillingContainer); static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container, ItemInstance *item_instance) { // Call Original Method FillingContainer_addItem(filling_container, item_instance); + // Run Functions handle_misc_creative_inventory_setup(filling_container); } @@ -85,22 +86,33 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli SETUP_CALLBACK(tiles_setup, void); // Handle Custom Tiles Setup Behavior static void Tile_initTiles_injection() { - // Run Functions - handle_misc_tiles_setup(NULL); - // Call Original Method Tile_initTiles(); + + // Run Functions + handle_misc_tiles_setup(NULL); } // Run Functions On Items Setup SETUP_CALLBACK(items_setup, void); // Handle Custom Items Setup Behavior static void Item_initItems_injection() { - // Run Functions - handle_misc_items_setup(NULL); - // Call Original Method Item_initItems(); + + // Run Functions + handle_misc_items_setup(NULL); +} + +// Run Functions On Language Setup +SETUP_CALLBACK(language_setup, void); +// Handle Custom Items Setup Behavior +static void I18n_loadLanguage_injection(AppPlatform *app, std::string language_name) { + // Call Original Method + I18n_loadLanguage(app, language_name); + + // Run Functions + handle_misc_language_setup(NULL); } // Init @@ -117,4 +129,6 @@ void _init_misc_api() { // Handle Custom Item/Tile Init Behavior overwrite_calls((void *) Tile_initTiles, (void *) Tile_initTiles_injection); overwrite_calls((void *) Item_initItems, (void *) Item_initItems_injection); + // Handle Custom Language Entries + overwrite_calls((void *) I18n_loadLanguage, (void *) I18n_loadLanguage_injection); } diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c index 0063997..9bf5ff9 100644 --- a/mods/src/misc/misc.c +++ b/mods/src/misc/misc.c @@ -545,6 +545,19 @@ static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity *furnace return ret; } +// Fix used items transferring durability +static int selected_slot = -1; +static void Player_startUsingItem_injection(Player *self, ItemInstance *item_instance, int time) { + selected_slot = self->inventory->selectedSlot; + Player_startUsingItem(self, item_instance, time); +} +static void Player_stopUsingItem_injection(Player *self) { + if (selected_slot != self->inventory->selectedSlot) { + self->itemBeingUsed.id = 0; + } + Player_stopUsingItem(self); +} + // Init static void nop() { } @@ -731,6 +744,10 @@ void init_misc() { unsigned char mov_r3_ff[4] = {0xff, 0x30, 0xa0, 0xe3}; // "mov r3, #0xff" patch((void *) 0x7178c, mov_r3_ff); + // Fix used items transferring durability + overwrite_calls((void *) Player_startUsingItem, (void *) Player_startUsingItem_injection); + overwrite_calls((void *) Player_stopUsingItem, (void *) Player_stopUsingItem_injection); + // Init C++ And Logging _init_misc_cpp(); _init_misc_logging(); diff --git a/symbols/CMakeLists.txt b/symbols/CMakeLists.txt index 75341d0..7715ed9 100644 --- a/symbols/CMakeLists.txt +++ b/symbols/CMakeLists.txt @@ -40,8 +40,9 @@ set(SRC src/entity/MobFactory.def src/entity/EntityRenderDispatcher.def src/entity/MobRenderer.def - src/entity/AgableMob.def - src/entity/Animal.def + src/entity/animal/AgableMob.def + src/entity/animal/Animal.def + src/entity/animal/Cow.def src/entity/Mob.def src/entity/player/ServerPlayer.def src/entity/player/Player.def @@ -82,6 +83,7 @@ set(SRC src/item/ArmorMaterial.def src/item/ArmorItem.def src/item/TileItem.def + src/item/FoodItem.def src/api/OffsetPosTranslator.def src/api/CommandServer.def src/api/ConnectedClient.def @@ -125,6 +127,7 @@ set(SRC src/tile/GrassTile.def src/tile/HeavyTile.def src/misc/Strings.def + src/misc/I18n.def src/entity/ModelPart.def src/misc/Tesselator.def src/misc/AABB.def diff --git a/symbols/src/entity/Entity.def b/symbols/src/entity/Entity.def index 096752e..3c57c4b 100644 --- a/symbols/src/entity/Entity.def +++ b/symbols/src/entity/Entity.def @@ -1,5 +1,6 @@ virtual-method void remove() = 0x10; virtual-method void tick() = 0x34; +virtual-method bool interact(Player *with) = 0x6c; virtual-method bool hurt(Entity *attacker, int damage) = 0xa4; virtual-method int getEntityTypeId() = 0xdc; diff --git a/symbols/src/entity/AgableMob.def b/symbols/src/entity/animal/AgableMob.def similarity index 100% rename from symbols/src/entity/AgableMob.def rename to symbols/src/entity/animal/AgableMob.def diff --git a/symbols/src/entity/Animal.def b/symbols/src/entity/animal/Animal.def similarity index 100% rename from symbols/src/entity/Animal.def rename to symbols/src/entity/animal/Animal.def diff --git a/symbols/src/entity/animal/Cow.def b/symbols/src/entity/animal/Cow.def new file mode 100644 index 0000000..f18dd75 --- /dev/null +++ b/symbols/src/entity/animal/Cow.def @@ -0,0 +1,3 @@ +extends Animal; + +vtable 0x10ba38; diff --git a/symbols/src/entity/player/Player.def b/symbols/src/entity/player/Player.def index 87cc8a4..a63a002 100644 --- a/symbols/src/entity/player/Player.def +++ b/symbols/src/entity/player/Player.def @@ -2,12 +2,18 @@ extends Mob; vtable 0x10de70; -method int isUsingItem() = 0x8f15c; virtual-method void drop(ItemInstance *item_instance, bool is_death) = 0x208; virtual-method void stopSleepInBed(bool param_1, bool param_2, bool param_3) = 0x228; virtual-method void openTextEdit(TileEntity *sign) = 0x230; -method ItemInstance *getArmor(int slot) = 0x8fda4; -property std::string username = 0xbf4; +method int isUsingItem() = 0x8f15c; +method void stopUsingItem() = 0x8f514; +method void startUsingItem(ItemInstance *item_instance, int use_duration) = 0x8f4b8; +method ItemInstance *getArmor(int slot) = 0x8fda4; +method bool isHurt() = 0x8fb44; + property Inventory *inventory = 0xbe0; +property std::string username = 0xbf4; +property bool immortal = 0xbfc; property bool infinite_items = 0xbff; +property ItemInstance itemBeingUsed = 0xc34; diff --git a/symbols/src/item/FoodItem.def b/symbols/src/item/FoodItem.def new file mode 100644 index 0000000..5c1c159 --- /dev/null +++ b/symbols/src/item/FoodItem.def @@ -0,0 +1,7 @@ +extends Item; + +size 0x30; +vtable 0x10e7b0; +vtable-size 0x98; + +property int nutrition = 0x24; diff --git a/symbols/src/item/Item.def b/symbols/src/item/Item.def index 6c70872..c1e72e4 100644 --- a/symbols/src/item/Item.def +++ b/symbols/src/item/Item.def @@ -6,12 +6,22 @@ vtable 0x10f128; size 0x24; constructor (int id) = 0x99488; -virtual-method void setIcon(int texture_x, int texture_y) = 0x18; virtual-method int getIcon(int auxiliary) = 0x14; +virtual-method void setIcon(int texture_x, int texture_y) = 0x18; virtual-method int useOn(ItemInstance *item_instance, Player *player, Level *level, int x, int y, int z, int hit_side, float hit_x, float hit_y, float hit_z) = 0x20; +// Normally returns 0 +virtual-method int getUseDuration(ItemInstance *item_instance) = 0x24; +// I don't know much about param_1, it might be some partially initialized ItemInstance* +virtual-method void useTimeDepleted(uchar *param_1, ItemInstance *item_instance, Level *level, Player *player) = 0x28; +virtual-method int getDestorySpeed(ItemInstance *item_instance, Tile *tile) = 0x2c; virtual-method ItemInstance *use(ItemInstance *item_instance, Level *level, Player *player) = 0x30; +virtual-method bool mineBlock(ItemInstance *instance, int tile_id, int x, int y, int z) = 0x48; +virtual-method bool isFood() = 0x64; +virtual-method bool isArmor() = 0x68; virtual-method void setDescriptionId(std::string *name) = 0x6c; virtual-method std::string getDescriptionId(ItemInstance *item_instance) = 0x7c; +// Swing = 0, eating = 1, drinking = 2, bow = 4, anything else is nothing +virtual-method int getUseAnimation() = 0x94; property int id = 0x4; property int max_damage = 0x8; diff --git a/symbols/src/misc/I18n.def b/symbols/src/misc/I18n.def new file mode 100644 index 0000000..e35e2bb --- /dev/null +++ b/symbols/src/misc/I18n.def @@ -0,0 +1,3 @@ +static-method void loadLanguage(AppPlatform *app, std::string language_name) = 0x680d0; + +static-property std::map _strings = 0x137d98; diff --git a/symbols/src/network/raknet/RakNet_BitStream.def b/symbols/src/network/raknet/RakNet_BitStream.def index 570c3be..586e4d1 100644 --- a/symbols/src/network/raknet/RakNet_BitStream.def +++ b/symbols/src/network/raknet/RakNet_BitStream.def @@ -1,4 +1,15 @@ method void Write_uchar(uchar *i) = 0x18448; method void Write_int(int *i) = 0x18454; +method void Write_ushort(ushort *i) = 0x45a68; +method void Write_short(short *i) = 0x71918; +// right_aligned should be true +method void WriteBits(uchar *buff, uint bits, bool right_aligned) = 0xd41b4; +method void Read_uchar(uchar *i) = 0x45ab0; method void Read_int(int *i) = 0x184ec; +method void Read_ushort(ushort *i) = 0x45acc; +method void Read_short(short *i) = 0x72070; +// right_aligned should be true +method void ReadBits(uchar *buff, uint bits, bool right_aligned) = 0xd3e18; + +property uint readOffset = 0x8;