Add Cake #81
@ -1,10 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
**3.0.0**
|
||||
* Add ``Add Cake`` Feature Flag (Enabled By Default)
|
||||
* Add Milk Buckets
|
||||
* Implement Crafting Remainders
|
||||
* Add Death Messages
|
||||
|
||||
**2.5.3**
|
||||
* Add `Replace Block Highlight With Outline` Feature Flag (Enabled By Default)
|
||||
bigjango13 marked this conversation as resolved
Outdated
|
||||
* By Default, The Outline Width Is Set Using The GUI Scale
|
||||
* This Can Be Overridden Using The `MCPI_BLOCK_OUTLINE_WIDTH` Environmental Variable
|
||||
* Added `overwrite_calls_within` Function
|
||||
* By Default, The Outline Width Is Set Using The GUI Scale
|
||||
* This Can Be Overridden Using The ``MCPI_BLOCK_OUTLINE_WIDTH`` Environmental Variable
|
||||
* Added ``overwrite_calls_within`` Function
|
||||
|
||||
**2.5.2**
|
||||
* Add `3D Chest Model` Feature Flag (Enabled By Default)
|
||||
|
@ -51,6 +51,7 @@ TRUE Disable Hostile AI In Creative Mode
|
||||
TRUE Load Custom Skins
|
||||
TRUE 3D Chest Model
|
||||
TRUE Replace Block Highlight With Outline
|
||||
TRUE Add Cake
|
||||
TRUE Use Java Beta 1.3 Light Ramp
|
||||
TRUE Send Full Level When Hosting Game
|
||||
FALSE Food Overlay
|
||||
|
@ -35,6 +35,8 @@ set(SRC
|
||||
src/options/options.cpp
|
||||
# bucket
|
||||
src/bucket/bucket.cpp
|
||||
# cake
|
||||
src/cake/cake.cpp
|
||||
# home
|
||||
src/home/home.c
|
||||
# test
|
||||
|
3
mods/include/mods/bucket/bucket.h
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
Please add a Also, instead of a fancy method containing a
just seems a bit over-complicated. Please add a `#pragma once`.
Also, instead of a fancy method containing a `static bool`, why not just use an `extern bool buckets_enabled`, or just have `buckets_enabled()` check a variable.
```c++
bool buckets_enabled() {
static bool ret = feature_has("Add Buckets", server_enabled);
return ret;
}
```
just seems a bit over-complicated.
|
||||
|
||||
extern bool buckets_enabled;
|
@ -33,6 +33,7 @@ void init_death();
|
||||
void init_options();
|
||||
void init_chat();
|
||||
void init_bucket();
|
||||
void init_cake();
|
||||
void init_home();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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
|
||||
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
|
||||
|
||||
|
@ -6,31 +6,57 @@
|
||||
#include <mods/misc/misc.h>
|
||||
|
||||
// Items
|
||||
static Item *bucket = NULL;
|
||||
static FoodItem *bucket = NULL;
|
||||
TheBrokenRail
commented
Do we really care about MCPE compatibility that much? IMO, the code might be nicer if the milk bucket was just a separate item. What are your thoughts? Do we really care about MCPE compatibility that much? IMO, the code might be nicer if the milk bucket was just a separate item. What are your thoughts?
bigjango13
commented
What MCPE compatibility? As far as I know, each type of bucket has it's own id (326 water bucket, 327 lava bucket, and 335 milk bucket). While it might be a little bit nicer without all the aux value checks, it would also be a lot more verbose (even with just splitting off milk buckets), and I think that the current systems is a bit harder to understand the first time, but once it's understood it's a lot easier to read/work with than splitting it off. (It also takes up 1-3 less item ids, but that's a pretty minor bonus.) What MCPE compatibility? As far as I know, each type of bucket has it's own id (326 water bucket, 327 lava bucket, and 335 milk bucket). While it might be a little bit nicer without all the aux value checks, it would also be a lot more verbose (even with just splitting off milk buckets), and I think that the current systems is a bit harder to understand the first time, but once it's understood it's a lot easier to read/work with than splitting it off. (It also takes up 1-3 less item ids, but that's a pretty minor bonus.)
|
||||
|
||||
// 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,19 +126,68 @@ 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 ItemInstance BucketItem_useTimeDepleted(FoodItem *item, ItemInstance *item_instance, Level *level, Player *player) {
|
||||
if (item_instance->auxiliary == 1) {
|
||||
*item_instance = FoodItem_useTimeDepleted_non_virtual(item, item_instance, level, player);
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
Use Use `FoodItem_useTimeDepleted_non_virtual` rather than de-referencing the address yourself.
|
||||
// Set it to a empty bucket
|
||||
item_instance->auxiliary = 0;
|
||||
item_instance->count = 1;
|
||||
}
|
||||
return *item_instance;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static ItemInstance *BucketItem_getCraftingRemainingItem(FoodItem *item, ItemInstance *item_instance) {
|
||||
if (item_instance->auxiliary == 0) {
|
||||
return NULL;
|
||||
}
|
||||
ItemInstance *ret = alloc_ItemInstance();
|
||||
ret->id = item->id;
|
||||
ret->count = item_instance->count;
|
||||
ret->auxiliary = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Bucket VTable
|
||||
CUSTOM_VTABLE(bucket, Item) {
|
||||
CUSTOM_VTABLE(bucket, FoodItem) {
|
||||
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;
|
||||
vtable->getCraftingRemainingItem = BucketItem_getCraftingRemainingItem;
|
||||
}
|
||||
|
||||
// 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();
|
||||
@ -140,6 +199,9 @@ 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;
|
||||
item->unknown_param_1 = 0.6;
|
||||
item->meat = false;
|
||||
|
||||
// Return
|
||||
return item;
|
||||
@ -159,17 +221,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
|
||||
@ -264,14 +338,23 @@ static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *
|
||||
}
|
||||
}
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
This should probably have a comment before it. This should probably have a comment before it.
|
||||
|
||||
// Add the bucket name to the language file
|
||||
static void Language_injection(__attribute__((unused)) void *null) {
|
||||
I18n__strings.insert(std::make_pair("item.bucketMilk.name", "Milk Bucket"));
|
||||
}
|
||||
|
||||
// Init
|
||||
bool buckets_enabled = false;
|
||||
void init_bucket() {
|
||||
// Add Buckets
|
||||
if (feature_has("Add Buckets", server_enabled)) {
|
||||
buckets_enabled = feature_has("Add Buckets", server_enabled);
|
||||
if (buckets_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);
|
||||
// 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
|
||||
@ -284,5 +367,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);
|
||||
}
|
||||
}
|
||||
|
3
mods/src/cake/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# ``cake`` Mod
|
||||
|
||||
This mod adds cake.
|
243
mods/src/cake/cake.cpp
Normal file
@ -0,0 +1,243 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
#include <mods/feature/feature.h>
|
||||
#include <mods/init/init.h>
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/bucket/bucket.h>
|
||||
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
This should probably be This should probably be `static`.
|
||||
static Tile *cake = NULL;
|
||||
|
||||
#define CAKE_LEN 0.0625F
|
||||
|
||||
// Description
|
||||
static std::string Cake_getDescriptionId(__attribute__((unused)) Tile *tile) {
|
||||
return "tile.cake";
|
||||
}
|
||||
|
||||
// Textures
|
||||
static int Cake_getTexture2(__attribute__((unused)) Tile *tile, int face, __attribute__((unused)) int data) {
|
||||
if (face == 1) {
|
||||
// Top texture
|
||||
return 121;
|
||||
} else if (face == 0) {
|
||||
// Bottom texture
|
||||
return 124;
|
||||
}
|
||||
// Side texture
|
||||
return 122;
|
||||
}
|
||||
|
||||
static int Cake_getTexture3(__attribute__((unused)) Tile *tile, LevelSource *level, int x, int y, int z, int face) {
|
||||
// Eaten face
|
||||
if (face == 3) {
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data != 0 && data < 6) {
|
||||
// Sliced texture
|
||||
return 123;
|
||||
}
|
||||
}
|
||||
// Normal
|
||||
return Cake_getTexture2(tile, face, 0);
|
||||
}
|
||||
|
||||
// Rendering
|
||||
static bool Cake_isSolidRender(__attribute__((unused)) Tile *tile) {
|
||||
// Stop it from turning other blocks invisable
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Cake_getRenderLayer(__attribute__((unused)) Tile *tile) {
|
||||
// Stop weird transparency issues
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool Cake_isCubeShaped(__attribute__((unused)) Tile *tile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Size
|
||||
static void Cake_updateDefaultShape(Tile *tile) {
|
||||
// Set the default shape
|
||||
tile->vtable->setShape(
|
||||
tile,
|
||||
CAKE_LEN, 0.0, CAKE_LEN,
|
||||
1.0 - CAKE_LEN, 0.5, 1.0 - CAKE_LEN
|
||||
);
|
||||
}
|
||||
|
||||
static AABB *Cake_getAABB(Tile *tile, Level *level, int x, int y, int z) {
|
||||
// Get the size of the slices
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data >= 6) data = 0;
|
||||
float slice_size = (1.0 / 7.0) * (float) data;
|
||||
|
||||
// Corner 1
|
||||
AABB *aabb = &tile->aabb;
|
||||
aabb->x1 = (float) x + CAKE_LEN;
|
||||
aabb->y1 = (float) y;
|
||||
aabb->z1 = (float) z + CAKE_LEN;
|
||||
|
||||
// Corner 2
|
||||
aabb->x2 = (float) x + (1.0 - CAKE_LEN);
|
||||
aabb->y2 = (float) y + 0.5;
|
||||
aabb->z2 = (float) z + (1.0 - CAKE_LEN) - slice_size;
|
||||
|
||||
return aabb;
|
||||
}
|
||||
|
||||
static void Cake_updateShape(Tile *tile, LevelSource *level, int x, int y, int z) {
|
||||
// Set cake
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data >= 6) data = 0;
|
||||
// Get slice amount
|
||||
float slice_size = (1.0 / 7.0) * (float) data;
|
||||
tile->vtable->setShape(
|
||||
tile,
|
||||
CAKE_LEN, 0.0, CAKE_LEN,
|
||||
1.0 - CAKE_LEN, 0.5, (1.0 - CAKE_LEN) - slice_size
|
||||
);
|
||||
}
|
||||
|
||||
// Eating
|
||||
static int Cake_use(__attribute__((unused)) Tile *tile, Level *level, int x, int y, int z, Player *player) {
|
||||
// Eat
|
||||
SimpleFoodData_eat(&player->foodData, 3);
|
||||
// Set the new tile
|
||||
int data = level->vtable->getData(level, x, y, z);
|
||||
if (data >= 5) {
|
||||
// Remove the cake, it has been completely gobbled up
|
||||
Level_setTileAndData(level, x, y, z, 0, 0);
|
||||
} else {
|
||||
// Remove a slice
|
||||
Level_setTileAndData(level, x, y, z, 92, data + 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Makes the cakes
|
||||
static void make_cake() {
|
||||
// Construct
|
||||
cake = alloc_Tile();
|
||||
ALLOC_CHECK(cake);
|
||||
int texture = 122;
|
||||
Tile_constructor(cake, 92, texture, Material_dirt);
|
||||
cake->texture = texture;
|
||||
|
||||
// Set VTable
|
||||
cake->vtable = dup_Tile_vtable(Tile_vtable_base);
|
||||
ALLOC_CHECK(cake->vtable);
|
||||
|
||||
// Set shape
|
||||
cake->vtable->setShape(
|
||||
cake,
|
||||
CAKE_LEN, 0.0, CAKE_LEN,
|
||||
1.0 - CAKE_LEN, 0.5, 1.0 - CAKE_LEN
|
||||
);
|
||||
|
||||
// Modify functions
|
||||
cake->vtable->getDescriptionId = Cake_getDescriptionId;
|
||||
cake->vtable->getTexture3 = Cake_getTexture3;
|
||||
cake->vtable->getTexture2 = Cake_getTexture2;
|
||||
cake->vtable->isSolidRender = Cake_isSolidRender;
|
||||
cake->vtable->getRenderLayer = Cake_getRenderLayer;
|
||||
cake->vtable->isCubeShaped = Cake_isCubeShaped;
|
||||
cake->vtable->updateShape = Cake_updateShape;
|
||||
cake->vtable->updateDefaultShape = Cake_updateDefaultShape;
|
||||
cake->vtable->getAABB = Cake_getAABB;
|
||||
cake->vtable->use = Cake_use;
|
||||
|
||||
// Init
|
||||
Tile_init(cake);
|
||||
cake->vtable->setDestroyTime(cake, 1.0f);
|
||||
cake->vtable->setExplodeable(cake, 20.0f);
|
||||
cake->category = 4;
|
||||
std::string name = "Cake";
|
||||
cake->vtable->setDescriptionId(cake, &name);
|
||||
}
|
||||
|
||||
static void Tile_initTiles_injection(__attribute__((unused)) void *null) {
|
||||
make_cake();
|
||||
}
|
||||
|
||||
// Add cake to creative inventory
|
||||
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
|
||||
ItemInstance *cake_instance = new ItemInstance;
|
||||
ALLOC_CHECK(cake_instance);
|
||||
cake_instance->count = 255;
|
||||
cake_instance->auxiliary = 0;
|
||||
cake_instance->id = 92;
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
Remove the Remove the `(*` and `)`.
|
||||
FillingContainer_addItem(filling_container, cake_instance);
|
||||
}
|
||||
|
||||
// Recipe (only when buckets are enabled)
|
||||
static void Recipes_injection(Recipes *recipes) {
|
||||
// Sugar
|
||||
Recipes_Type sugar = {
|
||||
.item = 0,
|
||||
.tile = 0,
|
||||
.instance = {
|
||||
.count = 1,
|
||||
.id = 353,
|
||||
.auxiliary = 0
|
||||
},
|
||||
.letter = 's'
|
||||
};
|
||||
// Wheat
|
||||
Recipes_Type wheat = {
|
||||
.item = 0,
|
||||
.tile = 0,
|
||||
.instance = {
|
||||
.count = 1,
|
||||
.id = 296,
|
||||
.auxiliary = 0
|
||||
},
|
||||
.letter = 'w'
|
||||
};
|
||||
// Eggs
|
||||
Recipes_Type eggs = {
|
||||
.item = 0,
|
||||
.tile = 0,
|
||||
.instance = {
|
||||
.count = 1,
|
||||
.id = 344,
|
||||
.auxiliary = 0
|
||||
},
|
||||
.letter = 'e'
|
||||
};
|
||||
// Milk
|
||||
Recipes_Type milk = {
|
||||
.item = 0,
|
||||
.tile = 0,
|
||||
.instance = {
|
||||
.count = 1,
|
||||
.id = 325,
|
||||
.auxiliary = 1
|
||||
},
|
||||
.letter = 'm'
|
||||
};
|
||||
// Cake
|
||||
ItemInstance cake_item = {
|
||||
.count = 1,
|
||||
.id = 92,
|
||||
.auxiliary = 0
|
||||
};
|
||||
// Add
|
||||
std::string line1 = "mmm";
|
||||
std::string line2 = "ses";
|
||||
std::string line3 = "www";
|
||||
std::vector<Recipes_Type> ingredients = {milk, sugar, wheat, eggs};
|
||||
Recipes_addShapedRecipe_3(recipes, &cake_item, &line1, &line2, &line3, &ingredients);
|
||||
}
|
||||
|
||||
void init_cake() {
|
||||
// Add cakes
|
||||
if (feature_has("Add Cake", server_enabled)) {
|
||||
misc_run_on_tiles_setup(Tile_initTiles_injection);
|
||||
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
`feature_has` should ideally only run once per feature (to avoid redundant log entries). Maybe `bucket` could set a variable if it's enabled?
|
||||
if (buckets_enabled) {
|
||||
// The recipe needs milk buckets
|
||||
misc_run_on_recipes_setup(Recipes_injection);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,55 +7,136 @@
|
||||
#include <mods/feature/feature.h>
|
||||
|
||||
// Death Messages
|
||||
static std::string get_death_message(Player *player) {
|
||||
// Get Username
|
||||
std::string *username = &player->username;
|
||||
|
||||
static const char *monster_names[] = {"Zombie", "Creeper", "Skeleton", "Spider", "Zombie Pigman"};
|
||||
static std::string get_death_message(Player *player, Entity *cause, bool was_shot = false) {
|
||||
// Prepare Death Message
|
||||
std::string message;
|
||||
message.append(username->c_str());
|
||||
message.append(" has died");
|
||||
std::string message = player->username;
|
||||
if (cause) {
|
||||
// Entity cause
|
||||
int type_id = cause->vtable->getEntityTypeId(cause);
|
||||
int aux = cause->vtable->getAuxData(cause);
|
||||
bool is_player = cause->vtable->isPlayer(cause);
|
||||
if (cause->vtable->getCreatureBaseType(cause) != 0 || is_player) {
|
||||
// Killed by a creature
|
||||
if (was_shot) {
|
||||
message += " was shot by ";
|
||||
} else {
|
||||
message += " was killed by ";
|
||||
}
|
||||
if (is_player) {
|
||||
// Killed by a player
|
||||
message += ((Player *) cause)->username;
|
||||
} else if (32 <= type_id && type_id <= 36) {
|
||||
// Normal monster
|
||||
message += "a ";
|
||||
message += monster_names[type_id - 32];
|
||||
} else {
|
||||
// Unknown creature
|
||||
message += "a Mysterious Beast";
|
||||
}
|
||||
return message;
|
||||
} else if (aux) {
|
||||
// Killed by a throwable with owner
|
||||
Level *level = player->level;
|
||||
Entity *shooter = Level_getEntity(level, aux);
|
||||
return get_death_message(player, shooter, true);
|
||||
} else if (type_id == 65) {
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
Shouldn't this check if this was an arrow? What if another entity has aux data? Shouldn't this check if this was an arrow? What if another entity has aux data?
bigjango13
commented
That's intended, only throwables have aux values:
So if I egg you to death, it still says that I'm the one who did it. That's intended, only throwables have aux values:
```
// The owner entity id for arrows/throwables, else 0
virtual-method int getAuxData() = 0xf4;
```
So if I egg you to death, it still says that I'm the one who did it.
|
||||
// Blown up by TNT
|
||||
return message + " was blown apart";
|
||||
} else if (cause->vtable->isHangingEntity(cause)) {
|
||||
// Painting?
|
||||
return message + " admired too much art";
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
A lot of these death messages are duplicated. Is there any chance these could be consolidated into fewer if statements? A lot of these death messages are duplicated. Is there any chance these could be consolidated into fewer if statements?
bigjango13
commented
Done 👍 Done 👍
|
||||
}
|
||||
}
|
||||
|
||||
if (was_shot) {
|
||||
// Throwable with invalid owner
|
||||
return message + " was shot under mysterious circumstances";
|
||||
TheBrokenRail
commented
When would this ever happen? When would this ever happen?
bigjango13
commented
No idea, I thought it might be useful in case the paintings ever try to take over. No idea, I thought it might be useful in case the paintings ever try to take over.
|
||||
} else if (cause) {
|
||||
// Unknown entity
|
||||
return message + " was killed";
|
||||
} else {
|
||||
// Anything else
|
||||
return message + " has died";
|
||||
}
|
||||
|
||||
// Return
|
||||
return message;
|
||||
}
|
||||
|
||||
static bool is_hurt = false;
|
||||
static bool Mob_hurt_injection(Mob *mob, Entity *source, int dmg) {
|
||||
// Call Original Method
|
||||
is_hurt = true;
|
||||
bool ret = Mob_hurt_non_virtual(mob, source, dmg);
|
||||
is_hurt = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Death Message Logic
|
||||
#define Player_actuallyHurt_injection(type) \
|
||||
#define Player_death_injections(type) \
|
||||
static void type##Player_die_injection(type##Player *player, Entity *cause) { \
|
||||
/* Call Original Method */ \
|
||||
type##Player_die_non_virtual(player, cause); \
|
||||
\
|
||||
/* Get Variable */ \
|
||||
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
|
||||
/* Only Run On Server-Side */ \
|
||||
if (rak_net_instance->vtable->isServer(rak_net_instance)) { \
|
||||
/* Get Death Message */ \
|
||||
std::string message = get_death_message((Player *) player, cause); \
|
||||
\
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
IIRC when originally implementing death message, that hooking Did you test:
IIRC when originally implementing death message, that hooking `Player::die` caused some issues on servers.
Did you test:
- Host player dying (in LAN)
- Guest player dying (in LAN)
- Server killing player (`kill` console command)
bigjango13
commented
That's why I also hooked That's why I also hooked `actuallyHurt` as it did before. There are quite a few ways to die without calling `Player::die`, falling into the void is a notable one. If the player dies without calling `Player::die`, it will just post the usual "<username> has died". As for your question, yes, all of those have been tested.
|
||||
/* Post Death Message */ \
|
||||
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \
|
||||
ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &message); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static void type##Player_actuallyHurt_injection(type##Player *player, int32_t damage) { \
|
||||
/* Store Old Health */ \
|
||||
int32_t old_health = player->health; \
|
||||
\
|
||||
/* Call Original Method */ \
|
||||
type##Player_actuallyHurt_non_virtual(player, damage); \
|
||||
if (is_hurt == true) return; \
|
||||
\
|
||||
/* Store New Health */ \
|
||||
int32_t new_health = player->health; \
|
||||
\
|
||||
/* Get Variables */ \
|
||||
Minecraft *minecraft = player->minecraft; \
|
||||
RakNetInstance *rak_net_instance = minecraft->rak_net_instance; \
|
||||
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
|
||||
/* Only Run On Server-Side */ \
|
||||
if (rak_net_instance->vtable->isServer(rak_net_instance)) { \
|
||||
/* Check Health */ \
|
||||
if (new_health < 1 && old_health >= 1) { \
|
||||
/* Get Death Message */ \
|
||||
std::string message = get_death_message((Player *) player); \
|
||||
std::string message = get_death_message((Player *) player, NULL); \
|
||||
\
|
||||
/* Post Death Message */ \
|
||||
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) minecraft->network_handler; \
|
||||
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \
|
||||
ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &message); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
Player_actuallyHurt_injection(Local)
|
||||
Player_actuallyHurt_injection(Server)
|
||||
|
||||
Player_death_injections(Local);
|
||||
Player_death_injections(Server);
|
||||
|
||||
// Init
|
||||
void init_death() {
|
||||
// Death Messages
|
||||
if (feature_has("Implement Death Messages", server_auto)) {
|
||||
patch_address(ServerPlayer_die_vtable_addr, (void *) ServerPlayer_die_injection);
|
||||
patch_address(LocalPlayer_die_vtable_addr, (void *) LocalPlayer_die_injection);
|
||||
patch_address(ServerPlayer_actuallyHurt_vtable_addr, (void *) ServerPlayer_actuallyHurt_injection);
|
||||
patch_address(LocalPlayer_actuallyHurt_vtable_addr, (void *) LocalPlayer_actuallyHurt_injection);
|
||||
patch_address(Mob_hurt_vtable_addr, (void *) Mob_hurt_injection);
|
||||
overwrite_calls((void *) Mob_hurt_non_virtual, (void *) Mob_hurt_injection);
|
||||
}
|
||||
// Fix TNT
|
||||
// This changes PrimedTnt_explode from Level_explode(NULL, x, y, z, 3.1f) to Level_explode(this, x, y, z, 3.1f)
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
So, uh, what does these patches actually do? Does it set an entity ID somewhere? Because that should probably be in the comment. So, uh, what does these patches actually do? Does it set an entity ID somewhere? Because that should probably be in the comment.
|
||||
unsigned char cpy_r1_r0_patch[4] = {0x00, 0x10, 0xa0, 0xe1}; // "cpy r1,r0"
|
||||
patch((void *) 0x87998, cpy_r1_r0_patch);
|
||||
unsigned char ldr_r0_24_patch[4] = {0x24, 0x00, 0x90, 0xe5}; // "ldr r0,[r0,#0x24]"
|
||||
patch((void *) 0x8799c, ldr_r0_24_patch);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ __attribute__((constructor)) static void init(int argc, char *argv[]) {
|
||||
init_options();
|
||||
init_chat();
|
||||
init_bucket();
|
||||
init_cake();
|
||||
init_home();
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
init_benchmark(argc, argv);
|
||||
|
@ -5,3 +5,4 @@ This mod has several miscellaneous mods that are too small to be their own mod,
|
||||
* Removing the red background from unobtainable items in the inventory.
|
||||
* Loading the bundled language file.
|
||||
* Printing chat messages to the log.
|
||||
* Implementing crafting remainders.
|
||||
|
@ -79,6 +79,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);
|
||||
}
|
||||
@ -98,11 +99,22 @@ static void Tile_initTiles_injection() {
|
||||
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();
|
||||
|
||||
TheBrokenRail
commented
Why was the order of Why was the order of `Item_initItems_injection` changed?
bigjango13
commented
A few reasons:
A few reasons:
- It allows for mods to modify and overwrite existing items
- It allows for mods to tell if an item is already assigned to an id
- It doesn't really change anything beyond that (the same isn't true for tiles)
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Run Functions On GUI Key Press
|
||||
@ -140,6 +152,8 @@ 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);
|
||||
// Handle Key Presses
|
||||
overwrite_calls((void *) Gui_handleKeyPressed, (void *) Gui_handleKeyPressed_injection);
|
||||
}
|
||||
|
@ -601,6 +601,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);
|
||||
}
|
||||
|
||||
// Java Light Ramp
|
||||
static void Dimension_updateLightRamp_injection(Dimension *self) {
|
||||
// https://github.com/ReMinecraftPE/mcpe/blob/d7a8b6baecf8b3b050538abdbc976f690312aa2d/source/world/level/Dimension.cpp#L92-L105
|
||||
@ -816,6 +829,10 @@ void init_misc() {
|
||||
overwrite((void *) Dimension_updateLightRamp_non_virtual, (void *) Dimension_updateLightRamp_injection);
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
@ -58,6 +58,38 @@ static void PauseScreen_init_injection(PauseScreen *screen) {
|
||||
}
|
||||
}
|
||||
|
||||
// Implement crafting remainders
|
||||
void PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection(PaneCraftingScreen *self) {
|
||||
// Check for crafting remainders
|
||||
CItem *item = self->item;
|
||||
for (size_t i = 0; i < item->ingredients.size(); i++) {
|
||||
ItemInstance requested_item_instance = item->ingredients[i].requested_item;
|
||||
Item *requested_item = Item_items[requested_item_instance.id];
|
||||
ItemInstance *craftingRemainingItem = requested_item->vtable->getCraftingRemainingItem(requested_item, &requested_item_instance);
|
||||
if (craftingRemainingItem != NULL) {
|
||||
// Add or drop remainder
|
||||
LocalPlayer *player = self->minecraft->player;
|
||||
if (!player->inventory->vtable->add(player->inventory, craftingRemainingItem)) {
|
||||
// Drop
|
||||
player->vtable->drop(player, craftingRemainingItem, false);
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
How does this work if, for instance, the remaining item is 5 sticks and the player's inventory has space for 3 sticks? Do 3 sticks get added to the inventory and 2 dropped? How does this work if, for instance, the remaining item is 5 sticks and the player's inventory has space for 3 sticks? Do 3 sticks get added to the inventory and 2 dropped?
bigjango13
commented
Yep! Yep!
|
||||
}
|
||||
}
|
||||
}
|
||||
// Call Original Method
|
||||
PaneCraftingScreen_recheckRecipes(self);
|
||||
}
|
||||
|
||||
ItemInstance *Item_getCraftingRemainingItem_injection(Item *self, ItemInstance *item_instance) {
|
||||
if (self->craftingRemainingItem != NULL) {
|
||||
ItemInstance *ret = alloc_ItemInstance();
|
||||
ret->id = self->craftingRemainingItem->id;
|
||||
ret->count = item_instance->count;
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
This feels wrong? Was this added for a specific reason? This feels wrong? Was this added for a specific reason?
bigjango13
commented
Yes, in case anyone decides to use Yes, in case anyone decides to use `Item`'s `craftingRemainingItem` instead of overwriting it's `Item_getCraftingRemainingItem`. I mentioned it [here](https://discord.com/channels/740287937727561779/761048906242981948/1200982540501135401).
|
||||
ret->auxiliary = 0;
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Init
|
||||
void _init_misc_cpp() {
|
||||
// Implement AppPlatform::readAssetFile So Translations Work
|
||||
@ -70,4 +102,8 @@ void _init_misc_cpp() {
|
||||
// Add Missing Buttons To Pause Menu
|
||||
patch_address(PauseScreen_init_vtable_addr, (void *) PauseScreen_init_injection);
|
||||
}
|
||||
|
||||
// Implement crafting remainders
|
||||
overwrite_call((void *) 0x2e230, (void *) PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_injection);
|
||||
overwrite((void *) Item_getCraftingRemainingItem_non_virtual, (void *) Item_getCraftingRemainingItem_injection);
|
||||
}
|
||||
|
@ -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,10 +83,10 @@ set(SRC
|
||||
src/item/AuxDataTileItem.def
|
||||
src/item/ItemInstance.def
|
||||
src/item/Item.def
|
||||
src/item/FoodItem.def
|
||||
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
|
||||
@ -102,6 +103,7 @@ set(SRC
|
||||
src/gui/screens/StartMenuScreen.def
|
||||
src/gui/screens/ProgressScreen.def
|
||||
src/gui/screens/Touch_SelectWorldScreen.def
|
||||
src/gui/screens/PaneCraftingScreen.def
|
||||
src/gui/screens/ScreenChooser.def
|
||||
src/gui/Font.def
|
||||
src/gui/components/ImageButton.def
|
||||
@ -131,6 +133,8 @@ set(SRC
|
||||
src/tile/GrassTile.def
|
||||
src/tile/HeavyTile.def
|
||||
src/misc/Strings.def
|
||||
src/misc/I18n.def
|
||||
src/misc/SimpleFoodData.def
|
||||
src/entity/ModelPart.def
|
||||
src/misc/Tesselator.def
|
||||
src/misc/AABB.def
|
||||
@ -154,6 +158,8 @@ set(SRC
|
||||
src/recipes/FurnaceRecipes.def
|
||||
src/recipes/Recipes.def
|
||||
src/recipes/Recipes_Type.def
|
||||
src/recipes/ReqItem.def
|
||||
src/recipes/CItem.def
|
||||
)
|
||||
# Resolve Definition Files
|
||||
set(RESOLVED_SRC "")
|
||||
|
@ -1,7 +1,17 @@
|
||||
virtual-method void remove() = 0x10;
|
||||
virtual-method void tick() = 0x34;
|
||||
virtual-method bool interact(Player *with) = 0x6c;
|
||||
virtual-method bool isPlayer() = 0x94;
|
||||
virtual-method bool hurt(Entity *attacker, int damage) = 0xa4;
|
||||
// See https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Entity_List for these two
|
||||
virtual-method int getEntityTypeId() = 0xdc;
|
||||
virtual-method int getCreatureBaseType() = 0xe0;
|
||||
virtual-method bool isMob() = 0xe8;
|
||||
virtual-method bool isItemEntity() = 0xec;
|
||||
// HangingEntity is a painting
|
||||
virtual-method bool isHangingEntity() = 0xf0;
|
||||
// The owner entity id for arrows/throwables, else 0
|
||||
virtual-method int getAuxData() = 0xf4;
|
||||
|
||||
method void moveTo(float x, float y, float z, float yaw, float pitch) = 0x7a834;
|
||||
|
||||
|
3
symbols/src/entity/animal/Cow.def
Normal file
@ -0,0 +1,3 @@
|
||||
extends Animal;
|
||||
|
||||
vtable 0x10ba38;
|
@ -2,12 +2,19 @@ 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;
|
||||
property SimpleFoodData foodData = 0xc00;
|
||||
|
@ -7,3 +7,4 @@ method void blit(int x_dest, int y_dest, int x_src, int y_src, int width_dest, i
|
||||
method void drawCenteredString(Font *font, std::string *text, int x, int y, int color) = 0x2821c;
|
||||
method void drawString(Font *font, std::string *text, int x, int y, int color) = 0x28284;
|
||||
method void fill(int x1, int y1, int x2, int y2, uint color) = 0x285f0;
|
||||
method void fillGradient(int x1, int y1, int x2, int y2, int color1, int color2) = 0x287c0;
|
6
symbols/src/gui/screens/PaneCraftingScreen.def
Normal file
@ -0,0 +1,6 @@
|
||||
extends Screen;
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
Shouldn't this extend Shouldn't this extend `Screen`?
|
||||
|
||||
method void craftSelectedItem() = 0x2e0e4;
|
||||
method void recheckRecipes() = 0x2dc98;
|
||||
|
||||
property CItem *item = 0x74;
|
@ -6,23 +6,23 @@ constructor () = 0x29028;
|
||||
vtable-size 0x74;
|
||||
vtable 0x1039d8;
|
||||
|
||||
virtual-method void updateEvents() = 0x14;
|
||||
virtual-method void keyboardNewChar(char key) = 0x70;
|
||||
virtual-method void keyPressed(int key) = 0x6c;
|
||||
virtual-method void init() = 0xc;
|
||||
virtual-method void render(int x, int y, float param_1) = 0x8;
|
||||
virtual-method void setupPositions() = 0x10;
|
||||
virtual-method void updateEvents() = 0x14;
|
||||
virtual-method bool handleBackEvent(bool do_nothing) = 0x24;
|
||||
virtual-method void tick() = 0x28;
|
||||
virtual-method void buttonClicked(Button *button) = 0x60;
|
||||
virtual-method void init() = 0xc;
|
||||
virtual-method void mouseClicked(int x, int y, int param_1) = 0x64;
|
||||
virtual-method void removed() = 0x2c;
|
||||
virtual-method void renderBackground() = 0x30;
|
||||
virtual-method void setupPositions() = 0x10;
|
||||
virtual-method void buttonClicked(Button *button) = 0x60;
|
||||
virtual-method void mouseClicked(int x, int y, int param_1) = 0x64;
|
||||
virtual-method void keyPressed(int key) = 0x6c;
|
||||
virtual-method void keyboardNewChar(char key) = 0x70;
|
||||
|
||||
property Minecraft *minecraft = 0x14;
|
||||
property std::vector<Button *> rendered_buttons = 0x18;
|
||||
property std::vector<Button *> selectable_buttons = 0x30;
|
||||
property int width = 0x8;
|
||||
property int height = 0xc;
|
||||
property bool passthrough_input = 0x10;
|
||||
property Minecraft *minecraft = 0x14;
|
||||
property std::vector<Button *> rendered_buttons = 0x18;
|
||||
property std::vector<Button *> selectable_buttons = 0x30;
|
||||
property Font *font = 0x40;
|
||||
|
@ -5,3 +5,6 @@ vtable 0x10e7b0;
|
||||
vtable-size 0x98;
|
||||
|
||||
property int nutrition = 0x24;
|
||||
// Always 0.6
|
||||
property float unknown_param_1 = 0x28;
|
||||
property bool meat = 0x2c;
|
||||
|
@ -6,13 +6,23 @@ 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;
|
||||
virtual-method ItemInstance useTimeDepleted(ItemInstance *item_instance, Level *level, Player *player) = 0x28;
|
||||
virtual-method int getDestorySpeed(ItemInstance *item_instance, Tile *tile) = 0x2c;
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
This seems wrong. According to Ghidra, this function's signature is It could be returning a structure, IIRC if a function returns a structure, the caller allocates the structure and passes a pointer to it as the first argument top the function (like how This seems wrong. According to Ghidra, this function's signature is `Item::useTimeDepleted(ItemInstance*, Level*, Player*)` (and of course an extra `Item *self`).
It could be returning a structure, IIRC if a function returns a structure, the caller allocates the structure and passes a pointer to it as the first argument top the function (like how `this` is passed) and then the function writes to that pointer. Check out `CommandServer::parse` in Ghidra.
bigjango13
commented
Hmm, seems like it. it tripped me up because both Item and ItemInstance have the id at 0x4. Hmm, seems like it. it tripped me up because both Item and ItemInstance have the id at 0x4.
|
||||
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;
|
||||
// This returns an Item*, but it's never called normally so it doesn't matter if we invent a better system over top of it
|
||||
virtual-method ItemInstance *getCraftingRemainingItem(ItemInstance *item_instance) = 0x84;
|
||||
// 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;
|
||||
@ -21,6 +31,7 @@ property int category = 0x10;
|
||||
property int max_stack_size = 0x14;
|
||||
property bool equipped = 0x18;
|
||||
property bool is_stacked_by_data = 0x19;
|
||||
property Item *craftingRemainingItem = 0x1c;
|
||||
property std::string description_id = 0x20;
|
||||
|
||||
// Globals
|
||||
|
@ -1,4 +1,5 @@
|
||||
static-method void renderGuiItem_one(Font *font, Textures *textures, ItemInstance *item_instance, float param_1, float param_2, bool param_3) = 0x63e58;
|
||||
static-method void renderGuiItem_two(Font *font, Textures *textures, ItemInstance *item_instance, float param_1, float param_2, float param_3, float param_4, bool param_5) = 0x63be0;
|
||||
static-method void renderGuiItemCorrect(Font *font, Textures *textures, ItemInstance *item_instance, int param_1, int param_2) = 0x639a0;
|
||||
static-method void renderGuiItemDecorations(ItemInstance *item, float x, float y) = 0x63748;
|
||||
static-method void renderGuiItem_one(Font *font, Textures *textures, ItemInstance *item_instance, float x, float y, bool param_3) = 0x63e58;
|
||||
static-method void renderGuiItem_two(Font *font, Textures *textures, ItemInstance *item_instance, float x, float y, float w, float h, bool param_5) = 0x63be0;
|
||||
static-method void renderGuiItemCorrect(Font *font, Textures *textures, ItemInstance *item_instance, int x, int y) = 0x639a0;
|
||||
static-method void renderGuiItemDecorations(ItemInstance *item, float x, float y) = 0x63748;
|
||||
static-method void blit(float x, float y, float texture_x, float texture_y, float w, float h) = 0x638c0;
|
||||
|
@ -1,4 +1,7 @@
|
||||
virtual-method bool isSolid() = 0x8;
|
||||
|
||||
// Globals
|
||||
static-property Material *Material_stone = 0x180a9c;
|
||||
static-property Material *dirt = 0x180a94;
|
||||
static-property Material *stone = 0x180a9c;
|
||||
static-property Material *metal = 0x180aa0;
|
||||
static-property Material *glass = 0x180acc;
|
||||
|
3
symbols/src/misc/I18n.def
Normal file
@ -0,0 +1,3 @@
|
||||
static-method void loadLanguage(AppPlatform *app, std::string language_name) = 0x680d0;
|
||||
|
||||
static-property std::map<std::string, std::string> _strings = 0x137d98;
|
5
symbols/src/misc/SimpleFoodData.def
Normal file
@ -0,0 +1,5 @@
|
||||
size 0x4;
|
||||
|
||||
method void eat(int amount) = 0x91470;
|
||||
|
||||
property int health = 0x0;
|
@ -1,6 +1,8 @@
|
||||
method void begin(int mode) = 0x529d4;
|
||||
method void draw() = 0x52e08;
|
||||
method void colorABGR(int color) = 0x52b54;
|
||||
method void color(int r, int g, int b, int a) = 0x52a48;
|
||||
method void vertex(float x, float y, float z) = 052bc0;
|
||||
method void vertexUV(float x, float y, float z, float u, float v) = 0x52d40;
|
||||
|
||||
static-property Tesselator instance = 0x137538;
|
||||
|
@ -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;
|
||||
|
3
symbols/src/recipes/CItem.def
Normal file
@ -0,0 +1,3 @@
|
||||
property ItemInstance item = 0x0;
|
||||
property std::vector<ReqItem> ingredients = 0x20;
|
||||
property bool craftable = 0x2c;
|
3
symbols/src/recipes/ReqItem.def
Normal file
@ -0,0 +1,3 @@
|
||||
size 0x10;
|
||||
|
||||
property ItemInstance requested_item = 0x0;
|
@ -3,21 +3,43 @@ static-method void initTiles() = 0xc358c;
|
||||
vtable 0x115670;
|
||||
vtable-size 0x104;
|
||||
|
||||
constructor (int id, int texture, void *material) = 0xc33a0;
|
||||
constructor (int id, int texture, Material *material) = 0xc33a0;
|
||||
size 0x5c;
|
||||
|
||||
method Tile *init() = 0xc34dc;
|
||||
virtual-method Tile *setDestroyTime(float destroy_time) = 0xf8;
|
||||
virtual-method Tile *setExplodeable(float explodeable) = 0xf4;
|
||||
virtual-method Tile *setSoundType(Tile_SoundType *sound_type) = 0xe8;
|
||||
virtual-method int use(Level *level, int x, int y, int z, Player *player) = 0x98;
|
||||
virtual-method int getColor(LevelSource *level_source, int x, int y, int z) = 0xb8;
|
||||
|
||||
|
||||
virtual-method bool isCubeShaped() = 0x8;
|
||||
virtual-method int getRenderShape() = 0xc;
|
||||
virtual-method void setShape(float x1, float y1, float z1, float x2, float y2, float z2) = 0x10;
|
||||
virtual-method void updateShape(LevelSource *level, int x, int y, int z) = 0x14;
|
||||
virtual-method void updateDefaultShape() = 0x18;
|
||||
virtual-method float getBrightness(LevelSource *level, int x, int y, int z) = 0x20;
|
||||
virtual-method int getTexture1() = 0x28;
|
||||
virtual-method int getTexture2(int face, int data) = 0x2c;
|
||||
virtual-method int getTexture3(LevelSource *level, int x, int y, int z, int face) = 0x30;
|
||||
virtual-method AABB *getAABB(Level *level, int x, int y, int z) = 0x34;
|
||||
virtual-method bool isSolidRender() = 0x40;
|
||||
virtual-method void tick(Level *level, int x, int y, int z) = 0x58;
|
||||
virtual-method void neighborChanged(Level *level, int x, int y, int z, int neighborId) = 0x64;
|
||||
virtual-method void onPlace(Level *level, int x, int y, int z) = 0x68;
|
||||
virtual-method void onRemove(Level *level, int x, int y, int z) = 0x6c;
|
||||
virtual-method int getRenderLayer() = 0x94;
|
||||
virtual-method int use(Level *level, int x, int y, int z, Player *player) = 0x98;
|
||||
virtual-method void setPlacedBy(Level *level, int x, int y, int z, Mob *placer) = 0xa8;
|
||||
virtual-method int getColor(LevelSource *level_source, int x, int y, int z) = 0xb8;
|
||||
virtual-method void entityInside(Level *level, int x, int y, int z, Entity *entity) = 0xcc;
|
||||
virtual-method std::string getDescriptionId() = 0xdc;
|
||||
virtual-method Tile *setDescriptionId(std::string *description_id) = 0xe0;
|
||||
virtual-method Tile *setSoundType(Tile_SoundType *sound_type) = 0xe8;
|
||||
virtual-method Tile *setLightEmission(float light) = 0xf0;
|
||||
virtual-method Tile *setExplodeable(float explodeable) = 0xf4;
|
||||
virtual-method Tile *setDestroyTime(float destroy_time) = 0xf8;
|
||||
|
||||
property int texture = 0x4;
|
||||
property int id = 0x8;
|
||||
property int category = 0x3c;
|
||||
property AABB aabb = 0x40;
|
||||
|
||||
// Globals
|
||||
static-property-array Tile *tiles = 0x180e08;
|
||||
@ -49,3 +71,6 @@ static-property Tile *grass_carried = 0x181dd4;
|
||||
|
||||
// Sounds
|
||||
static-property Tile_SoundType SOUND_STONE = 0x181c80;
|
||||
|
||||
// Light
|
||||
static-property float *lightEmission = 0x181214;
|
||||
|
@ -1 +1,4 @@
|
||||
method void tesselateBlockInWorld(Tile *tile, int x, int y, int z) = 0x59e30;
|
||||
method bool tesselateBlockInWorld(Tile *tile, int x, int y, int z) = 0x59e30;
|
||||
method bool tesselateInWorld(Tile *tile, int x, int y, int z) = 0x5e80c;
|
||||
|
||||
property Level *level = 0x0;
|
||||
|
Why did you add this to the v2.5.3 changelog?
Should I add it to v2.5.4 or v2.6.0 instead?
Add it to v3.0.0.