WIP New Modding API
Some checks failed
Build / Build (AMD64, Server) (push) Failing after 3m17s
Build / Build (AMD64, Client) (push) Successful in 8m28s
Build / Build (ARM64, Client) (push) Successful in 8m27s
Build / Build (ARM64, Server) (push) Failing after 4m1s
Build / Build (ARMHF, Server) (push) Failing after 3m31s
Build / Build (ARMHF, Client) (push) Successful in 7m38s
Build / Release (push) Has been skipped
Build / Test (Client) (push) Failing after 5m48s
Build / Test (Server) (push) Failing after 3m9s

This commit is contained in:
TheBrokenRail 2024-01-06 06:30:23 -05:00
parent 0be1f4fce8
commit aa92da6fdd
161 changed files with 1423 additions and 1763 deletions

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
[submodule "archives"]
path = archives
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/archives.git
[submodule "dependencies/symbol-processor/src"]
path = dependencies/symbol-processor/src
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/symbol-processor.git

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2022 TheBrokenRail
Copyright (c) 2024 TheBrokenRail
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -30,3 +30,7 @@ if(BUILD_MEDIA_LAYER_CORE AND NOT MCPI_HEADLESS_MODE AND MCPI_USE_GLES1_COMPATIB
endif()
# UTF8-CPP
add_subdirectory(utf8cpp)
# Symbol Prcoessor
if(BUILD_ARM_COMPONENTS)
add_subdirectory(symbol-processor)
endif()

View File

@ -0,0 +1,20 @@
project(symbol-processor)
# Install Dependencies
set(SRC "${CMAKE_CURRENT_SOURCE_DIR}/src")
set(NODE_MODULES "${SRC}/node_modules")
function(npm_run)
execute_process(
COMMAND npm ${ARGV}
WORKING_DIRECTORY "${SRC}"
RESULT_VARIABLE RESULT
)
if(NOT RESULT EQUAL 0)
file(REMOVE_RECURSE "${NODE_MODULES}")
message(FATAL_ERROR "Unable To Run NPM Command")
endif()
endfunction()
if(NOT EXISTS "${NODE_MODULES}")
npm_run(ci --silent)
npm_run(run --silent lint)
endif()

1
dependencies/symbol-processor/src vendored Submodule

@ -0,0 +1 @@
Subproject commit 1062e048c493607b7b57faf83570562fa44c0f9c

View File

@ -8,6 +8,7 @@ target_include_directories(
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${MCPI_SDK_INCLUDE_DIR}/mods>"
)
target_link_libraries(mods-headers INTERFACE symbols)
# SDK
install(TARGETS mods-headers EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}")
install(DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/mods")
@ -115,7 +116,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 reborn-util compat game-mode misc death options chat creative bucket textures home version test media-layer-core)
target_link_libraries(init symbols mods-headers reborn-util compat game-mode misc death options chat creative bucket textures home version test media-layer-core)
if(MCPI_SERVER_MODE)
target_link_libraries(init server)
else()

View File

@ -1,11 +1,12 @@
#pragma once
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#ifdef __cplusplus
#include <string>
// Send API Command
std::string chat_send_api_command(unsigned char *minecraft, char *str);
std::string chat_send_api_command(Minecraft *minecraft, std::string str);
#endif
#ifdef __cplusplus
@ -18,8 +19,8 @@ unsigned int chat_get_counter();
#endif
// Override using the HOOK() macro to provide customized chat behavior.
void chat_send_message(unsigned char *server_side_network_handler, char *username, char *message);
void chat_handle_packet_send(unsigned char *minecraft, unsigned char *packet);
void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, char *username, char *message);
void chat_handle_packet_send(Minecraft *minecraft, ChatPacket *packet);
#ifdef __cplusplus
}

View File

@ -1,10 +1,12 @@
#pragma once
#include <symbols/minecraft.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*input_tick_function_t)(unsigned char *minecraft);
typedef void (*input_tick_function_t)(Minecraft *minecraft);
void input_run_on_tick(input_tick_function_t function);
void input_set_is_right_click(int val);

View File

@ -2,25 +2,31 @@
#include <stdint.h>
#include <symbols/minecraft.h>
#ifdef __cplusplus
extern "C" {
#endif
int32_t misc_get_real_selected_slot(unsigned char *player);
int32_t misc_get_real_selected_slot(Player *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
typedef void (*misc_update_function_Minecraft_t)(Minecraft *obj);
void misc_run_on_update(misc_update_function_Minecraft_t function); // obj == Minecraft *
void misc_run_on_tick(misc_update_function_Minecraft_t function); // obj == Minecraft *
typedef void (*misc_update_function_Recipes_t)(Recipes *obj);
void misc_run_on_recipes_setup(misc_update_function_Recipes_t function); // obj == Recipes *
typedef void (*misc_update_function_FurnaceRecipes_t)(FurnaceRecipes *obj);
void misc_run_on_furnace_recipes_setup(misc_update_function_FurnaceRecipes_t function); // obj == FurnaceRecipes *
typedef void (*misc_update_function_FillingContainer_t)(FillingContainer *obj);
void misc_run_on_creative_inventory_setup(misc_update_function_FillingContainer_t function); // obj == FillingContainer *
typedef void (*misc_update_function_void_t)(void *obj);
void misc_run_on_tiles_setup(misc_update_function_void_t function); // obj == NULL
void misc_run_on_items_setup(misc_update_function_void_t function); // obj == NULL
void Level_saveLevelData_injection(unsigned char *level);
void Level_saveLevelData_injection(Level *level);
// Use this instead of directly calling Gui::addMessage(), it has proper logging!
void misc_add_message(unsigned char *gui, const char *text);
void misc_add_message(Gui *gui, const char *text);
#ifdef __cplusplus
}

View File

@ -7,9 +7,9 @@
#include <mods/init/init.h>
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
static void ItemRenderer_renderGuiItemCorrect_injection(unsigned char *font, unsigned char *textures, ItemInstance *item_instance, int32_t param_1, int32_t param_2) {
int32_t leaves_id = *(int32_t *) (*Tile_leaves + Tile_id_property_offset);
int32_t grass_id = *(int32_t *) (*Tile_grass + Tile_id_property_offset);
static void ItemRenderer_renderGuiItemCorrect_injection(Font *font, Textures *textures, ItemInstance *item_instance, int32_t param_1, int32_t param_2) {
int32_t leaves_id = (*Tile_leaves)->id;
int32_t grass_id = (*Tile_grass)->id;
// Replace Rendered Item With Carried Variant
ItemInstance carried_item_instance;
bool use_carried = false;
@ -40,7 +40,7 @@ static void ItemRenderer_renderGuiItemCorrect_injection(unsigned char *font, uns
static int item_color_fix_mode = 0;
#define POTENTIAL_FURNACE_ITEM_TRANSPARENCY 0x33
#define INVALID_FURNACE_ITEM_MULTIPLIER 0.25f
static void Tesselator_color_injection(unsigned char *tesselator, int32_t r, int32_t g, int32_t b, int32_t a) {
static void Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_t g, int32_t b, int32_t a) {
// Fix Furnace UI
if (item_color_fix_mode != 0) {
// Force Translucent
@ -57,7 +57,7 @@ static void Tesselator_color_injection(unsigned char *tesselator, int32_t r, int
// Call Original Method
(*Tesselator_color)(tesselator, r, g, b, a);
}
static void Tesselator_begin_injection(unsigned char *tesselator, int32_t mode) {
static void Tesselator_begin_injection(Tesselator *tesselator, int32_t mode) {
// Call Original Method
(*Tesselator_begin)(tesselator, mode);
@ -67,21 +67,21 @@ static void Tesselator_begin_injection(unsigned char *tesselator, int32_t mode)
(*Tesselator_color_injection)(tesselator, 0xff, 0xff, 0xff, 0xff);
}
}
static void InventoryPane_renderBatch_Tesselator_color_injection(unsigned char *tesselator, int32_t r, int32_t g, int32_t b) {
static void InventoryPane_renderBatch_Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_t g, int32_t b) {
// Call Original Method
(*Tesselator_color)(tesselator, r, g, b, 0xff);
// Enable Item Color Fix
item_color_fix_mode = 2;
}
static void ItemRenderer_renderGuiItem_two_injection(unsigned char *font, unsigned char *textures, ItemInstance *item_instance, float param_1, float param_2, float param_3, float param_4, bool param_5) {
static void ItemRenderer_renderGuiItem_two_injection(Font *font, Textures *textures, ItemInstance *item_instance, float param_1, float param_2, float param_3, float param_4, bool param_5) {
// Call Original Method
(*ItemRenderer_renderGuiItem_two)(font, textures, item_instance, param_1, param_2, param_3, param_4, param_5);
// Disable Item Color Fix
item_color_fix_mode = 0;
}
static void FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection(unsigned char *font, unsigned char *textures, ItemInstance *item_instance, float param_1, float param_2, bool param_3) {
static void FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection(Font *font, Textures *textures, ItemInstance *item_instance, float param_1, float param_2, bool param_3) {
// Enable Item Color Fix
item_color_fix_mode = 1;

View File

@ -36,7 +36,7 @@ __attribute__((constructor)) static void _init_active(int argc, char *argv[]) {
#define BENCHMARK_ROTATION_AMOUNT 10
// Create/Start World
static void start_world(unsigned char *minecraft) {
static void start_world(Minecraft *minecraft) {
// Log
INFO("Loading Benchmark");
@ -46,19 +46,18 @@ static void start_world(unsigned char *minecraft) {
settings.seed = BENCHMARK_SEED;
// Delete World If It Already Exists
unsigned char *level_source = (*Minecraft_getLevelSource)(minecraft);
unsigned char *level_source_vtable = *(unsigned char **) level_source;
ExternalFileLevelStorageSource_deleteLevel_t ExternalFileLevelStorageSource_deleteLevel = *(ExternalFileLevelStorageSource_deleteLevel_t *) (level_source_vtable + ExternalFileLevelStorageSource_deleteLevel_vtable_offset);
(*ExternalFileLevelStorageSource_deleteLevel)(level_source, BENCHMARK_WORLD_NAME);
LevelStorageSource *level_source = (*Minecraft_getLevelSource)(minecraft);
std::string name = BENCHMARK_WORLD_NAME;
level_source->vtable->deleteLevel(level_source, &name);
// Select Level
(*Minecraft_selectLevel)(minecraft, BENCHMARK_WORLD_NAME, BENCHMARK_WORLD_NAME, settings);
minecraft->vtable->selectLevel(minecraft, &name, &name, &settings);
// Open ProgressScreen
void *screen = ::operator new(PROGRESS_SCREEN_SIZE);
ProgressScreen *screen = alloc_ProgressScreen();
ALLOC_CHECK(screen);
screen = (*ProgressScreen)((unsigned char *) screen);
(*Minecraft_setScreen)(minecraft, (unsigned char *) screen);
screen = (*ProgressScreen_constructor)(screen);
(*Minecraft_setScreen)(minecraft, (Screen *) screen);
}
// Track Frames
@ -73,7 +72,7 @@ HOOK(media_swap_buffers, void, ()) {
// Track Ticks
static unsigned long long int ticks = 0;
static void Minecraft_tick_injection(__attribute__((unused)) unsigned char *minecraft) {
static void Minecraft_tick_injection(__attribute__((unused)) Minecraft *minecraft) {
ticks++;
}
@ -100,7 +99,7 @@ static int32_t last_logged_status = -1;
// Runs Every Tick
static bool loaded = false;
static bool exit_requested = false;
static void Minecraft_update_injection(unsigned char *minecraft) {
static void Minecraft_update_injection(Minecraft *minecraft) {
// Create/Start World
if (!loaded) {
start_world(minecraft);

View File

@ -6,22 +6,22 @@
#include <mods/misc/misc.h>
// Items
unsigned char *bucket = NULL;
Item *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)) {
static std::string BucketItem_getDescriptionId(__attribute__((unused)) Item *item, ItemInstance *item_instance) {
if (item_instance->auxiliary == (*Tile_water)->id) {
return "item.bucketWater";
} else if (item_instance->auxiliary == *(int32_t *) (*Tile_lava + Tile_id_property_offset)) {
} else if (item_instance->auxiliary == (*Tile_lava)->id) {
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)) {
static int32_t BucketItem_getIcon(__attribute__((unused)) Item *item, int32_t auxiliary) {
if (auxiliary == (*Tile_water)->id) {
return 75;
} else if (auxiliary == *(int32_t *) (*Tile_lava + Tile_id_property_offset)) {
} else if (auxiliary == (*Tile_lava)->id) {
return 76;
} else {
return 74;
@ -29,17 +29,17 @@ static int32_t BucketItem_getIcon(__attribute__((unused)) unsigned char *item, i
}
// 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) {
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) {
return 0;
} else 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_lava + Tile_id_property_offset);
int32_t tile = level->vtable->getTile(level, x, y, z);
if (tile == (*Tile_calmWater)->id) {
new_auxiliary = (*Tile_water)->id;
} else if (tile == (*Tile_calmLava)->id) {
new_auxiliary = (*Tile_lava)->id;
}
if (new_auxiliary != 0) {
// Valid
@ -49,13 +49,11 @@ static int32_t BucketItem_useOn(__attribute__((unused)) unsigned char *item, Ite
success = true;
} else {
ItemInstance new_item;
new_item.id = *(int32_t *) (bucket + Item_id_property_offset);
new_item.id = bucket->id;
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)) {
Inventory *inventory = player->inventory;
if (inventory->vtable->add(inventory, &new_item)) {
// Added To Inventory
success = true;
item_instance->count -= 1;
@ -101,13 +99,11 @@ static int32_t BucketItem_useOn(__attribute__((unused)) unsigned char *item, Ite
}
// Get Current Tile
bool valid = false;
unsigned char *material = (*Level_getMaterial)(level, x, y, z);
Material *material = level->vtable->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);
valid = !material->vtable->isSolid(material);
}
if (item_instance->auxiliary != *(int32_t *) (*Tile_water + Tile_id_property_offset) && item_instance->auxiliary != *(int32_t *) (*Tile_lava + Tile_id_property_offset)) {
if (item_instance->auxiliary != (*Tile_water)->id && item_instance->auxiliary != (*Tile_lava)->id) {
valid = false;
}
if (valid) {
@ -121,59 +117,49 @@ static int32_t BucketItem_useOn(__attribute__((unused)) unsigned char *item, Ite
}
// Bucket VTable
static unsigned char *get_bucket_vtable() {
static unsigned char *vtable = NULL;
static Item_vtable *get_bucket_vtable() {
static Item_vtable *vtable = NULL;
if (vtable == NULL) {
// Init
vtable = (unsigned char *) malloc(ITEM_VTABLE_SIZE);
vtable = dup_Item_vtable(Item_vtable_base);
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;
vtable->getDescriptionId = BucketItem_getDescriptionId;
vtable->getIcon = BucketItem_getIcon;
vtable->useOn = 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) {
static Item *create_bucket(int32_t id, int32_t texture_x, int32_t texture_y, std::string name) {
// Construct
unsigned char *item = (unsigned char *) ::operator new(ITEM_SIZE);
Item *item = alloc_Item();
ALLOC_CHECK(item);
(*Item)(item, id);
(*Item_constructor)(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);
item->vtable = get_bucket_vtable();
// 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;
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;
// Return
return item;
}
static void Item_initItems_injection(__attribute__((unused)) unsigned char *null) {
static void Item_initItems_injection(__attribute__((unused)) void *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) {
if (item_instance->id == bucket->id && item_instance->auxiliary == 0) {
// Custom Value
return 16;
} else {
@ -183,60 +169,56 @@ static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instanc
}
// Creative Inventory
static void inventory_add_item(unsigned char *inventory, unsigned char *item, int32_t auxiliary) {
static void inventory_add_item(FillingContainer *inventory, Item *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) {
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *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));
inventory_add_item(filling_container, bucket, (*Tile_water)->id);
inventory_add_item(filling_container, bucket, (*Tile_lava)->id);
}
// Make Liquids Selectable
static bool is_holding_bucket = false;
static HitResult Mob_pick_Level_clip_injection(unsigned char *level, unsigned char *param_1, unsigned char *param_2, __attribute__((unused)) bool clip_liquids, bool param_3) {
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) {
// Call Original Method
return (*Level_clip)(level, param_1, param_2, is_holding_bucket, param_3);
}
static void handle_tick(unsigned char *minecraft) {
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
static void handle_tick(Minecraft *minecraft) {
LocalPlayer *player = minecraft->player;
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);
int32_t selected_slot = misc_get_real_selected_slot((Player *) player);
Inventory *inventory = player->inventory;
// Get Item
ItemInstance *inventory_item = (*FillingContainer_getItem)(inventory, selected_slot);
ItemInstance *inventory_item = inventory->vtable->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;
is_holding_bucket = inventory_item != NULL && inventory_item->id == bucket->id && 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)) {
if (id == (*Tile_calmWater)->id) {
return true;
} else if (id == *(int32_t *) (*Tile_calmLava + Tile_id_property_offset)) {
} else if (id == (*Tile_calmLava)->id) {
return true;
} else {
return false;
}
}
static void Minecraft_handleMouseDown_injection(unsigned char *minecraft, int param_1, bool can_destroy) {
static void Minecraft_handleMouseDown_injection(Minecraft *minecraft, int param_1, bool can_destroy) {
// Check
unsigned char *level = *(unsigned char **) (minecraft + Minecraft_level_property_offset);
Level *level = minecraft->level;
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);
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);
if (is_calm_liquid(tile)) {
can_destroy = false;
}
@ -247,7 +229,7 @@ static void Minecraft_handleMouseDown_injection(unsigned char *minecraft, int pa
}
// Custom Crafting Recipes
static void Recipes_injection(unsigned char *recipes) {
static void Recipes_injection(Recipes *recipes) {
// Add
Recipes_Type type1 = {
.item = 0,
@ -261,15 +243,18 @@ static void Recipes_injection(unsigned char *recipes) {
};
ItemInstance result = {
.count = 1,
.id = (*(int32_t *) (bucket + Item_id_property_offset)),
.id = bucket->id,
.auxiliary = 0
};
(*Recipes_addShapedRecipe_2)(recipes, result, "# #", " # ", {type1});
std::string line1 = "# #";
std::string line2 = " # ";
std::vector<Recipes_Type> types = {type1};
(*Recipes_addShapedRecipe_2)(recipes, &result, &line1, &line2, &types);
}
// 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))) {
static int32_t FurnaceTileEntity_getBurnDuration_injection(ItemInstance *item_instance) {
if (item_instance->count > 0 && item_instance->id == bucket->id && item_instance->auxiliary == (*Tile_lava)->id) {
return 20000;
} else {
// Call Original Method
@ -278,7 +263,7 @@ static int32_t FurnaceTileEntity_getBurnDuration_injection(ItemInstance const& i
}
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))) {
if (item_instance->id == bucket->id) {
item_instance->auxiliary = 0;
} else {
// Original Behavior

View File

@ -7,28 +7,28 @@
#include <mods/init/init.h>
// Take Screenshot Using TripodCamera
static void AppPlatform_linux_saveScreenshot_injection(__attribute__((unused)) unsigned char *app_platform, __attribute__((unused)) std::string const& path, __attribute__((unused)) int32_t width, __attribute__((unused)) int32_t height) {
static void AppPlatform_linux_saveScreenshot_injection(__attribute__((unused)) AppPlatform *app_platform, __attribute__((unused)) std::string const& path, __attribute__((unused)) int32_t width, __attribute__((unused)) int32_t height) {
#ifndef MCPI_HEADLESS_MODE
screenshot_take(home_get());
#endif
}
// Enable TripodCameraRenderer
static unsigned char *EntityRenderDispatcher_injection(unsigned char *dispatcher) {
static EntityRenderDispatcher *EntityRenderDispatcher_injection(EntityRenderDispatcher *dispatcher) {
// Call Original Method
(*EntityRenderDispatcher)(dispatcher);
(*EntityRenderDispatcher_constructor)(dispatcher);
// Register TripodCameraRenderer
unsigned char *renderer = (unsigned char *) ::operator new(TRIPOD_CAMERA_RENDERER_SIZE);
TripodCameraRenderer *renderer = alloc_TripodCameraRenderer();
ALLOC_CHECK(renderer);
(*TripodCameraRenderer)(renderer);
(*EntityRenderDispatcher_assign)(dispatcher, (unsigned char) 0x5, renderer);
(*TripodCameraRenderer_constructor)(renderer);
(*EntityRenderDispatcher_assign)(dispatcher, (unsigned char) 0x5, (EntityRenderer *) renderer);
return dispatcher;
}
// Display Smoke From TripodCamera Higher
static void TripodCamera_tick_Level_addParticle_call_injection(unsigned char *level, std::string const& particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count) {
static void TripodCamera_tick_Level_addParticle_call_injection(Level *level, std::string *particle, float x, float y, float z, float deltaX, float deltaY, float deltaZ, int count) {
// Call Original Method
(*Level_addParticle)(level, particle, x, y + 0.5, z, deltaX, deltaY, deltaZ, count);
}
@ -41,7 +41,7 @@ void init_camera() {
// Fix Camera Rendering
if (feature_has("Fix Camera Rendering", server_disabled)) {
// Enable TripodCameraRenderer
overwrite_calls((void *) EntityRenderDispatcher, (void *) EntityRenderDispatcher_injection);
overwrite_calls((void *) EntityRenderDispatcher_constructor, (void *) EntityRenderDispatcher_injection);
// Display Smoke From TripodCamera Higher
overwrite_call((void *) 0x87dc4, (void *) TripodCamera_tick_Level_addParticle_call_injection);
}

View File

@ -29,14 +29,14 @@ int _chat_enabled = 0;
#define MAX_CHAT_MESSAGE_LENGTH 512
// Send API Command
std::string chat_send_api_command(unsigned char *minecraft, char *str) {
std::string chat_send_api_command(Minecraft *minecraft, std::string str) {
struct ConnectedClient client;
client.sock = -1;
client.str = "";
client.time = 0;
unsigned char *command_server = *(unsigned char **) (minecraft + Minecraft_command_server_property_offset);
CommandServer *command_server = minecraft->command_server;
if (command_server != NULL) {
return (*CommandServer_parse)(command_server, client, str);
return (*CommandServer_parse)(command_server, &client, &str);
} else {
return "";
}
@ -44,7 +44,7 @@ std::string chat_send_api_command(unsigned char *minecraft, char *str) {
#ifndef MCPI_HEADLESS_MODE
// Send API Chat Command
static void send_api_chat_command(unsigned char *minecraft, char *str) {
static void send_api_chat_command(Minecraft *minecraft, char *str) {
char *command = NULL;
safe_asprintf(&command, "chat.post(%s)\n", str);
chat_send_api_command(minecraft, command);
@ -53,45 +53,43 @@ static void send_api_chat_command(unsigned char *minecraft, char *str) {
#endif
// Send Message To Players
void chat_send_message(unsigned char *server_side_network_handler, char *username, char *message) {
void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, char *username, char *message) {
char *full_message = NULL;
safe_asprintf(&full_message, "<%s> %s", username, message);
sanitize_string(&full_message, MAX_CHAT_MESSAGE_LENGTH, 0);
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, std::string(full_message));
std::string cpp_string = full_message;
free(full_message);
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, &cpp_string);
}
// Handle Chat packet Send
void chat_handle_packet_send(unsigned char *minecraft, unsigned char *packet) {
unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset);
unsigned char *rak_net_instance_vtable = *(unsigned char **) rak_net_instance;
RakNetInstance_isServer_t RakNetInstance_isServer = *(RakNetInstance_isServer_t *) (rak_net_instance_vtable + RakNetInstance_isServer_vtable_offset);
if ((*RakNetInstance_isServer)(rak_net_instance)) {
void chat_handle_packet_send(Minecraft *minecraft, ChatPacket *packet) {
RakNetInstance *rak_net_instance = minecraft->rak_net_instance;
if (rak_net_instance->vtable->isServer(rak_net_instance)) {
// Hosting Multiplayer
char *message = *(char **) (packet + ChatPacket_message_property_offset);
unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset);
chat_send_message(server_side_network_handler, *default_username, message);
char *message = packet->message;
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) minecraft->network_handler;
chat_send_message(server_side_network_handler, *Strings_default_username, message);
} else {
// Client
RakNetInstance_send_t RakNetInstance_send = *(RakNetInstance_send_t *) (rak_net_instance_vtable + RakNetInstance_send_vtable_offset);
(*RakNetInstance_send)(rak_net_instance, packet);
rak_net_instance->vtable->send(rak_net_instance, (Packet *) packet);
}
}
// Manually Send (And Loopback) ChatPacket
static void CommandServer_parse_CommandServer_dispatchPacket_injection(unsigned char *command_server, unsigned char *packet) {
unsigned char *minecraft = *(unsigned char **) (command_server + CommandServer_minecraft_property_offset);
static void CommandServer_parse_CommandServer_dispatchPacket_injection(CommandServer *command_server, Packet *packet) {
Minecraft *minecraft = command_server->minecraft;
if (minecraft != NULL) {
chat_handle_packet_send(minecraft, packet);
chat_handle_packet_send(minecraft, (ChatPacket *) packet);
}
}
// Handle ChatPacket Server-Side
static void ServerSideNetworkHandler_handle_ChatPacket_injection(unsigned char *server_side_network_handler, RakNet_RakNetGUID *rak_net_guid, unsigned char *chat_packet) {
unsigned char *player = (*ServerSideNetworkHandler_getPlayer)(server_side_network_handler, rak_net_guid);
static void ServerSideNetworkHandler_handle_ChatPacket_injection(ServerSideNetworkHandler *server_side_network_handler, RakNet_RakNetGUID *rak_net_guid, ChatPacket *chat_packet) {
Player *player = (*ServerSideNetworkHandler_getPlayer)(server_side_network_handler, rak_net_guid);
if (player != NULL) {
char *username = *(char **) (player + Player_username_property_offset);
char *message = *(char **) (chat_packet + ChatPacket_message_property_offset);
chat_send_message(server_side_network_handler, username, message);
const char *username = player->username.c_str();
char *message = chat_packet->message;
chat_send_message(server_side_network_handler, (char *) username, message);
}
}
@ -112,7 +110,7 @@ void _chat_queue_message(char *message) {
}
// Empty Queue
unsigned int old_chat_counter = 0;
static void send_queued_messages(unsigned char *minecraft) {
static void send_queued_messages(Minecraft *minecraft) {
// Lock
pthread_mutex_lock(&queue_mutex);
// If Message Was Submitted, No Other Chat Windows Are Open, And The Game Is Not Paused, Then Re-Lock Cursor

View File

@ -8,20 +8,26 @@
#ifndef MCPI_SERVER_MODE
// Add Item To Inventory
static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) {
static void inventory_add_item(FillingContainer *inventory, Item *item) {
ItemInstance *item_instance = new ItemInstance;
ALLOC_CHECK(item_instance);
item_instance = (*(is_tile ? ItemInstance_constructor_tile : ItemInstance_constructor_item))(item_instance, item);
item_instance = (*ItemInstance_constructor_item)(item_instance, item);
(*FillingContainer_addItem)(inventory, item_instance);
}
static void inventory_add_item(FillingContainer *inventory, Tile *item) {
ItemInstance *item_instance = new ItemInstance;
ALLOC_CHECK(item_instance);
item_instance = (*ItemInstance_constructor_tile)(item_instance, item);
(*FillingContainer_addItem)(inventory, item_instance);
}
// Expand Creative Inventory
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsigned char *filling_container) {
static void Inventory_setupDefault_FillingContainer_addItem_call_injection(FillingContainer *filling_container) {
// Add Items
inventory_add_item(filling_container, *Item_flintAndSteel, false);
inventory_add_item(filling_container, *Item_snowball, false);
inventory_add_item(filling_container, *Item_egg, false);
inventory_add_item(filling_container, *Item_shears, false);
inventory_add_item(filling_container, *Item_flintAndSteel);
inventory_add_item(filling_container, *Item_snowball);
inventory_add_item(filling_container, *Item_egg);
inventory_add_item(filling_container, *Item_shears);
// Dyes
for (int i = 0; i < 16; i++) {
if (i == 15) {
@ -33,20 +39,20 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
new_item_instance = (*ItemInstance_constructor_item_extra)(new_item_instance, *Item_dye_powder, 1, i);
(*FillingContainer_addItem)(filling_container, new_item_instance);
}
inventory_add_item(filling_container, *Item_camera, false);
inventory_add_item(filling_container, *Item_camera);
// Add Tiles
inventory_add_item(filling_container, *Tile_water, true);
inventory_add_item(filling_container, *Tile_lava, true);
inventory_add_item(filling_container, *Tile_calmWater, true);
inventory_add_item(filling_container, *Tile_calmLava, true);
inventory_add_item(filling_container, *Tile_glowingObsidian, true);
inventory_add_item(filling_container, *Tile_web, true);
inventory_add_item(filling_container, *Tile_topSnow, true);
inventory_add_item(filling_container, *Tile_ice, true);
inventory_add_item(filling_container, *Tile_invisible_bedrock, true);
inventory_add_item(filling_container, *Tile_bedrock, true);
inventory_add_item(filling_container, *Tile_info_updateGame1, true);
inventory_add_item(filling_container, *Tile_info_updateGame2, true);
inventory_add_item(filling_container, *Tile_water);
inventory_add_item(filling_container, *Tile_lava);
inventory_add_item(filling_container, *Tile_calmWater);
inventory_add_item(filling_container, *Tile_calmLava);
inventory_add_item(filling_container, *Tile_glowingObsidian);
inventory_add_item(filling_container, *Tile_web);
inventory_add_item(filling_container, *Tile_topSnow);
inventory_add_item(filling_container, *Tile_ice);
inventory_add_item(filling_container, *Tile_invisible_bedrock);
inventory_add_item(filling_container, *Tile_bedrock);
inventory_add_item(filling_container, *Tile_info_updateGame1);
inventory_add_item(filling_container, *Tile_info_updateGame2);
// Nether Reactor
for (int i = 0; i < 3; i++) {
if (i == 0) {
@ -80,19 +86,19 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(unsig
#endif
// Hook Specific TileItem Constructor
static unsigned char *Tile_initTiles_TileItem_injection(unsigned char *tile_item, int32_t id) {
static TileItem *Tile_initTiles_TileItem_injection(TileItem *tile_item, int32_t id) {
// Call Original Method
unsigned char *ret = (*TileItem)(tile_item, id);
(*TileItem_constructor)(tile_item, id);
// Switch VTable
*(unsigned char **) tile_item = AuxDataTileItem_vtable;
tile_item->vtable = (TileItem_vtable *) AuxDataTileItem_vtable_base;
// Configure Item
*(bool *) (tile_item + Item_is_stacked_by_data_property_offset) = true;
*(int32_t *) (tile_item + Item_max_damage_property_offset) = 0;
*(unsigned char **) (tile_item + AuxDataTileItem_icon_tile_property_offset) = Tile_tiles[id + 0x100];
tile_item->is_stacked_by_data = true;
tile_item->max_damage = 0;
((AuxDataTileItem *) tile_item)->icon_tile = Tile_tiles[id + 0x100];
// Return
return ret;
return tile_item;
}
// Check Restriction Status

View File

@ -7,9 +7,9 @@
#include <mods/feature/feature.h>
// Death Messages
static std::string get_death_message(unsigned char *player) {
static std::string get_death_message(Player *player) {
// Get Username
std::string *username = (std::string *) (player + Player_username_property_offset);
std::string *username = &player->username;
// Prepare Death Message
std::string message;
@ -20,44 +20,36 @@ static std::string get_death_message(unsigned char *player) {
return message;
}
// Common Death Message Logic
static void Player_actuallyHurt_injection_helper(unsigned char *player, int32_t damage, bool is_local_player) {
// Store Old Health
int32_t old_health = *(int32_t *) (player + Mob_health_property_offset);
// Call Original Method
(*(is_local_player ? LocalPlayer_actuallyHurt : Mob_actuallyHurt))(player, damage);
// Store New Health
int32_t new_health = *(int32_t *) (player + Mob_health_property_offset);
// Get Variables
unsigned char *minecraft = *(unsigned char **) (player + (is_local_player ? LocalPlayer_minecraft_property_offset : ServerPlayer_minecraft_property_offset));
unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset);
unsigned char *rak_net_instance_vtable = *(unsigned char **) rak_net_instance;
// Only Run On Server-Side
RakNetInstance_isServer_t RakNetInstance_isServer = *(RakNetInstance_isServer_t *) (rak_net_instance_vtable + RakNetInstance_isServer_vtable_offset);
if ((*RakNetInstance_isServer)(rak_net_instance)) {
// Check Health
if (new_health < 1 && old_health >= 1) {
// Get Death Message
std::string message = get_death_message(player);
// Post Death Message
unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset);
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, message);
}
// Death Message Logic
#define Player_actuallyHurt_injection(type) \
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); \
\
/* Store New Health */ \
int32_t new_health = player->health; \
\
/* Get Variables */ \
Minecraft *minecraft = player->minecraft; \
RakNetInstance *rak_net_instance = 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); \
\
/* Post Death Message */ \
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) minecraft->network_handler; \
(*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, &message); \
} \
} \
}
}
// ServerPlayer Death Message Logic
static void ServerPlayer_actuallyHurt_injection(unsigned char *player, int32_t damage) {
Player_actuallyHurt_injection_helper(player, damage, false);
}
// LocalPlayer Death Message Logic
static void LocalPlayer_actuallyHurt_injection(unsigned char *player, int32_t damage) {
Player_actuallyHurt_injection_helper(player, damage, true);
}
Player_actuallyHurt_injection(Local)
Player_actuallyHurt_injection(Server)
// Init
void init_death() {

View File

@ -21,14 +21,14 @@ static void set_is_survival(int new_is_survival) {
patch((void *) 0x16ee4, size_patch);
// Replace Default CreatorMode Constructor With CreatorMode Or SurvivalMode Constructor
overwrite_call((void *) 0x16ef4, new_is_survival ? SurvivalMode : CreatorMode);
overwrite_call((void *) 0x16ef4, new_is_survival ? (void *) SurvivalMode_constructor : (void *) CreatorMode_constructor);
is_survival = new_is_survival;
}
}
// Handle Gamemode Switching
static void Minecraft_setIsCreativeMode_injection(unsigned char *this, int32_t new_game_mode) {
static void Minecraft_setIsCreativeMode_injection(Minecraft *this, int32_t new_game_mode) {
set_is_survival(!new_game_mode);
// Call Original Method
@ -36,7 +36,7 @@ static void Minecraft_setIsCreativeMode_injection(unsigned char *this, int32_t n
}
// Disable CreatorMode-Specific API Features (Polling Block Hits) In SurvivalMode, This Is Preferable To Crashing
static unsigned char *Minecraft_getCreator_injection(unsigned char *minecraft) {
static unsigned char *Minecraft_getCreator_injection(Minecraft *minecraft) {
if (is_survival) {
// SurvivalMode, Return NULL
return NULL;
@ -54,7 +54,7 @@ void init_game_mode() {
overwrite_calls((void *) Minecraft_setIsCreativeMode, (void *) Minecraft_setIsCreativeMode_injection);
// Replace CreatorLevel With ServerLevel (This Fixes Beds And Mob Spawning)
overwrite_call((void *) 0x16f84, (void *) ServerLevel);
overwrite_call((void *) 0x16f84, (void *) ServerLevel_constructor);
// Allocate Correct Size For ServerLevel
uint32_t level_size = SERVER_LEVEL_SIZE;

View File

@ -51,12 +51,12 @@ typedef enum {
DIALOG_OPEN,
DIALOG_SUCCESS
} create_world_state_dialog_t;
typedef struct {
struct create_world_state_t {
volatile create_world_state_dialog_t dialog_state = DIALOG_CLOSED;
volatile char *name = NULL;
volatile int32_t game_mode = 0;
volatile int32_t seed = 0;
} create_world_state_t;
};
static create_world_state_t create_world_state;
// Destructor
__attribute__((destructor)) static void _free_create_world_state_name() {
@ -80,9 +80,9 @@ static void reset_create_world_state() {
#define GAME_MODE_DIALOG_SIZE "200"
static void *create_world_thread(__attribute__((unused)) void *nop) {
// Run Dialogs
char *world_name = NULL;
{
// World Name
char *world_name = NULL;
{
// Open
const char *command[] = {
@ -201,6 +201,7 @@ static void *create_world_thread(__attribute__((unused)) void *nop) {
pthread_mutex_lock(&create_world_state_lock);
reset_create_world_state();
pthread_mutex_unlock(&create_world_state_lock);
free(world_name);
// Return
return NULL;
}
@ -214,15 +215,10 @@ static void open_create_world() {
pthread_create(&thread, NULL, create_world_thread, NULL);
}
// Get Minecraft From Screen
static unsigned char *get_minecraft_from_screen(unsigned char *screen) {
return *(unsigned char **) (screen + Screen_minecraft_property_offset);
}
// Create World
static void create_world(unsigned char *host_screen, std::string folder_name) {
static void create_world(Screen *host_screen, std::string folder_name) {
// Get Minecraft
unsigned char *minecraft = get_minecraft_from_screen(host_screen);
Minecraft *minecraft = host_screen->minecraft;
// Settings
LevelSettings settings;
@ -231,16 +227,16 @@ static void create_world(unsigned char *host_screen, std::string folder_name) {
// Create World
std::string world_name = (char *) create_world_state.name;
(*Minecraft_selectLevel)(minecraft, folder_name, world_name, settings);
minecraft->vtable->selectLevel(minecraft, &folder_name, &world_name, &settings);
// Multiplayer
(*Minecraft_hostMultiplayer)(minecraft, 19132);
// Open ProgressScreen
unsigned char *screen = (unsigned char *) ::operator new(PROGRESS_SCREEN_SIZE);
ProgressScreen *screen = alloc_ProgressScreen();
ALLOC_CHECK(screen);
screen = (*ProgressScreen)(screen);
(*Minecraft_setScreen)(minecraft, screen);
screen = (*ProgressScreen_constructor)(screen);
(*Minecraft_setScreen)(minecraft, (Screen *) screen);
// Reset
reset_create_world_state();
@ -248,11 +244,11 @@ static void create_world(unsigned char *host_screen, std::string folder_name) {
// Redirect Create World Button
#define create_SelectWorldScreen_tick_injection(prefix) \
static void prefix##SelectWorldScreen_tick_injection(unsigned char *screen) { \
static void prefix##SelectWorldScreen_tick_injection(prefix##SelectWorldScreen *screen) { \
/* Lock */ \
pthread_mutex_lock(&create_world_state_lock); \
\
bool *should_create_world = (bool *) (screen + prefix##SelectWorldScreen_should_create_world_property_offset); \
bool *should_create_world = &screen->should_create_world; \
if (*should_create_world) { \
/* Check State */ \
if (create_world_state.dialog_state == DIALOG_CLOSED) { \
@ -264,7 +260,7 @@ static void create_world(unsigned char *host_screen, std::string folder_name) {
*should_create_world = false; \
} else { \
/* Call Original Method */ \
(*prefix##SelectWorldScreen_tick)(screen); \
(*prefix##SelectWorldScreen_tick_non_virtual)(screen); \
} \
\
/* Create World If Dialog Succeeded */ \
@ -273,10 +269,10 @@ static void create_world(unsigned char *host_screen, std::string folder_name) {
\
/* Get New World Name */ \
std::string name = (char *) create_world_state.name; \
std::string new_name = (*prefix##SelectWorldScreen_getUniqueLevelName)(screen, name); \
std::string new_name = (*prefix##SelectWorldScreen_getUniqueLevelName)(screen, &name); \
\
/* Create World */ \
create_world(screen, new_name); \
create_world((Screen *) screen, new_name); \
} \
\
/* Lock/Unlock UI */ \

View File

@ -24,7 +24,7 @@ __attribute__((destructor)) static void _free_home() {
// Init
void init_home() {
// Store Data In ~/.minecraft-pi Instead Of ~/.minecraft
patch_address((void *) default_path, (void *) HOME_SUBDIRECTORY_FOR_GAME_DATA);
patch_address((void *) Strings_default_path, (void *) HOME_SUBDIRECTORY_FOR_GAME_DATA);
// The override code resolves assets manually,
// making changing directory redundant.

View File

@ -1,12 +1,12 @@
#include <libreborn/libreborn.h>
#include <mods/init/init.h>
#include <media-layer/core.h>
#include <symbols/minecraft.h>
__attribute__((constructor)) static void init() {
media_ensure_loaded();
run_tests();
init_symbols();
init_version();
init_compat();
#ifdef MCPI_SERVER_MODE

View File

@ -14,15 +14,15 @@ void input_set_is_left_click(int val) {
}
// Add Attacking To MouseBuildInput
static int32_t MouseBuildInput_tickBuild_injection(unsigned char *mouse_build_input, unsigned char *local_player, uint32_t *build_action_intention_return) {
static int32_t MouseBuildInput_tickBuild_injection(MouseBuildInput *mouse_build_input, Player *local_player, uint32_t *build_action_intention_return) {
// Call Original Method
int32_t ret = (*MouseBuildInput_tickBuild)(mouse_build_input, local_player, build_action_intention_return);
int32_t ret = (*MouseBuildInput_tickBuild_non_virtual)(mouse_build_input, local_player, build_action_intention_return);
// Use Attack/Place BuildActionIntention If No Other Valid BuildActionIntention Was Selected And This Was Not A Repeated Left Click
if (ret != 0 && is_left_click == 1 && *build_action_intention_return == 0xa) {
// Get Target HitResult
unsigned char *minecraft = *(unsigned char **) (local_player + LocalPlayer_minecraft_property_offset);
HitResult *hit_result = (HitResult *) (minecraft + Minecraft_hit_result_property_offset);
Minecraft *minecraft = ((LocalPlayer *) local_player)->minecraft;
HitResult *hit_result = &minecraft->hit_result;
int32_t hit_result_type = hit_result->type;
// Check if The Target Is An Entity Using HitResult
if (hit_result_type == 1) {
@ -37,14 +37,12 @@ static int32_t MouseBuildInput_tickBuild_injection(unsigned char *mouse_build_in
// Fix Holding Attack
static bool last_player_attack_successful = 0;
static bool Player_attack_Entity_hurt_injection(unsigned char *entity, unsigned char *attacker, int32_t damage) {
static bool Player_attack_Entity_hurt_injection(Entity *entity, Entity *attacker, int32_t damage) {
// Call Original Method
unsigned char *entity_vtable = *(unsigned char **) entity;
Entity_hurt_t Entity_hurt = *(Entity_hurt_t *) (entity_vtable + Entity_hurt_vtable_offset);
last_player_attack_successful = (*Entity_hurt)(entity, attacker, damage);
last_player_attack_successful = entity->vtable->hurt(entity, attacker, damage);
return last_player_attack_successful;
}
static ItemInstance *Player_attack_Inventory_getSelected_injection(unsigned char *inventory) {
static ItemInstance *Player_attack_Inventory_getSelected_injection(Inventory *inventory) {
// Check If Attack Was Successful
if (!last_player_attack_successful) {
return NULL;

View File

@ -15,16 +15,12 @@ void input_set_is_right_click(int val) {
static int fix_bow = 0;
// Handle Bow & Arrow
static void _handle_bow(unsigned char *minecraft) {
static void _handle_bow(Minecraft *minecraft) {
if (fix_bow && !is_right_click) {
// GameMode Is Offset From minecraft By 0x160
// Player Is Offset From minecraft By 0x18c
unsigned char *game_mode = *(unsigned char **) (minecraft + Minecraft_game_mode_property_offset);
unsigned char *player = *(unsigned char **) (minecraft + Minecraft_player_property_offset);
if (player != NULL && game_mode != NULL && (*Player_isUsingItem)(player)) {
unsigned char *game_mode_vtable = *(unsigned char **) game_mode;
GameMode_releaseUsingItem_t GameMode_releaseUsingItem = *(GameMode_releaseUsingItem_t *) (game_mode_vtable + GameMode_releaseUsingItem_vtable_offset);
(*GameMode_releaseUsingItem)(game_mode, player);
GameMode *game_mode = minecraft->game_mode;
LocalPlayer *player = minecraft->player;
if (player != NULL && game_mode != NULL && (*LocalPlayer_isUsingItem)(player)) {
game_mode->vtable->releaseUsingItem(game_mode, (Player *) player);
}
}
}

View File

@ -10,16 +10,16 @@ static int should_open_crafting = 0;
void input_open_crafting() {
should_open_crafting = 1;
}
static void _handle_open_crafting(unsigned char *minecraft) {
static void _handle_open_crafting(Minecraft *minecraft) {
if (should_open_crafting) {
should_open_crafting = 0;
// Set Screen
if (!creative_is_restricted() || !(*Minecraft_isCreativeMode)(minecraft)) {
unsigned char *screen = (unsigned char *) ::operator new(WORKBENCH_SCREEN_SIZE);
WorkbenchScreen *screen = alloc_WorkbenchScreen();
ALLOC_CHECK(screen);
screen = (*WorkbenchScreen)(screen, 0);
(*Minecraft_setScreen)(minecraft, screen);
screen = (*WorkbenchScreen_constructor)(screen, 0);
(*Minecraft_setScreen)(minecraft, (Screen *) screen