minecraft-pi-reborn/mods/src/bucket/bucket.cpp

289 lines
9.4 KiB
C++
Raw Normal View History

2022-07-10 14:37:19 +00:00
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/feature/feature.h>
#include <mods/init/init.h>
#include <mods/misc/misc.h>
// Items
2024-01-27 22:47:43 +00:00
static Item *bucket = NULL;
2022-07-10 14:37:19 +00:00
// Description And Texture
2024-01-06 11:30:23 +00:00
static std::string BucketItem_getDescriptionId(__attribute__((unused)) Item *item, ItemInstance *item_instance) {
2024-01-07 07:59:04 +00:00
if (item_instance->auxiliary == Tile_water->id) {
2022-07-10 14:37:19 +00:00
return "item.bucketWater";
2024-01-07 07:59:04 +00:00
} else if (item_instance->auxiliary == Tile_lava->id) {
2022-07-10 14:37:19 +00:00
return "item.bucketLava";
} else {
return "item.bucket";
}
}
2024-01-06 11:30:23 +00:00
static int32_t BucketItem_getIcon(__attribute__((unused)) Item *item, int32_t auxiliary) {
2024-01-07 07:59:04 +00:00
if (auxiliary == Tile_water->id) {
2022-07-10 14:37:19 +00:00
return 75;
2024-01-07 07:59:04 +00:00
} else if (auxiliary == Tile_lava->id) {
2022-07-10 14:37:19 +00:00
return 76;
} else {
return 74;
}
}
// Use Bucket
2024-01-06 11:30:23 +00:00
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) {
2022-07-10 14:37:19 +00:00
if (item_instance->count < 1) {
return 0;
2022-08-09 22:38:48 +00:00
} else if (item_instance->auxiliary == 0) {
2022-07-10 14:37:19 +00:00
// Empty Bucket
int32_t new_auxiliary = 0;
2024-01-06 11:30:23 +00:00
int32_t tile = level->vtable->getTile(level, x, y, z);
2024-01-07 07:59:04 +00:00
if (tile == Tile_calmWater->id) {
new_auxiliary = Tile_water->id;
} else if (tile == Tile_calmLava->id) {
new_auxiliary = Tile_lava->id;
2022-07-10 14:37:19 +00:00
}
if (new_auxiliary != 0) {
// Valid
bool success = false;
if (item_instance->count == 1) {
item_instance->auxiliary = new_auxiliary;
success = true;
} else {
ItemInstance new_item;
2024-01-06 11:30:23 +00:00
new_item.id = bucket->id;
2022-07-10 14:37:19 +00:00
new_item.count = 1;
new_item.auxiliary = new_auxiliary;
2024-01-06 11:30:23 +00:00
Inventory *inventory = player->inventory;
if (inventory->vtable->add(inventory, &new_item)) {
2022-07-10 14:37:19 +00:00
// Added To Inventory
success = true;
item_instance->count -= 1;
}
}
if (success) {
2024-01-07 08:23:43 +00:00
Level_setTileAndData(level, x, y, z, 0, 0);
2022-07-10 14:37:19 +00:00
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;
2024-01-06 11:30:23 +00:00
Material *material = level->vtable->getMaterial(level, x, y, z);
2022-07-10 14:37:19 +00:00
if (material != NULL) {
2024-01-06 11:30:23 +00:00
valid = !material->vtable->isSolid(material);
2022-07-10 14:37:19 +00:00
}
2024-01-07 07:59:04 +00:00
if (item_instance->auxiliary != Tile_water->id && item_instance->auxiliary != Tile_lava->id) {
2022-07-30 02:13:03 +00:00
valid = false;
}
2022-07-10 14:37:19 +00:00
if (valid) {
2024-01-07 08:23:43 +00:00
Level_setTileAndData(level, x, y, z, item_instance->auxiliary, 0);
2022-07-10 14:37:19 +00:00
item_instance->auxiliary = 0;
return 1;
} else {
return 0;
}
}
}
// Bucket VTable
2024-02-01 03:13:20 +00:00
CUSTOM_VTABLE(bucket, Item) {
vtable->getDescriptionId = BucketItem_getDescriptionId;
vtable->getIcon = BucketItem_getIcon;
vtable->useOn = BucketItem_useOn;
2022-07-10 14:37:19 +00:00
}
// Create Items
2024-01-06 11:30:23 +00:00
static Item *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) {
2022-07-10 14:37:19 +00:00
// Construct
2024-01-06 11:30:23 +00:00
Item *item = alloc_Item();
2022-07-10 14:37:19 +00:00
ALLOC_CHECK(item);
2024-01-07 08:23:43 +00:00
Item_constructor(item, id);
2022-07-10 14:37:19 +00:00
// Set VTable
2024-01-06 11:30:23 +00:00
item->vtable = get_bucket_vtable();
2022-07-10 14:37:19 +00:00
// Setup
2024-01-06 11:30:23 +00:00
item->vtable->setIcon(item, texture_x, texture_y);
item->vtable->setDescriptionId(item, &name);
item->is_stacked_by_data = 1;
item->category = 2;
item->max_damage = 0;
item->max_stack_size = 1;
2022-07-10 14:37:19 +00:00
// Return
return item;
}
2024-01-06 11:30:23 +00:00
static void Item_initItems_injection(__attribute__((unused)) void *null) {
2022-07-10 14:37:19 +00:00
bucket = create_bucket(69, 10, 4, "bucket");
}
// Change Max Stack Size Based On Auxiliary
static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instance) {
2024-01-06 11:30:23 +00:00
if (item_instance->id == bucket->id && item_instance->auxiliary == 0) {
2022-07-10 14:37:19 +00:00
// Custom Value
return 16;
} else {
// Call Original Method
2024-01-07 08:23:43 +00:00
return ItemInstance_getMaxStackSize(item_instance);
2022-07-10 14:37:19 +00:00
}
}
// Creative Inventory
2024-01-06 11:30:23 +00:00
static void inventory_add_item(FillingContainer *inventory, Item *item, int32_t auxiliary) {
2022-07-10 14:37:19 +00:00
ItemInstance *item_instance = new ItemInstance;
ALLOC_CHECK(item_instance);
2024-01-07 08:23:43 +00:00
item_instance = ItemInstance_constructor_item_extra(item_instance, item, 1, auxiliary);
FillingContainer_addItem(inventory, item_instance);
2022-07-10 14:37:19 +00:00
}
2024-01-06 11:30:23 +00:00
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
2022-07-10 14:37:19 +00:00
inventory_add_item(filling_container, bucket, 0);
2024-01-07 07:59:04 +00:00
inventory_add_item(filling_container, bucket, Tile_water->id);
inventory_add_item(filling_container, bucket, Tile_lava->id);
2022-07-10 14:37:19 +00:00
}
// Make Liquids Selectable
static bool is_holding_bucket = false;
2024-01-06 11:30:23 +00:00
static HitResult Mob_pick_Level_clip_injection(Level *level, unsigned char *param_1, unsigned char *param_2, __attribute__((unused)) bool clip_liquids, bool param_3) {
2022-07-10 14:37:19 +00:00
// Call Original Method
2024-01-07 08:23:43 +00:00
return Level_clip(level, param_1, param_2, is_holding_bucket, param_3);
2022-07-10 14:37:19 +00:00
}
2024-01-06 11:30:23 +00:00
static void handle_tick(Minecraft *minecraft) {
LocalPlayer *player = minecraft->player;
2022-07-10 14:37:19 +00:00
if (player != NULL) {
// Get Selected Slot
2024-01-06 11:30:23 +00:00
int32_t selected_slot = misc_get_real_selected_slot((Player *) player);
Inventory *inventory = player->inventory;
2022-07-10 14:37:19 +00:00
// Get Item
2024-01-06 11:30:23 +00:00
ItemInstance *inventory_item = inventory->vtable->getItem(inventory, selected_slot);
2022-07-10 14:37:19 +00:00
// Check
2024-01-06 11:30:23 +00:00
is_holding_bucket = inventory_item != NULL && inventory_item->id == bucket->id && inventory_item->auxiliary == 0;
2022-07-10 14:37:19 +00:00
}
}
// Prevent Breaking Liquid
static bool is_calm_liquid(int32_t id) {
2024-01-07 07:59:04 +00:00
if (id == Tile_calmWater->id) {
2022-07-10 14:37:19 +00:00
return true;
2024-01-07 07:59:04 +00:00
} else if (id == Tile_calmLava->id) {
2022-07-10 14:37:19 +00:00
return true;
} else {
return false;
}
}
2024-01-06 11:30:23 +00:00
static void Minecraft_handleMouseDown_injection(Minecraft *minecraft, int param_1, bool can_destroy) {
2022-07-10 14:37:19 +00:00
// Check
2024-01-06 11:30:23 +00:00
Level *level = minecraft->level;
2022-07-10 14:37:19 +00:00
if (level != NULL) {
2024-01-06 11:30:23 +00:00
int32_t x = minecraft->hit_result.x;
int32_t y = minecraft->hit_result.y;
int32_t z = minecraft->hit_result.z;
int32_t tile = level->vtable->getTile(level, x, y, z);
2022-07-10 14:37:19 +00:00
if (is_calm_liquid(tile)) {
can_destroy = false;
}
}
// Call Original Method
2024-01-07 08:23:43 +00:00
Minecraft_handleMouseDown(minecraft, param_1, can_destroy);
2022-07-10 14:37:19 +00:00
}
// Custom Crafting Recipes
2024-01-06 11:30:23 +00:00
static void Recipes_injection(Recipes *recipes) {
2022-07-10 14:37:19 +00:00
// Add
Recipes_Type type1 = {
.item = 0,
.tile = 0,
.instance = {
.count = 3,
.id = 265,
.auxiliary = 0
},
.letter = '#'
};
ItemInstance result = {
.count = 1,
2024-01-06 11:30:23 +00:00
.id = bucket->id,
2022-07-10 14:37:19 +00:00
.auxiliary = 0
};
2024-01-06 11:30:23 +00:00
std::string line1 = "# #";
std::string line2 = " # ";
std::vector<Recipes_Type> types = {type1};
2024-01-07 08:23:43 +00:00
Recipes_addShapedRecipe_2(recipes, &result, &line1, &line2, &types);
2022-07-10 14:37:19 +00:00
}
// Custom Furnace Fuel
2024-01-06 11:30:23 +00:00
static int32_t FurnaceTileEntity_getBurnDuration_injection(ItemInstance *item_instance) {
2024-01-07 07:59:04 +00:00
if (item_instance->count > 0 && item_instance->id == bucket->id && item_instance->auxiliary == Tile_lava->id) {
2022-07-10 14:37:19 +00:00
return 20000;
} else {
// Call Original Method
2024-01-07 08:23:43 +00:00
return FurnaceTileEntity_getBurnDuration(item_instance);
2022-07-10 14:37:19 +00:00
}
}
static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *item_instance) {
// Replace Lava Bucket With Empty Bucket When It Burns Out
2024-01-06 11:30:23 +00:00
if (item_instance->id == bucket->id) {
2022-07-10 14:37:19 +00:00
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);
}
}