This commit is contained in:
Bigjango13 2024-04-07 20:04:41 -07:00
commit e03caceb6d
72 changed files with 1359 additions and 1484 deletions

@ -1 +1 @@
Subproject commit 225eb259fe00348044b7b9008a810204004701df
Subproject commit 67c4adaa772445f919f37131d7605bd374c67845

View File

@ -11,24 +11,53 @@ extern "C" {
void reborn_init_patch();
void _overwrite_call(const char *file, int line, void *start, void *target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target);
#define overwrite_call(start, target) _overwrite_call(__FILE__, __LINE__, start, target)
#define _setup_fancy_overwrite(start, name, target) \
if (!_is_new_method_##name()) { \
ERR("Method Is Not \"New\""); \
} \
static name##_t _original_for_##target = start; \
static name##_t _helper_for_##target = _overwrite_helper_for_##name(target, _original_for_##target)
#define _update_references(from, to) \
{ \
void *old_reference = (void *) from; \
for (int i = 0; _all_method_symbols[i] != nullptr; i++) { \
if (_all_method_symbols[i] == old_reference) { \
_all_method_symbols[i] = (void *) to; \
} \
} \
}
void _overwrite_calls(const char *file, int line, void *start, void *target);
#define overwrite_calls(start, target) _overwrite_calls(__FILE__, __LINE__, start, target);
#define overwrite_calls_manual(start, target) _overwrite_calls(__FILE__, __LINE__, start, target)
#define overwrite_calls(start, target) \
{ \
_setup_fancy_overwrite(start, start, target); \
overwrite_calls_manual((void *) start, (void *) _helper_for_##target); \
_update_references(start, _helper_for_##target); \
}
#define overwrite_virtual_calls(start, target) \
{ \
_setup_fancy_overwrite(*start##_vtable_addr, start, target); \
overwrite_calls_manual((void *) *start##_vtable_addr, (void *) _helper_for_##target); \
}
void _overwrite_calls_within(const char *file, int line, void *from, void *to, void *start, void *target);
#define overwrite_calls_within(from, to, start, target) _overwrite_calls_within(__FILE__, __LINE__, from, to, start, target);
#define overwrite_calls_within(from, to, start, target) _overwrite_calls_within(__FILE__, __LINE__, from, to, start, target)
void *extract_from_bl_instruction(unsigned char *from);
void _overwrite(const char *file, int line, void *start, void *target);
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, start, target);
#define overwrite(start, target) _overwrite(__FILE__, __LINE__, (void *) start, (void *) target)
void _patch(const char *file, int line, void *start, unsigned char patch[4]);
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch);
#define patch(start, patch) _patch(__FILE__, __LINE__, start, patch)
void _patch_address(const char *file, int line, void *start, void *target);
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, start, target);
#define patch_address(start, target) _patch_address(__FILE__, __LINE__, (void *) start, (void *) target)
#endif

View File

@ -16,6 +16,11 @@
}
// Hook Library Function
#ifdef __cplusplus
#define hooked_function_setup extern "C"
#else
#define hooked_function_setup
#endif
#define HOOK(name, return_type, args) \
typedef return_type (*name##_t)args; \
static name##_t real_##name = NULL; \
@ -30,7 +35,7 @@
} \
} \
\
__attribute__((__used__)) return_type name args
hooked_function_setup __attribute__((__used__)) return_type name args
#ifdef __cplusplus
extern "C" {

View File

@ -3,14 +3,14 @@ project(mods)
# Common Sources
set(SRC
# compat
src/compat/compat.c
src/compat/egl.c
src/compat/x11.c
src/compat/bcm_host.c
src/compat/compat.cpp
src/compat/egl.cpp
src/compat/x11.cpp
src/compat/bcm_host.cpp
# readdir
src/readdir/readdir.c
src/readdir/readdir.cpp
# feature
src/feature/feature.c
src/feature/feature.cpp
# version
src/version/version.cpp
# chat
@ -19,30 +19,28 @@ set(SRC
# creative
src/creative/creative.cpp
# game-mode
src/game-mode/game-mode.c
src/game-mode/game-mode.cpp
src/game-mode/ui.cpp
# override
src/override/override.c
src/override/override.cpp
# death
src/death/death.cpp
# misc
src/misc/misc.c
src/misc/misc.cpp
src/misc/logging.cpp
src/misc/api.cpp
# options
src/options/options.c
src/options/options.cpp
# bucket
src/bucket/bucket.cpp
# cake
src/cake/cake.cpp
# home
src/home/home.c
src/home/home.cpp
# test
src/test/test.c
src/test/test.cpp
# init
src/init/init.c
src/init/init.cpp
)
# Server-Only Sources
@ -76,10 +74,10 @@ else()
src/camera/camera.cpp
# input
src/input/input.cpp
src/input/bow.c
src/input/attack.c
src/input/toggle.c
src/input/misc.c
src/input/bow.cpp
src/input/attack.cpp
src/input/toggle.cpp
src/input/misc.cpp
src/input/drop.cpp
src/input/crafting.cpp
# sign
@ -95,7 +93,7 @@ else()
src/skin/skin.cpp
src/skin/loader.cpp
# screenshot
src/screenshot/screenshot.c
src/screenshot/screenshot.cpp
# textures
src/textures/textures.cpp
src/textures/lava.cpp

View File

@ -2,12 +2,4 @@
#include <symbols/minecraft.h>
#ifdef __cplusplus
extern "C" {
#endif
extern bool buckets_enabled;
#ifdef __cplusplus
}
#endif

View File

@ -1,22 +1,13 @@
#pragma once
#include <string>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#ifdef __cplusplus
#include <string>
// Send API Command
std::string chat_send_api_command(Minecraft *minecraft, std::string str);
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Override using the HOOK() macro to provide customized chat behavior.
void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, char *username, char *message);
void chat_handle_packet_send(Minecraft *minecraft, ChatPacket *packet);
#ifdef __cplusplus
}
#endif

View File

@ -1,12 +1,4 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int compat_check_exit_requested();
void compat_request_exit();
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
int creative_is_restricted();
#ifdef __cplusplus
}
#endif
int creative_is_restricted();

View File

@ -2,11 +2,7 @@
#include <libreborn/libreborn.h>
#ifdef __cplusplus
extern "C" {
#endif
int _feature_has(const char *name);
bool _feature_has(const char *name);
#ifdef MCPI_SERVER_MODE
#define _feature_has__server_defaul_is_server_disabled(name) 0
@ -16,7 +12,3 @@ int _feature_has(const char *name);
#else
#define feature_has(name, server_default) _feature_has(name)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
extern double fps;
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
char *home_get();
#ifdef __cplusplus
}
#endif

View File

@ -2,10 +2,6 @@
#include <libreborn/libreborn.h>
#ifdef __cplusplus
extern "C" {
#endif
void run_tests();
void init_version();
void init_compat();
@ -35,8 +31,4 @@ void init_options();
void init_chat();
void init_bucket();
void init_cake();
void init_home();
#ifdef __cplusplus
}
#endif
void init_home();

View File

@ -2,10 +2,6 @@
#include <symbols/minecraft.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*input_tick_function_t)(Minecraft *minecraft);
void input_run_on_tick(input_tick_function_t function);
@ -17,7 +13,3 @@ void input_open_crafting();
void input_set_is_left_click(int val);
void input_set_mouse_grab_state(int state);
#ifdef __cplusplus
}
#endif

View File

@ -1,13 +1,9 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <symbols/minecraft.h>
#ifdef __cplusplus
extern "C" {
#endif
int32_t misc_get_real_selected_slot(Player *player);
typedef void (*misc_update_function_Minecraft_t)(Minecraft *obj);
@ -26,13 +22,4 @@ void misc_run_on_language_setup(misc_update_function_void_t function); // obj ==
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
void Level_saveLevelData_injection(Level *level);
// Use this instead of directly calling Gui::addMessage(), it has proper logging!
void misc_add_message(Gui *gui, const char *text);
extern bool is_in_chat;
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
char *override_get_path(const char *filename);
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void screenshot_take(char *home);
#ifdef __cplusplus
}
#endif

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void sign_key_press(char key);
#ifdef __cplusplus
}
#endif
void sign_key_press(char key);

View File

@ -2,12 +2,4 @@
#include <GLES/gl.h>
#ifdef __cplusplus
extern "C" {
#endif
void glTexSubImage2D_with_scaling(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei normal_texture_width, GLsizei normal_texture_height, GLenum format, GLenum type, const void *pixels);
#ifdef __cplusplus
}
#endif

View File

@ -3,6 +3,4 @@
#include <string>
#include <vector>
extern "C" {
void title_screen_load_splashes(std::vector<std::string> &splashes);
}

View File

@ -1,11 +1,3 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
char *version_get();
#ifdef __cplusplus
}
#endif

View File

@ -7,13 +7,13 @@
#include <mods/init/init.h>
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
static void ItemRenderer_renderGuiItemCorrect_injection(Font *font, Textures *textures, ItemInstance *item_instance, int32_t param_1, int32_t param_2) {
static void ItemRenderer_renderGuiItemCorrect_injection(ItemRenderer_renderGuiItemCorrect_t original, 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;
if (item_instance != NULL) {
if (item_instance != nullptr) {
if (item_instance->id == leaves_id) {
ItemInstance_constructor_tile_extra(&carried_item_instance, Tile_leaves_carried, item_instance->count, item_instance->auxiliary);
use_carried = true;
@ -28,7 +28,7 @@ static void ItemRenderer_renderGuiItemCorrect_injection(Font *font, Textures *te
glDisable(GL_DEPTH_TEST);
// Call Original Method
ItemRenderer_renderGuiItemCorrect(font, textures, use_carried ? &carried_item_instance : item_instance, param_1, param_2);
original(font, textures, use_carried ? &carried_item_instance : item_instance, param_1, param_2);
// Revert GL State Changes
if (depth_test_was_enabled) {
@ -40,7 +40,7 @@ static void ItemRenderer_renderGuiItemCorrect_injection(Font *font, Textures *te
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(Tesselator *tesselator, int32_t r, int32_t g, int32_t b, int32_t a) {
static void Tesselator_color_injection(Tesselator_color_t original, 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
@ -55,16 +55,16 @@ static void Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_
}
// Call Original Method
Tesselator_color(tesselator, r, g, b, a);
original(tesselator, r, g, b, a);
}
static void Tesselator_begin_injection(Tesselator *tesselator, int32_t mode) {
static void Tesselator_begin_injection(Tesselator_begin_t original, Tesselator *tesselator, int32_t mode) {
// Call Original Method
Tesselator_begin(tesselator, mode);
original(tesselator, mode);
// Fix Furnace UI
if (item_color_fix_mode != 0) {
// Implict Translucent
Tesselator_color_injection(tesselator, 0xff, 0xff, 0xff, 0xff);
Tesselator_color(tesselator, 0xff, 0xff, 0xff, 0xff);
}
}
static void InventoryPane_renderBatch_Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_t g, int32_t b) {
@ -74,9 +74,9 @@ static void InventoryPane_renderBatch_Tesselator_color_injection(Tesselator *tes
// Enable Item Color Fix
item_color_fix_mode = 2;
}
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) {
static void ItemRenderer_renderGuiItem_two_injection(ItemRenderer_renderGuiItem_two_t original, 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);
original(font, textures, item_instance, param_1, param_2, param_3, param_4, param_5);
// Disable Item Color Fix
item_color_fix_mode = 0;
@ -91,18 +91,18 @@ static void FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection(Font *
// Init
void init_atlas() {
// Add Better NULL-Check (And More UI Fixes When The gui_blocks Atlas Is Disabled)
overwrite_calls((void *) ItemRenderer_renderGuiItem_two, (void *) ItemRenderer_renderGuiItem_two_injection);
// Add Better nullptr-Check (And More UI Fixes When The gui_blocks Atlas Is Disabled)
overwrite_calls(ItemRenderer_renderGuiItem_two, ItemRenderer_renderGuiItem_two_injection);
// Disable The gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory
if (feature_has("Disable \"gui_blocks\" Atlas", server_disabled)) {
unsigned char disable_gui_blocks_atlas_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x63c2c, disable_gui_blocks_atlas_patch);
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
overwrite_calls((void *) ItemRenderer_renderGuiItemCorrect, (void *) ItemRenderer_renderGuiItemCorrect_injection);
overwrite_calls(ItemRenderer_renderGuiItemCorrect, ItemRenderer_renderGuiItemCorrect_injection);
// Fix Furnace UI
overwrite_calls((void *) Tesselator_begin, (void *) Tesselator_begin_injection);
overwrite_calls((void *) Tesselator_color, (void *) Tesselator_color_injection);
overwrite_calls(Tesselator_begin, Tesselator_begin_injection);
overwrite_calls(Tesselator_color, Tesselator_color_injection);
overwrite_call((void *) 0x32324, (void *) FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection);
overwrite_call((void *) 0x1e21c, (void *) InventoryPane_renderBatch_Tesselator_color_injection);
}

View File

@ -64,7 +64,7 @@ static void Minecraft_tick_injection(__attribute__((unused)) Minecraft *minecraf
// Get Time
static long long int get_time() {
struct timespec ts;
timespec ts = {};
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
long long int a = (long long int) ts.tv_nsec;
long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;

View File

@ -7,7 +7,7 @@
#include <mods/bucket/bucket.h>
// Items
static FoodItem *bucket = NULL;
static FoodItem *bucket = nullptr;
// Description And Texture
static std::string BucketItem_getDescriptionId(__attribute__((unused)) FoodItem *item, ItemInstance *item_instance) {
@ -111,7 +111,7 @@ static int32_t BucketItem_useOn(__attribute__((unused)) FoodItem *item, ItemInst
// Get Current Tile
bool valid = false;
Material *material = level->vtable->getMaterial(level, x, y, z);
if (material != NULL) {
if (material != nullptr) {
valid = !material->vtable->isSolid(material);
}
if (item_instance->auxiliary != Tile_water->id && item_instance->auxiliary != Tile_lava->id) {
@ -136,7 +136,7 @@ static int BucketItem_getUseDuration(__attribute__((unused)) FoodItem *item, Ite
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);
*item_instance = (*FoodItem_useTimeDepleted_vtable_addr)(item, item_instance, level, player);
// Set it to a empty bucket
item_instance->auxiliary = 0;
item_instance->count = 1;
@ -161,7 +161,7 @@ static ItemInstance *BucketItem_use(FoodItem *item, ItemInstance *item_instance,
static ItemInstance *BucketItem_getCraftingRemainingItem(FoodItem *item, ItemInstance *item_instance) {
if (item_instance->auxiliary == 0) {
return NULL;
return nullptr;
}
ItemInstance *ret = alloc_ItemInstance();
ret->id = item->id;
@ -212,25 +212,25 @@ static void Item_initItems_injection(__attribute__((unused)) void *null) {
}
// Change Max Stack Size Based On Auxiliary
static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance *item_instance) {
static int32_t ItemInstance_getMaxStackSize_injection(ItemInstance_getMaxStackSize_t original, ItemInstance *item_instance) {
if (item_instance->id == bucket->id && item_instance->auxiliary == 0) {
// Custom Value
return 16;
} else {
// Call Original Method
return ItemInstance_getMaxStackSize(item_instance);
return original(item_instance);
}
}
// Milking
bool Cow_interact_injection(Cow *self, Player *player) {
bool Cow_interact_injection(Cow_interact_t original, 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);
return original(self, player);
}
// Creative Inventory
@ -255,7 +255,7 @@ static HitResult Mob_pick_Level_clip_injection(Level *level, unsigned char *para
}
static void handle_tick(Minecraft *minecraft) {
LocalPlayer *player = minecraft->player;
if (player != NULL) {
if (player != nullptr) {
// Get Selected Slot
int32_t selected_slot = misc_get_real_selected_slot((Player *) player);
Inventory *inventory = player->inventory;
@ -263,7 +263,7 @@ static void handle_tick(Minecraft *minecraft) {
// Get Item
ItemInstance *inventory_item = inventory->vtable->getItem(inventory, selected_slot);
// Check
is_holding_bucket = inventory_item != NULL && inventory_item->id == bucket->id && inventory_item->auxiliary == 0;
is_holding_bucket = inventory_item != nullptr && inventory_item->id == bucket->id && inventory_item->auxiliary == 0;
}
}
@ -277,10 +277,10 @@ static bool is_calm_liquid(int32_t id) {
return false;
}
}
static void Minecraft_handleMouseDown_injection(Minecraft *minecraft, int param_1, bool can_destroy) {
static void Minecraft_handleMouseDown_injection(Minecraft_handleMouseDown_t original, Minecraft *minecraft, int param_1, bool can_destroy) {
// Check
Level *level = minecraft->level;
if (level != NULL) {
if (level != nullptr) {
int32_t x = minecraft->hit_result.x;
int32_t y = minecraft->hit_result.y;
int32_t z = minecraft->hit_result.z;
@ -291,7 +291,7 @@ static void Minecraft_handleMouseDown_injection(Minecraft *minecraft, int param_
}
// Call Original Method
Minecraft_handleMouseDown(minecraft, param_1, can_destroy);
original(minecraft, param_1, can_destroy);
}
// Custom Crafting Recipes
@ -319,12 +319,12 @@ static void Recipes_injection(Recipes *recipes) {
}
// Custom Furnace Fuel
static int32_t FurnaceTileEntity_getBurnDuration_injection(ItemInstance *item_instance) {
static int32_t FurnaceTileEntity_getBurnDuration_injection(FurnaceTileEntity_getBurnDuration_t original, 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
return FurnaceTileEntity_getBurnDuration(item_instance);
return original(item_instance);
}
}
static void FurnaceTileEntity_tick_ItemInstance_setNull_injection(ItemInstance *item_instance) {
@ -353,20 +353,20 @@ void init_bucket() {
// 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);
overwrite_calls(ItemInstance_getMaxStackSize, ItemInstance_getMaxStackSize_injection);
// Enable milking
patch_address((void *) Cow_interact_vtable_addr, (void *) Cow_interact_injection);
overwrite_virtual_calls(Cow_interact, Cow_interact_injection);
// Creative Inventory
misc_run_on_creative_inventory_setup(Inventory_setupDefault_FillingContainer_addItem_call_injection);
// Make Liquids Selectable
overwrite_call((void *) 0x7f5b0, (void *) Mob_pick_Level_clip_injection);
misc_run_on_tick(handle_tick);
// Prevent Breaking Liquid
overwrite_calls((void *) Minecraft_handleMouseDown, (void *) Minecraft_handleMouseDown_injection);
overwrite_calls(Minecraft_handleMouseDown, Minecraft_handleMouseDown_injection);
// Custom Crafting Recipes
misc_run_on_recipes_setup(Recipes_injection);
// Custom Furnace Fuel
overwrite_calls((void *) FurnaceTileEntity_getBurnDuration, (void *) FurnaceTileEntity_getBurnDuration_injection);
overwrite_calls(FurnaceTileEntity_getBurnDuration, FurnaceTileEntity_getBurnDuration_injection);
overwrite_call((void *) 0xd351c, (void *) FurnaceTileEntity_tick_ItemInstance_setNull_injection);
// Language for milk
misc_run_on_language_setup(Language_injection);

View File

@ -6,7 +6,7 @@
#include <mods/misc/misc.h>
#include <mods/bucket/bucket.h>
static Tile *cake = NULL;
static Tile *cake = nullptr;
#define CAKE_LEN 0.0625F

View File

@ -7,16 +7,16 @@
#include <mods/init/init.h>
// Take Screenshot Using TripodCamera
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) {
static void AppPlatform_saveScreenshot_injection(__attribute__((unused)) AppPlatform_saveScreenshot_t original, __attribute__((unused)) AppPlatform *app_platform, __attribute__((unused)) std::string *path, __attribute__((unused)) int32_t width, __attribute__((unused)) int32_t height) {
#ifndef MCPI_HEADLESS_MODE
screenshot_take(home_get());
#endif
}
// Enable TripodCameraRenderer
static EntityRenderDispatcher *EntityRenderDispatcher_injection(EntityRenderDispatcher *dispatcher) {
static EntityRenderDispatcher *EntityRenderDispatcher_injection(EntityRenderDispatcher_constructor_t original, EntityRenderDispatcher *dispatcher) {
// Call Original Method
EntityRenderDispatcher_constructor(dispatcher);
original(dispatcher);
// Register TripodCameraRenderer
TripodCameraRenderer *renderer = alloc_TripodCameraRenderer();
@ -36,12 +36,12 @@ static void TripodCamera_tick_Level_addParticle_call_injection(Level *level, std
// Init
void init_camera() {
// Implement AppPlatform_linux::saveScreenshot So Cameras Work
patch_address(AppPlatform_linux_saveScreenshot_vtable_addr, (void *) AppPlatform_linux_saveScreenshot_injection);
overwrite_virtual_calls(AppPlatform_saveScreenshot, AppPlatform_saveScreenshot_injection);
// Fix Camera Rendering
if (feature_has("Fix Camera Rendering", server_disabled)) {
// Enable TripodCameraRenderer
overwrite_calls((void *) EntityRenderDispatcher_constructor, (void *) EntityRenderDispatcher_injection);
overwrite_calls(EntityRenderDispatcher_constructor, EntityRenderDispatcher_injection);
// Display Smoke From TripodCamera Higher
overwrite_call((void *) 0x87dc4, (void *) TripodCamera_tick_Level_addParticle_call_injection);
}

View File

@ -21,12 +21,12 @@
// Send API Command
std::string chat_send_api_command(Minecraft *minecraft, std::string str) {
struct ConnectedClient client;
ConnectedClient client;
client.sock = -1;
client.str = "";
client.time = 0;
CommandServer *command_server = minecraft->command_server;
if (command_server != NULL) {
if (command_server != nullptr) {
return CommandServer_parse(command_server, &client, &str);
} else {
return "";
@ -36,7 +36,7 @@ std::string chat_send_api_command(Minecraft *minecraft, std::string str) {
#ifndef MCPI_HEADLESS_MODE
// Send API Chat Command
static void send_api_chat_command(Minecraft *minecraft, char *str) {
char *command = NULL;
char *command = nullptr;
safe_asprintf(&command, "chat.post(%s)\n", str);
chat_send_api_command(minecraft, command);
free(command);
@ -48,7 +48,7 @@ std::string _chat_get_prefix(char *username) {
return std::string("<") + username + "> ";
}
void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, char *username, char *message) {
char *full_message = NULL;
char *full_message = nullptr;
safe_asprintf(&full_message, "%s%s", _chat_get_prefix(username).c_str(), message);
sanitize_string(&full_message, MAX_CHAT_MESSAGE_LENGTH, 0);
std::string cpp_string = full_message;
@ -72,7 +72,7 @@ void chat_handle_packet_send(Minecraft *minecraft, ChatPacket *packet) {
// Manually Send (And Loopback) ChatPacket
static void CommandServer_parse_CommandServer_dispatchPacket_injection(CommandServer *command_server, Packet *packet) {
Minecraft *minecraft = command_server->minecraft;
if (minecraft != NULL) {
if (minecraft != nullptr) {
chat_handle_packet_send(minecraft, (ChatPacket *) packet);
}
}
@ -80,7 +80,7 @@ static void CommandServer_parse_CommandServer_dispatchPacket_injection(CommandSe
// Handle ChatPacket Server-Side
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) {
if (player != nullptr) {
const char *username = player->username.c_str();
const char *message = chat_packet->message.c_str();
chat_send_message(server_side_network_handler, (char *) username, (char *) message);
@ -116,7 +116,7 @@ void init_chat() {
// Manually Send (And Loopback) ChatPacket
overwrite_call((void *) 0x6b518, (void *) CommandServer_parse_CommandServer_dispatchPacket_injection);
// Re-Broadcast ChatPacket
patch_address(ServerSideNetworkHandler_handle_ChatPacket_vtable_addr, (void *) ServerSideNetworkHandler_handle_ChatPacket_injection);
patch_address(ServerSideNetworkHandler_handle_ChatPacket_vtable_addr, ServerSideNetworkHandler_handle_ChatPacket_injection);
#ifndef MCPI_HEADLESS_MODE
// Send Messages On Input Tick
input_run_on_tick(send_queued_messages);

View File

@ -69,8 +69,9 @@ CUSTOM_VTABLE(chat_screen, Screen) {
original_render(super, x, y, param_1);
};
// Positioning
static Screen_setupPositions_t original_setupPositions = vtable->setupPositions;
vtable->setupPositions = [](Screen *super) {
Screen_setupPositions_non_virtual(super);
original_setupPositions(super);
ChatScreen *self = (ChatScreen *) super;
self->send->height = 24;
self->send->width = 40;
@ -95,7 +96,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
}
_chat_queue_message(text.c_str());
}
Minecraft_setScreen(super->minecraft, NULL);
Minecraft_setScreen(super->minecraft, nullptr);
} else if (key == 0x26) {
// Up
local_history.at(self->history_pos) = self->chat->getText();
@ -118,6 +119,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
original_keyPressed(super, key);
};
// Button Click
static Screen_buttonClicked_t original_buttonClicked = vtable->buttonClicked;
vtable->buttonClicked = [](Screen *super, Button *button) {
ChatScreen *self = (ChatScreen *) super;
if (button == self->send) {
@ -126,7 +128,7 @@ CUSTOM_VTABLE(chat_screen, Screen) {
super->vtable->keyPressed(super, 0x0d);
} else {
// Call Original Method
Screen_buttonClicked_non_virtual(super, button);
original_buttonClicked(super, button);
}
};
}
@ -147,7 +149,7 @@ static Screen *create_chat_screen() {
void _init_chat_ui() {
misc_run_on_game_key_press([](Minecraft *minecraft, int key) {
if (key == 0x54) {
if (Minecraft_isLevelGenerated(minecraft) && minecraft->screen == NULL) {
if (Minecraft_isLevelGenerated(minecraft) && minecraft->screen == nullptr) {
Minecraft_setScreen(minecraft, create_chat_screen());
}
return true;

View File

@ -1,6 +1,6 @@
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <csignal>
#include <cerrno>
#include <mods/compat/compat.h>
#include <mods/screenshot/screenshot.h>
@ -51,7 +51,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
int ret = real_SDL_PollEvent(event);
// Handle Events
if (ret == 1 && event != NULL) {
if (ret == 1 && event != nullptr) {
int handled = 0;
#ifndef MCPI_HEADLESS_MODE
@ -116,11 +116,10 @@ static void exit_handler(__attribute__((unused)) int data) {
void init_compat() {
// Install Signal Handlers
signal(SIGINT, SIG_IGN);
struct sigaction act_sigterm;
memset((void *) &act_sigterm, 0, sizeof (struct sigaction));
struct sigaction act_sigterm = {};
act_sigterm.sa_flags = SA_RESTART;
act_sigterm.sa_handler = &exit_handler;
sigaction(SIGTERM, &act_sigterm, NULL);
sigaction(SIGTERM, &act_sigterm, nullptr);
// Patches
_patch_egl_calls();
_patch_x11_calls();

View File

@ -6,13 +6,13 @@
// Functions That Have Their Return Values Used
static EGLSurface eglCreateWindowSurface_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) NativeWindowType native_window, __attribute__((unused)) EGLint const *attrib_list) {
return 0;
return nullptr;
}
static EGLDisplay eglGetDisplay_injection(__attribute__((unused)) NativeDisplayType native_display) {
return 0;
return nullptr;
}
static EGLContext eglCreateContext_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLConfig config, __attribute__((unused)) EGLContext share_context, __attribute__((unused)) EGLint const *attrib_list) {
return 0;
return nullptr;
}
// Call media_swap_buffers()
static EGLBoolean eglSwapBuffers_injection(__attribute__((unused)) EGLDisplay display, __attribute__((unused)) EGLSurface surface) {

View File

@ -13,7 +13,7 @@ static int XTranslateCoordinates_injection(__attribute__((unused)) void *display
}
static int XGetWindowAttributes_injection(__attribute__((unused)) void *display, __attribute__((unused)) XID w, XWindowAttributes *window_attributes_return) {
// Use MCPI Replacemnt Function
XWindowAttributes attributes;
XWindowAttributes attributes = {};
attributes.x = 0;
attributes.y = 0;
media_get_framebuffer_size(&attributes.width, &attributes.height);

View File

@ -65,19 +65,19 @@ std::string get_death_message(Player *player, Entity *cause, bool was_shot = fal
}
static bool is_hurt = false;
static bool Mob_hurt_injection(Mob *mob, Entity *source, int dmg) {
// Call Original Method
static bool Mob_hurt_injection(Mob_hurt_t original, Mob *mob, Entity *source, int dmg) {
is_hurt = true;
bool ret = Mob_hurt_non_virtual(mob, source, dmg);
bool ret = original(mob, source, dmg);
is_hurt = false;
return ret;
}
// Death Message Logic
#define Player_death_injections(type) \
static void type##Player_die_injection(type##Player *player, Entity *cause) { \
#define Player_die_injections(type) \
static type##_die_t original_##type##_die; \
static void type##_die_injection(type *player, Entity *cause) { \
/* Call Original Method */ \
type##Player_die_non_virtual(player, cause); \
original_##type##_die(player, cause); \
\
/* Get Variable */ \
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
@ -90,14 +90,14 @@ static bool Mob_hurt_injection(Mob *mob, Entity *source, int dmg) {
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) { \
}
#define Player_actuallyHurt_injections(type) \
static void type##_actuallyHurt_injection(type *player, int32_t damage) { \
/* Store Old Health */ \
int32_t old_health = player->health; \
\
/* Call Original Method */ \
type##Player_actuallyHurt_non_virtual(player, damage); \
(*Mob_actuallyHurt_vtable_addr)((Mob *) player, damage); \
if (is_hurt == true) return; \
\
/* Store New Health */ \
@ -110,7 +110,7 @@ static bool Mob_hurt_injection(Mob *mob, Entity *source, int dmg) {
/* Check Health */ \
if (new_health < 1 && old_health >= 1) { \
/* Get Death Message */ \
std::string message = get_death_message((Player *) player, NULL); \
std::string message = get_death_message((Player *) player, nullptr); \
\
/* Post Death Message */ \
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \
@ -119,22 +119,25 @@ static bool Mob_hurt_injection(Mob *mob, Entity *source, int dmg) {
} \
}
Player_death_injections(Local);
Player_death_injections(Server);
Player_die_injections(LocalPlayer)
Player_die_injections(ServerPlayer)
Player_actuallyHurt_injections(LocalPlayer)
Player_actuallyHurt_injections(ServerPlayer)
// 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);
overwrite_calls((void *) Mob_hurt_non_virtual, (void *) Mob_hurt_injection);
patch_address(ServerPlayer_die_vtable_addr, ServerPlayer_die_injection);
patch_address(LocalPlayer_die_vtable_addr, LocalPlayer_die_injection);
patch_address(LocalPlayer_actuallyHurt_vtable_addr, LocalPlayer_actuallyHurt_injection);
patch_address(ServerPlayer_actuallyHurt_vtable_addr, ServerPlayer_actuallyHurt_injection);
overwrite_virtual_calls(Mob_hurt, 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)
// This changes PrimedTnt_explode from Level::explode(nullptr, x, y, z, 3.1f) to Level::explode(this, x, y, z, 3.1f)
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]"

View File

@ -6,18 +6,18 @@
#include <mods/feature/feature.h>
// Check For Feature
int _feature_has(const char *name) {
bool _feature_has(const char *name) {
// Get Value
char *env = getenv("MCPI_FEATURE_FLAGS");
char *features = strdup(env != NULL ? env : "");
char *features = strdup(env != nullptr ? env : "");
char *tok = strtok(features, "|");
int ret = 0;
while (tok != NULL) {
bool ret = false;
while (tok != nullptr) {
if (strcmp(tok, name) == 0) {
ret = 1;
ret = true;
break;
}
tok = strtok(NULL, "|");
tok = strtok(nullptr, "|");
}
free(features);

View File

@ -9,7 +9,7 @@
// Track FPS
#define NANOSECONDS_IN_SECOND 1000000000ll
static long long int get_time() {
struct timespec ts;
timespec ts = {};
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
long long int a = (long long int) ts.tv_nsec;
long long int b = ((long long int) ts.tv_sec) * NANOSECONDS_IN_SECOND;

View File

@ -8,16 +8,16 @@
static int is_survival = -1;
// Patch Game Mode
static void set_is_survival(int new_is_survival) {
static void set_is_survival(bool new_is_survival) {
if (is_survival != new_is_survival) {
DEBUG("Setting Game Mode: %s", new_is_survival ? "Survival" : "Creative");
// Correct Inventpry UI
unsigned char inventory_patch[4] = {new_is_survival ? 0x00 : 0x01, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0" or "mov r3, #0x1"
unsigned char inventory_patch[4] = {(unsigned char) (new_is_survival ? 0x00 : 0x01), 0x30, 0xa0, 0xe3}; // "mov r3, #0x0" or "mov r3, #0x1"
patch((void *) 0x16efc, inventory_patch);
// Use Correct Size For GameMode Object
unsigned char size_patch[4] = {new_is_survival ? SURVIVAL_MODE_SIZE : CREATOR_MODE_SIZE, 0x00, 0xa0, 0xe3}; // "mov r0, #SURVIVAL_MODE_SIZE" or "mov r0, #CREATOR_MODE_SIZE"
unsigned char size_patch[4] = {(unsigned char) (new_is_survival ? SURVIVAL_MODE_SIZE : CREATOR_MODE_SIZE), 0x00, 0xa0, 0xe3}; // "mov r0, #SURVIVAL_MODE_SIZE" or "mov r0, #CREATOR_MODE_SIZE"
patch((void *) 0x16ee4, size_patch);
// Replace Default CreatorMode Constructor With CreatorMode Or SurvivalMode Constructor
@ -28,21 +28,21 @@ static void set_is_survival(int new_is_survival) {
}
// Handle Gamemode Switching
static void Minecraft_setIsCreativeMode_injection(Minecraft *this, int32_t new_game_mode) {
static void Minecraft_setIsCreativeMode_injection(Minecraft_setIsCreativeMode_t original, Minecraft *self, int32_t new_game_mode) {
set_is_survival(!new_game_mode);
// Call Original Method
Minecraft_setIsCreativeMode(this, new_game_mode);
original(self, new_game_mode);
}
// Disable CreatorMode-Specific API Features (Polling Block Hits) In SurvivalMode, This Is Preferable To Crashing
static unsigned char *Minecraft_getCreator_injection(Minecraft *minecraft) {
static unsigned char *Minecraft_getCreator_injection(Minecraft_getCreator_t original, Minecraft *minecraft) {
if (is_survival) {
// SurvivalMode, Return NULL
return NULL;
// SurvivalMode, Return nullptr
return nullptr;
} else {
// CreatorMode, Call Original Method
return Minecraft_getCreator(minecraft);
return original(minecraft);
}
}
@ -50,8 +50,8 @@ static unsigned char *Minecraft_getCreator_injection(Minecraft *minecraft) {
void init_game_mode() {
// Dynamic Game Mode Switching
if (feature_has("Implement Game-Mode Switching", server_enabled)) {
set_is_survival(1);
overwrite_calls((void *) Minecraft_setIsCreativeMode, (void *) Minecraft_setIsCreativeMode_injection);
set_is_survival(true);
overwrite_calls(Minecraft_setIsCreativeMode, Minecraft_setIsCreativeMode_injection);
// Replace CreatorLevel With ServerLevel (This Fixes Beds And Mob Spawning)
overwrite_call((void *) 0x16f84, (void *) ServerLevel_constructor);
@ -61,7 +61,7 @@ void init_game_mode() {
patch_address((void *) 0x17004, (void *) level_size);
// Disable CreatorMode-Specific API Features (Polling Block Hits) In SurvivalMode, This Is Preferable To Crashing
overwrite_calls((void *) Minecraft_getCreator, (void *) Minecraft_getCreator_injection);
overwrite_calls(Minecraft_getCreator, Minecraft_getCreator_injection);
}
// Create World Dialog

View File

@ -92,8 +92,9 @@ CUSTOM_VTABLE(create_world_screen, Screen) {
Screen_drawString(super, super->font, &description, self->game_mode->x, self->game_mode->y + self->game_mode->height + description_padding, 0xa0a0a0);
};
// Positioning
static Screen_setupPositions_t original_setupPositions = vtable->setupPositions;
vtable->setupPositions = [](Screen *super) {
Screen_setupPositions_non_virtual(super);
original_setupPositions(super);
CreateWorldScreen *self = (CreateWorldScreen *) super;
// Height/Width
int width = 120;
@ -234,7 +235,7 @@ static void create_world(Minecraft *minecraft, std::string name, bool is_creativ
// Redirect Create World Button
#define create_SelectWorldScreen_tick_injection(prefix) \
static void prefix##SelectWorldScreen_tick_injection(prefix##SelectWorldScreen *screen) { \
static void prefix##SelectWorldScreen_tick_injection(prefix##SelectWorldScreen_tick_t original, prefix##SelectWorldScreen *screen) { \
if (screen->should_create_world) { \
/* Open Screen */ \
Minecraft_setScreen(screen->minecraft, create_create_world_screen()); \
@ -242,7 +243,7 @@ static void create_world(Minecraft *minecraft, std::string name, bool is_creativ
screen->should_create_world = false; \
} else { \
/* Call Original Method */ \
prefix##SelectWorldScreen_tick_non_virtual(screen); \
original(screen); \
} \
}
create_SelectWorldScreen_tick_injection()
@ -251,8 +252,8 @@ create_SelectWorldScreen_tick_injection(Touch_)
// Init
void _init_game_mode_ui() {
// Hijack Create World Button
patch_address(SelectWorldScreen_tick_vtable_addr, (void *) SelectWorldScreen_tick_injection);
patch_address(Touch_SelectWorldScreen_tick_vtable_addr, (void *) Touch_SelectWorldScreen_tick_injection);
overwrite_virtual_calls(SelectWorldScreen_tick, SelectWorldScreen_tick_injection);
overwrite_virtual_calls(Touch_SelectWorldScreen_tick, Touch_SelectWorldScreen_tick_injection);
}
#else

View File

@ -1,4 +1,4 @@
#include <errno.h>
#include <cerrno>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
@ -8,9 +8,9 @@
// Get MCPI Home Directory
char *home_get() {
static char *dir = NULL;
static char *dir = nullptr;
// Load
if (dir == NULL) {
if (dir == nullptr) {
safe_asprintf(&dir, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA, getenv("HOME"));
}
// Return

View File

@ -14,9 +14,9 @@ void input_set_is_left_click(int val) {
}
// Add Attacking To MouseBuildInput
static int32_t MouseBuildInput_tickBuild_injection(MouseBuildInput *mouse_build_input, Player *local_player, uint32_t *build_action_intention_return) {
static int32_t MouseBuildInput_tickBuild_injection(MouseBuildInput_tickBuild_t original, MouseBuildInput *mouse_build_input, Player *local_player, uint32_t *build_action_intention_return) {
// Call Original Method
int32_t ret = MouseBuildInput_tickBuild_non_virtual(mouse_build_input, local_player, build_action_intention_return);
int32_t ret = original(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) {
@ -36,7 +36,7 @@ static int32_t MouseBuildInput_tickBuild_injection(MouseBuildInput *mouse_build_
}
// Fix Holding Attack
static bool last_player_attack_successful = 0;
static bool last_player_attack_successful = false;
static bool Player_attack_Entity_hurt_injection(Entity *entity, Entity *attacker, int32_t damage) {
// Call Original Method
last_player_attack_successful = entity->vtable->hurt(entity, attacker, damage);
@ -45,7 +45,7 @@ static bool Player_attack_Entity_hurt_injection(Entity *entity, Entity *attacker
static ItemInstance *Player_attack_Inventory_getSelected_injection(Inventory *inventory) {
// Check If Attack Was Successful
if (!last_player_attack_successful) {
return NULL;
return nullptr;
}
// Call Original Method
@ -56,7 +56,7 @@ static ItemInstance *Player_attack_Inventory_getSelected_injection(Inventory *in
void _init_attack() {
// Allow Attacking Mobs
if (feature_has("Fix Attacking", server_disabled)) {
patch_address(MouseBuildInput_tickBuild_vtable_addr, (void *) MouseBuildInput_tickBuild_injection);
overwrite_virtual_calls(MouseBuildInput_tickBuild, MouseBuildInput_tickBuild_injection);
// Fix Holding Attack
overwrite_call((void *) 0x8fc1c, (void *) Player_attack_Entity_hurt_injection);

View File

@ -19,7 +19,7 @@ static void _handle_bow(Minecraft *minecraft) {
if (fix_bow && !is_right_click) {
GameMode *game_mode = minecraft->game_mode;
LocalPlayer *player = minecraft->player;
if (player != NULL && game_mode != NULL && LocalPlayer_isUsingItem(player)) {
if (player != nullptr && game_mode != nullptr && LocalPlayer_isUsingItem(player)) {
game_mode->vtable->releaseUsingItem(game_mode, (Player *) player);
}
}

View File

@ -25,10 +25,10 @@ void input_drop(int drop_slot) {
// Handle Drop Item Presses
static void _handle_drop(Minecraft *minecraft) {
if ((minecraft->screen == NULL) && (!creative_is_restricted() || !Minecraft_isCreativeMode(minecraft)) && (drop_item_presses > 0 || drop_slot_pressed)) {
if ((minecraft->screen == nullptr) && (!creative_is_restricted() || !Minecraft_isCreativeMode(minecraft)) && (drop_item_presses > 0 || drop_slot_pressed)) {
// Get Player
LocalPlayer *player = minecraft->player;
if (player != NULL) {
if (player != nullptr) {
// Get Selected Slot
int32_t selected_slot = misc_get_real_selected_slot((Player *) player);
Inventory *inventory = player->inventory;
@ -36,7 +36,7 @@ static void _handle_drop(Minecraft *minecraft) {
// Get Item
ItemInstance *inventory_item = inventory->vtable->getItem(inventory, selected_slot);
// Check
if (inventory_item != NULL && inventory_item->count > 0) {
if (inventory_item != nullptr && inventory_item->count > 0) {
// Copy
ItemInstance *dropped_item = new ItemInstance;
ALLOC_CHECK(dropped_item);

View File

@ -19,9 +19,9 @@ void input_run_on_tick(input_tick_function_t function) {
}
// Handle Input Fixes
static void Minecraft_tickInput_injection(Minecraft *minecraft) {
static void Minecraft_tickInput_injection(Minecraft_tickInput_t original, Minecraft *minecraft) {
// Call Original Method
Minecraft_tickInput(minecraft);
original(minecraft);
// Run Input Tick Functions
for (input_tick_function_t function : get_input_tick_functions()) {
@ -44,7 +44,7 @@ void init_input() {
_init_bow();
// Loop
overwrite_calls((void *) Minecraft_tickInput, (void *) Minecraft_tickInput_injection);
overwrite_calls(Minecraft_tickInput, Minecraft_tickInput_injection);
// Allow Attacking Mobs
_init_attack();

View File

@ -22,8 +22,8 @@ int input_back() {
// Handle Back Button Presses
static void _handle_back(Minecraft *minecraft) {
// If Minecraft's Level property is initialized, but Minecraft's Player property is NULL, then Minecraft::handleBack may crash.
if (minecraft->level != NULL && minecraft->player == NULL) {
// If Minecraft's Level property is initialized, but Minecraft's Player property is nullptr, then Minecraft::handleBack may crash.
if (minecraft->level != nullptr && minecraft->player == nullptr) {
// Unable to safely run Minecraft::handleBack, deferring until safe.
return;
}
@ -38,24 +38,24 @@ static void _handle_back(Minecraft *minecraft) {
static bool OptionsScreen_handleBackEvent_injection(OptionsScreen *screen, bool do_nothing) {
if (!do_nothing) {
Minecraft *minecraft = screen->minecraft;
Minecraft_setScreen(minecraft, NULL);
Minecraft_setScreen(minecraft, nullptr);
}
return 1;
return true;
}
// Fix "Sleeping Beauty" Bug
static int32_t InBedScreen_handleBackEvent_injection(InBedScreen *screen, bool do_nothing) {
static bool InBedScreen_handleBackEvent_injection(InBedScreen *screen, bool do_nothing) {
if (!do_nothing) {
// Close Screen
Minecraft *minecraft = screen->minecraft;
Minecraft_setScreen(minecraft, NULL);
Minecraft_setScreen(minecraft, nullptr);
// Stop Sleeping
LocalPlayer *player = minecraft->player;
if (player != NULL) {
if (player != nullptr) {
player->vtable->stopSleepInBed(player, 1, 1, 1);
}
}
return 1;
return true;
}
// Set Mouse Grab State
@ -80,7 +80,7 @@ static void _handle_mouse_grab(Minecraft *minecraft) {
// Block UI Interaction When Mouse Is Locked
static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(Minecraft *minecraft) {
bool is_in_game = minecraft->screen == NULL || minecraft->screen->vtable == (Screen_vtable *) Touch_IngameBlockSelectionScreen_vtable_base;
bool is_in_game = minecraft->screen == nullptr || minecraft->screen->vtable == (Screen_vtable *) Touch_IngameBlockSelectionScreen_vtable_base;
if (!enable_misc || (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF && is_in_game)) {
// Call Original Method
return creative_is_restricted() && Minecraft_isCreativeMode(minecraft);
@ -91,10 +91,10 @@ static bool Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection(Minecraft *
}
// Block UI Interaction When Mouse Is Locked
static void Gui_handleClick_injection(Gui *gui, int32_t param_2, int32_t param_3, int32_t param_4) {
static void Gui_handleClick_injection(Gui_handleClick_t original, Gui *gui, int32_t param_2, int32_t param_3, int32_t param_4) {
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
// Call Original Method
Gui_handleClick(gui, param_2, param_3, param_4);
original(gui, param_2, param_3, param_4);
}
}
@ -103,11 +103,11 @@ void _init_misc() {
enable_misc = feature_has("Miscellaneous Input Fixes", server_disabled);
if (enable_misc) {
// Fix OptionsScreen Ignoring The Back Button
patch_address(OptionsScreen_handleBackEvent_vtable_addr, (void *) OptionsScreen_handleBackEvent_injection);
patch_address(OptionsScreen_handleBackEvent_vtable_addr, OptionsScreen_handleBackEvent_injection);
// Fix "Sleeping Beauty" Bug
patch_address(InBedScreen_handleBackEvent_vtable_addr, (void *) InBedScreen_handleBackEvent_injection);
patch_address(InBedScreen_handleBackEvent_vtable_addr, InBedScreen_handleBackEvent_injection);
// Disable Opening Inventory Using The Cursor When Cursor Is Hidden
overwrite_calls((void *) Gui_handleClick, (void *) Gui_handleClick_injection);
overwrite_calls(Gui_handleClick, Gui_handleClick_injection);
}
// Disable Item Dropping Using The Cursor When Cursor Is Hidden
overwrite_call((void *) 0x27800, (void *) Gui_tickItemDrop_Minecraft_isCreativeMode_call_injection);

View File

@ -12,13 +12,13 @@ static bool _handle_toggle_options(Minecraft *minecraft, int key) {
if (key == 0x70) {
// Toggle Hide GUI
options->hide_gui = options->hide_gui ^ 1;
return 1;
return true;
} else if (key == 0x74) {
// Toggle Third Person
options->third_person = (options->third_person + 1) % 3;
return 1;
return true;
} else {
return 0;
return false;
}
}
static void _fix_third_person(Minecraft *minecraft) {
@ -32,7 +32,7 @@ static void _fix_third_person(Minecraft *minecraft) {
// Font-Facing View
static void invert_rotation(Entity *entity) {
if (entity != NULL) {
if (entity != nullptr) {
entity->yaw = 180.f + entity->yaw;
entity->old_yaw = 180.f + entity->old_yaw;
entity->pitch = -entity->pitch;
@ -40,7 +40,7 @@ static void invert_rotation(Entity *entity) {
}
}
static void revert_rotation(Entity *entity) {
if (entity != NULL) {
if (entity != nullptr) {
entity->yaw = -180.f + entity->yaw;
entity->old_yaw = -180.f + entity->old_yaw;
entity->pitch = -entity->pitch;
@ -48,8 +48,8 @@ static void revert_rotation(Entity *entity) {
}
}
static int is_front_facing = 0;
static LocalPlayer *stored_player = NULL;
static void GameRenderer_setupCamera_injection(GameRenderer *game_renderer, float param_1, int param_2) {
static LocalPlayer *stored_player = nullptr;
static void GameRenderer_setupCamera_injection(GameRenderer_setupCamera_t original, GameRenderer *game_renderer, float param_1, int param_2) {
// Get Objects
Minecraft *minecraft = game_renderer->minecraft;
stored_player = minecraft->player;
@ -64,21 +64,21 @@ static void GameRenderer_setupCamera_injection(GameRenderer *game_renderer, floa
}
// Call Original Method
GameRenderer_setupCamera(game_renderer, param_1, param_2);
original(game_renderer, param_1, param_2);
// Revert
if (is_front_facing) {
revert_rotation((Entity *) stored_player);
}
}
static void ParticleEngine_render_injection(ParticleEngine *particle_engine, Entity *entity, float param_2) {
static void ParticleEngine_render_injection(ParticleEngine_render_t original, ParticleEngine *particle_engine, Entity *entity, float param_2) {
// Invert Rotation
if (is_front_facing && (Entity *) stored_player == entity) {
invert_rotation((Entity *) stored_player);
}
// Call Original Method
ParticleEngine_render(particle_engine, entity, param_2);
original(particle_engine, entity, param_2);
// Revert
if (is_front_facing && (Entity *) stored_player == entity) {
@ -93,7 +93,7 @@ void _init_toggle() {
misc_run_on_update(_fix_third_person);
// Font-Facing View
overwrite_calls((void *) GameRenderer_setupCamera, (void *) GameRenderer_setupCamera_injection);
overwrite_calls((void *) ParticleEngine_render, (void *) ParticleEngine_render_injection);
overwrite_calls(GameRenderer_setupCamera, GameRenderer_setupCamera_injection);
overwrite_calls(ParticleEngine_render, ParticleEngine_render_injection);
}
}

View File

@ -1,3 +1,4 @@
#include <utility>
#include <vector>
#include <libreborn/libreborn.h>
@ -26,9 +27,9 @@
// Run Functions On Update
SETUP_CALLBACK(update, Minecraft);
// Handle Custom Update Behavior
static void Minecraft_update_injection(Minecraft *minecraft) {
static void Minecraft_update_injection(Minecraft_update_t original, Minecraft *minecraft) {
// Call Original Method
Minecraft_update_non_virtual(minecraft);
original(minecraft);
// Run Functions
handle_misc_update(minecraft);
@ -37,9 +38,9 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
// Run Functions On Tick
SETUP_CALLBACK(tick, Minecraft);
// Handle Custom Tick Behavior
static void Minecraft_tick_injection(Minecraft *minecraft, int32_t param_1, int32_t param_2) {
static void Minecraft_tick_injection(Minecraft_tick_t original, Minecraft *minecraft, int32_t param_1, int32_t param_2) {
// Call Original Method
Minecraft_tick(minecraft, param_1, param_2);
original(minecraft, param_1, param_2);
// Run Functions
handle_misc_tick(minecraft);
@ -48,9 +49,9 @@ static void Minecraft_tick_injection(Minecraft *minecraft, int32_t param_1, int3
// Run Functions On Recipes Setup
SETUP_CALLBACK(recipes_setup, Recipes);
// Handle Custom Recipes Setup Behavior
static Recipes *Recipes_injection(Recipes *recipes) {
static Recipes *Recipes_injection(Recipes_constructor_t original, Recipes *recipes) {
// Call Original Method
Recipes_constructor(recipes);
original(recipes);
// Run Functions
handle_misc_recipes_setup(recipes);
@ -62,9 +63,9 @@ static Recipes *Recipes_injection(Recipes *recipes) {
// Run Functions On Furnace Recipes Setup
SETUP_CALLBACK(furnace_recipes_setup, FurnaceRecipes);
// Handle Custom Furnace Recipes Setup Behavior
static FurnaceRecipes *FurnaceRecipes_injection(FurnaceRecipes *recipes) {
static FurnaceRecipes *FurnaceRecipes_injection(FurnaceRecipes_constructor_t original, FurnaceRecipes *recipes) {
// Call Original Method
FurnaceRecipes_constructor(recipes);
original(recipes);
// Run Functions
handle_misc_furnace_recipes_setup(recipes);
@ -87,34 +88,34 @@ static void Inventory_setupDefault_FillingContainer_addItem_call_injection(Filli
// Run Functions On Tiles Setup
SETUP_CALLBACK(tiles_setup, void);
// Handle Custom Tiles Setup Behavior
static void Tile_initTiles_injection() {
static void Tile_initTiles_injection(Tile_initTiles_t original) {
// Run Functions
handle_misc_tiles_setup(NULL);
handle_misc_tiles_setup(nullptr);
// Call Original Method
Tile_initTiles();
original();
}
// Run Functions On Items Setup
SETUP_CALLBACK(items_setup, void);
// Handle Custom Items Setup Behavior
static void Item_initItems_injection() {
static void Item_initItems_injection(Item_initItems_t original) {
// Call Original Method
Item_initItems();
original();
// Run Functions
handle_misc_items_setup(NULL);
handle_misc_items_setup(nullptr);
}
// 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) {
static void I18n_loadLanguage_injection(I18n_loadLanguage_t original, AppPlatform *app, std::string language_name) {
// Call Original Method
I18n_loadLanguage(app, language_name);
original(app, std::move(language_name));
// Run Functions
handle_misc_language_setup(NULL);
handle_misc_language_setup(nullptr);
}
// Run Functions On GUI Key Press
@ -128,32 +129,32 @@ static bool handle_misc_game_key_press(Minecraft *minecraft, int key) {
return false;
}
// Handle Key Presses
static void Gui_handleKeyPressed_injection(Gui *self, int key) {
static void Gui_handleKeyPressed_injection(Gui_handleKeyPressed_t original, Gui *self, int key) {
// Run Functions
if (handle_misc_game_key_press(self->minecraft, key)) {
return;
}
// Call Original Method
Gui_handleKeyPressed(self, key);
original(self, key);
}
// Init
void _init_misc_api() {
// Handle Custom Update Behavior
overwrite_calls((void *) Minecraft_update_non_virtual, (void *) Minecraft_update_injection);
overwrite_virtual_calls(Minecraft_update, Minecraft_update_injection);
// Handle Custom Tick Behavior
overwrite_calls((void *) Minecraft_tick, (void *) Minecraft_tick_injection);
overwrite_calls(Minecraft_tick, Minecraft_tick_injection);
// Handle Custom Recipe Setup Behavior
overwrite_calls((void *) Recipes_constructor, (void *) Recipes_injection);
overwrite_calls((void *) FurnaceRecipes_constructor, (void *) FurnaceRecipes_injection);
overwrite_calls(Recipes_constructor, Recipes_injection);
overwrite_calls(FurnaceRecipes_constructor, FurnaceRecipes_injection);
// Handle Custom Creative Inventory Setup Behavior
overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection);
// Handle Custom Item/Tile Init Behavior
overwrite_calls((void *) Tile_initTiles, (void *) Tile_initTiles_injection);
overwrite_calls((void *) Item_initItems, (void *) Item_initItems_injection);
overwrite_calls(Tile_initTiles, Tile_initTiles_injection);
overwrite_calls(Item_initItems, Item_initItems_injection);
// Handle Custom Language Entries
overwrite_calls((void *) I18n_loadLanguage, (void *) I18n_loadLanguage_injection);
overwrite_calls(I18n_loadLanguage, I18n_loadLanguage_injection);
// Handle Key Presses
overwrite_calls((void *) Gui_handleKeyPressed, (void *) Gui_handleKeyPressed_injection);
overwrite_calls(Gui_handleKeyPressed, Gui_handleKeyPressed_injection);
}

View File

@ -8,7 +8,7 @@
// Print Chat To Log
static bool Gui_addMessage_recursing = false;
static void Gui_addMessage_injection(Gui *gui, std::string *text) {
static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, std::string *text) {
// Sanitize Message
char *new_message = strdup(text->c_str());
ALLOC_CHECK(new_message);
@ -26,26 +26,22 @@ static void Gui_addMessage_injection(Gui *gui, std::string *text) {
free(safe_message);
// Call Original Method
Gui_addMessage(gui, &cpp_str);
original(gui, &cpp_str);
// End Recursing
Gui_addMessage_recursing = false;
} else {
// Call Original Method
Gui_addMessage(gui, &cpp_str);
original(gui, &cpp_str);
}
// Free
free(new_message);
}
void misc_add_message(Gui *gui, const char *text) {
std::string str = text;
Gui_addMessage_injection(gui, &str);
}
// Print Progress Reports
static int last_progress = -1;
static const char *last_message = NULL;
static const char *last_message = nullptr;
static void print_progress(Minecraft *minecraft) {
const char *message = Minecraft_getProgressMessage(minecraft);
int32_t progress = minecraft->progress;
@ -53,7 +49,7 @@ static void print_progress(Minecraft *minecraft) {
message = "Ready";
progress = -1;
}
if (message != NULL) {
if (message != nullptr) {
bool message_different = message != last_message;
bool progress_significant = is_progress_difference_significant(progress, last_progress);
if (message_different || progress_significant) {
@ -79,25 +75,25 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
}
// Log When Game Is Saved
void Level_saveLevelData_injection(Level *level) {
static void Level_saveLevelData_injection(Level_saveLevelData_t original, Level *level) {
// Print Log Message
DEBUG("Saving Game");
// Call Original Method
Level_saveLevelData(level);
original(level);
}
// Init
void _init_misc_logging() {
// Print Chat To Log
overwrite_calls((void *) Gui_addMessage, (void *) Gui_addMessage_injection);
overwrite_calls(Gui_addMessage, Gui_addMessage_injection);
// Print Progress Reports
misc_run_on_update(Minecraft_update_injection);
// Print Log On Game Save
overwrite_calls((void *) Level_saveLevelData, (void *) Level_saveLevelData_injection);
overwrite_calls(Level_saveLevelData, Level_saveLevelData_injection);
// Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0);
}

View File

@ -4,7 +4,6 @@
extern "C" {
#endif
__attribute__((visibility("internal"))) void _init_misc_cpp();
__attribute__((visibility("internal"))) void _init_misc_logging();
__attribute__((visibility("internal"))) void _init_misc_api();

View File

@ -1,850 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <math.h>
#ifndef MCPI_HEADLESS_MODE
#include <GLES/gl.h>
#endif
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <SDL/SDL.h>
#include <media-layer/core.h>
#include <mods/init/init.h>
#include <mods/feature/feature.h>
#include "misc-internal.h"
#include <mods/misc/misc.h>
// Heart food overlay
static int heal_amount = 0, heal_amount_drawing = 0;
void Gui_renderHearts_injection(Gui *gui) {
// Get heal_amount
heal_amount = heal_amount_drawing = 0;
Inventory *inventory = gui->minecraft->player->inventory;
ItemInstance *held_ii = Inventory_getSelected(inventory);
if (held_ii) {
Item *held = Item_items[held_ii->id];
if (held->vtable->isFood(held) && held_ii->id) {
int nutrition = ((FoodItem *) held)->nutrition;
int cur_health = gui->minecraft->player->health;
int heal_num = fmin(cur_health + nutrition, 20) - cur_health;
heal_amount = heal_amount_drawing = heal_num;
}
}
// Call original
Gui_renderHearts(gui);
}
#define PINK_HEART_FULL 70
#define PINK_HEART_HALF 79
Gui_blit_t Gui_blit_renderHearts_original = NULL;
void Gui_renderHearts_GuiComponent_blit_overlay_empty_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) {
// Call original
Gui_blit_renderHearts_original(gui, x1, y1, x2, y2, w1, h1, w2, h2);
// Render the overlay
if (heal_amount_drawing == 1) {
// Half heart
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_HALF, 0, w1, h1, w2, h2);
heal_amount_drawing = 0;
} else if (heal_amount_drawing > 0) {
// Full heart
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
heal_amount_drawing -= 2;
}
}
void Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) {
// Offset the overlay
if (x2 == 52) {
heal_amount_drawing += 2;
} else if (x2 == 61 && heal_amount) {
// Half heart, flipped
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
heal_amount_drawing += 1;
};
// Call original
Gui_blit_renderHearts_original(gui, x1, y1, x2, y2, w1, h1, w2, h2);
heal_amount_drawing = fmin(heal_amount_drawing, heal_amount);
}
// Classic HUD
#define DEFAULT_HUD_PADDING 2
#define NEW_HUD_PADDING 1
#define HUD_ELEMENT_WIDTH 82
#define HUD_ELEMENT_HEIGHT 9
#define TOOLBAR_HEIGHT 22
#define SLOT_WIDTH 20
#define DEFAULT_BUBBLES_PADDING 1
#define NUMBER_OF_SLOTS 9
static int use_classic_hud = 0;
static void Gui_renderHearts_GuiComponent_blit_hearts_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
Minecraft *minecraft = component->minecraft;
x_dest -= DEFAULT_HUD_PADDING;
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
y_dest -= DEFAULT_HUD_PADDING;
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
// Call Original Method
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
static void Gui_renderHearts_GuiComponent_blit_armor_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
Minecraft *minecraft = component->minecraft;
x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH;
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
x_dest += width - ((width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2) - HUD_ELEMENT_WIDTH;
y_dest -= DEFAULT_HUD_PADDING;
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
// Call Original Method
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
static void Gui_renderBubbles_GuiComponent_blit_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
Minecraft *minecraft = component->minecraft;
x_dest -= DEFAULT_HUD_PADDING;
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
y_dest -= DEFAULT_HUD_PADDING + DEFAULT_BUBBLES_PADDING + HUD_ELEMENT_HEIGHT;
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - HUD_ELEMENT_HEIGHT - NEW_HUD_PADDING;
// Call Original Method
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
// Additional GUI Rendering
static int hide_chat_messages = 0;
bool is_in_chat = 0;
static int render_selected_item_text = 0;
static void Gui_renderChatMessages_injection(Gui *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, Font *font) {
// Handle Classic HUD
if (use_classic_hud) {
Minecraft *minecraft = gui->minecraft;
if (!Minecraft_isCreativeMode(minecraft)) {
y_offset -= (HUD_ELEMENT_HEIGHT * 2) + NEW_HUD_PADDING;
}
}
// Call Original Method
if (!hide_chat_messages && !is_in_chat) {
Gui_renderChatMessages(gui, y_offset, max_messages, disable_fading, font);
}
// Render Selected Item Text
if (render_selected_item_text) {
// Fix GL Mode
#ifndef MCPI_HEADLESS_MODE
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
// Calculate Selected Item Text Scale
Minecraft *minecraft = gui->minecraft;
int32_t screen_width = minecraft->screen_width;
float scale = ((float) screen_width) * Gui_InvGuiScale;
// Render Selected Item Text
Gui_renderOnSelectItemNameText(gui, (int32_t) scale, font, y_offset - 0x13);
}
}
// Reset Selected Item Text Timer On Slot Select
static uint32_t reset_selected_item_text_timer = 0;
static void Gui_tick_injection(Gui *gui) {
// Call Original Method
Gui_tick(gui);
// Handle Reset
if (render_selected_item_text) {
float *selected_item_text_timer = &gui->selected_item_text_timer;
if (reset_selected_item_text_timer) {
// Reset
*selected_item_text_timer = 0;
reset_selected_item_text_timer = 0;
}
}
}
// Trigger Reset Selected Item Text Timer On Slot Select
static void Inventory_selectSlot_injection(Inventory *inventory, int32_t slot) {
// Call Original Method
Inventory_selectSlot(inventory, slot);
// Trigger Reset Selected Item Text Timer
if (render_selected_item_text) {
reset_selected_item_text_timer = 1;
}
}
// Translucent Toolbar
static void Gui_renderToolBar_injection(Gui *gui, float param_1, int32_t param_2, int32_t param_3) {
// Call Original Method
#ifndef MCPI_HEADLESS_MODE
int was_blend_enabled = glIsEnabled(GL_BLEND);
if (!was_blend_enabled) {
glEnable(GL_BLEND);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
Gui_renderToolBar(gui, param_1, param_2, param_3);
#ifndef MCPI_HEADLESS_MODE
if (!was_blend_enabled) {
glDisable(GL_BLEND);
}
#endif
}
static void Gui_renderToolBar_glColor4f_injection(GLfloat red, GLfloat green, GLfloat blue, __attribute__((unused)) GLfloat alpha) {
// Fix Alpha
#ifndef MCPI_HEADLESS_MODE
glColor4f(red, green, blue, 1.0f);
#else
(void) red;
(void) green;
(void) blue;
#endif
}
// Fix Screen Rendering When GUI is Hidden
static void Screen_render_injection(Screen *screen, int32_t param_1, int32_t param_2, float param_3) {
// Fix
#ifndef MCPI_HEADLESS_MODE
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
// Call Original Method
Screen_render_non_virtual(screen, param_1, param_2, param_3);
}
// Sanitize Username
#define MAX_USERNAME_LENGTH 16
static void LoginPacket_read_injection(LoginPacket *packet, RakNet_BitStream *bit_stream) {
// Call Original Method
LoginPacket_read_non_virtual(packet, bit_stream);
// Prepare
RakNet_RakString *rak_string = &packet->username;
// Get Original Username
RakNet_RakString_SharedString *shared_string = rak_string->sharedString;
char *c_str = shared_string->c_str;
// Sanitize
char *new_username = strdup(c_str);
ALLOC_CHECK(new_username);
sanitize_string(&new_username, MAX_USERNAME_LENGTH, 0);
// Set New Username
RakNet_RakString_Assign(rak_string, new_username);
// Free
free(new_username);
}
// Fix RakNet::RakString Security Bug
//
// RakNet::RakString's format constructor is often given unsanitized user input and is never used for formatting,
// this is a massive security risk, allowing clients to run arbitrary format specifiers, this disables the
// formatting functionality.
static RakNet_RakString *RakNet_RakString_injection(RakNet_RakString *rak_string, const char *format, ...) {
// Call Original Method
return RakNet_RakString_constructor(rak_string, "%s", format);
}
// Print Error Message If RakNet Startup Fails
static char *RAKNET_ERROR_NAMES[] = {
"Success",
"Already Started",
"Invalid Socket Descriptors",
"Invalid Max Connections",
"Socket Family Not Supported",
"Part Already In Use",
"Failed To Bind Port",
"Failed Test Send",
"Port Cannot Be 0",
"Failed To Create Network Thread",
"Couldn't Generate GUID",
"Unknown"
};
#ifdef MCPI_SERVER_MODE
#define PRINT_RAKNET_STARTUP_FAILURE ERR
#else
#define PRINT_RAKNET_STARTUP_FAILURE WARN
#endif
static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection(RakNet_RakPeer *rak_peer, unsigned short maxConnections, unsigned char *socketDescriptors, uint32_t socketDescriptorCount, int32_t threadPriority) {
// Call Original Method
RakNet_StartupResult result = rak_peer->vtable->Startup(rak_peer, maxConnections, socketDescriptors, socketDescriptorCount, threadPriority);
// Print Error
if (result != RAKNET_STARTED) {
PRINT_RAKNET_STARTUP_FAILURE("Failed To Start RakNet: %s", RAKNET_ERROR_NAMES[result]);
}
// Return
return result;
}
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
static RakNetInstance *RakNetInstance_injection(RakNetInstance *rak_net_instance) {
// Call Original Method
RakNetInstance *result = RakNetInstance_constructor(rak_net_instance);
// Fix
rak_net_instance->pinging_for_hosts = 0;
// Return
return result;
}
// Close Current Screen On Death To Prevent Bugs
static void LocalPlayer_die_injection(LocalPlayer *entity, Entity *cause) {
// Close Screen
Minecraft *minecraft = entity->minecraft;
Minecraft_setScreen(minecraft, NULL);
// Call Original Method
LocalPlayer_die_non_virtual(entity, cause);
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen *furnace_screen, int32_t slot, ItemInstance *item) {
// Get Existing Item
FurnaceTileEntity *tile_entity = furnace_screen->tile_entity;
ItemInstance *existing_item = tile_entity->vtable->getItem(tile_entity, slot);
// Check Item
int valid;
if (item->id == existing_item->id && item->auxiliary == existing_item->auxiliary) {
// Item Matches, Is Valid
valid = 1;
} else {
// Item Doesn't Match, Check If Existing Item Is Empty
if ((existing_item->id | existing_item->count | existing_item->auxiliary) == 0) {
// Existing Item Is Empty, Is Valid
valid = 1;
} else {
// Existing Item Isn't Empty, Isn't Valid
valid = 0;
}
}
// Call Original Method
if (valid) {
// Valid
return FurnaceScreen_handleAddItem(furnace_screen, slot, item);
} else {
// Invalid
return 0;
}
}
// Custom Cursor Rendering
//
// The default behavior for Touch GUI is to only render the cursor when the mouse is clicking, this fixes that.
// This also makes the cursor always render if the mouse is unlocked, instead of just when there is a Screen showing.
#ifndef MCPI_HEADLESS_MODE
static void GameRenderer_render_injection(GameRenderer *game_renderer, float param_1) {
// Call Original Method
GameRenderer_render(game_renderer, param_1);
// Check If Cursor Should Render
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
// Fix GL Mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Get X And Y
float x = Mouse_getX() * Gui_InvGuiScale;
float y = Mouse_getY() * Gui_InvGuiScale;
// Render Cursor
Minecraft *minecraft = game_renderer->minecraft;
Common_renderCursor(x, y, minecraft);
}
}
#endif
// Get Real Selected Slot
int32_t misc_get_real_selected_slot(Player *player) {
// Get Selected Slot
Inventory *inventory = player->inventory;
int32_t selected_slot = inventory->selectedSlot;
// Linked Slots
int32_t linked_slots_length = inventory->linked_slots_length;
if (selected_slot < linked_slots_length) {
int32_t *linked_slots = inventory->linked_slots;
selected_slot = linked_slots[selected_slot];
}
// Return
return selected_slot;
}
#ifndef MCPI_HEADLESS_MODE
// Properly Generate Buffers
static void anGenBuffers_injection(int32_t count, uint32_t *buffers) {
glGenBuffers(count, buffers);
}
#endif
// Fix Graphics Bug When Switching To First-Person While Sneaking
static void HumanoidMobRenderer_render_injection(HumanoidMobRenderer *model_renderer, Entity *entity, float param_2, float param_3, float param_4, float param_5, float param_6) {
HumanoidMobRenderer_render_non_virtual(model_renderer, entity, param_2, param_3, param_4, param_5, param_6);
HumanoidModel *model = model_renderer->model;
model->is_sneaking = 0;
}
// Custom API Port
HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) {
const struct sockaddr *new_addr = addr;
struct sockaddr_in in_addr;
if (addr->sa_family == AF_INET) {
in_addr = *(const struct sockaddr_in *) new_addr;
if (in_addr.sin_port == ntohs(4711)) {
const char *new_port_str = getenv("MCPI_API_PORT");
long int new_port;
if (new_port_str != NULL && (new_port = strtol(new_port_str, NULL, 0)) != 0L) {
in_addr.sin_port = htons(new_port);
}
}
new_addr = (const struct sockaddr *) &in_addr;
}
ensure_bind();
return real_bind(sockfd, new_addr, addrlen);
}
// Change Grass Color
static int32_t get_color(LevelSource *level_source, int32_t x, int32_t z) {
Biome *biome = level_source->vtable->getBiome(level_source, x, z);
if (biome == NULL) {
return 0;
}
return biome->color;
}
#define BIOME_BLEND_SIZE 7
static int32_t GrassTile_getColor_injection(__attribute__((unused)) Tile *tile, LevelSource *level_source, int32_t x, __attribute__((unused)) int32_t y, int32_t z) {
int r_sum = 0;
int g_sum = 0;
int b_sum = 0;
int color_sum = 0;
int x_start = x - (BIOME_BLEND_SIZE / 2);
int z_start = z - (BIOME_BLEND_SIZE / 2);
for (int x_offset = 0; x_offset < BIOME_BLEND_SIZE; x_offset++) {
for (int z_offset = 0; z_offset < BIOME_BLEND_SIZE; z_offset++) {
int32_t color = get_color(level_source, x_start + x_offset, z_start + z_offset);
r_sum += (color >> 16) & 0xff;
g_sum += (color >> 8) & 0xff;
b_sum += color & 0xff;
color_sum++;
}
}
int r_avg = r_sum / color_sum;
int g_avg = g_sum / color_sum;
int b_avg = b_sum / color_sum;
return (r_avg << 16) | (g_avg << 8) | b_avg;
}
static int32_t TallGrass_getColor_injection(TallGrass *tile, LevelSource *level_source, int32_t x, int32_t y, int32_t z) {
int32_t original_color = TallGrass_getColor_non_virtual(tile, level_source, x, y, z);
if (original_color == 0x339933) {
return GrassTile_getColor_injection((Tile *) tile, level_source, x, y, z);
} else {
return original_color;
}
}
// Generate Caves
static void RandomLevelSource_buildSurface_injection(RandomLevelSource *random_level_source, int32_t chunk_x, int32_t chunk_y, unsigned char *chunk_data, Biome **biomes) {
// Call Original Method
RandomLevelSource_buildSurface(random_level_source, chunk_x, chunk_y, chunk_data, biomes);
// Get Level
Level *level = random_level_source->level;
// Get Cave Feature
LargeCaveFeature *cave_feature = &random_level_source->cave_feature;
// Generate
cave_feature->vtable->apply(cave_feature, (ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0);
}
// No Block Tinting
static int32_t Tile_getColor_injection() {
return 0xffffff;
}
// Disable Hostile AI In Creative Mode
static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
// Call Original Method
Entity *target = mob->vtable->findAttackTarget(mob);
// Only modify the AI of monsters
if (mob->vtable->getCreatureBaseType(mob) != 1) {
return target;
}
// Check If Creative Mode
if (target != NULL && target->vtable->isPlayer(target)) {
Player *player = (Player *) target;
Inventory *inventory = player->inventory;
bool is_creative = inventory->is_creative;
if (is_creative) {
target = NULL;
}
}
// Return
return target;
}
// 3D Chests
static int32_t Tile_getRenderShape_injection(Tile *tile) {
if (tile == Tile_chest) {
// Don't Render "Simple" Chest Model
return -1;
} else {
// Call Original Method
return tile->vtable->getRenderShape(tile);
}
}
static ChestTileEntity *ChestTileEntity_injection(ChestTileEntity *tile_entity) {
// Call Original Method
ChestTileEntity_constructor(tile_entity);
// Enable Renderer
tile_entity->renderer_id = 1;
// Return
return tile_entity;
}
static bool is_rendering_chest = 0;
static void ModelPart_render_injection(ModelPart *model_part, float scale) {
// Start
is_rendering_chest = 1;
// Call Original Method
ModelPart_render(model_part, scale);
// Stop
is_rendering_chest = 0;
}
static void Tesselator_vertexUV_injection(Tesselator *tesselator, float x, float y, float z, float u, float v) {
// Fix Chest Texture
if (is_rendering_chest) {
v /= 2;
}
// Call Original Method
Tesselator_vertexUV(tesselator, x, y, z, u, v);
}
static bool ChestTileEntity_shouldSave_injection(__attribute__((unused)) unsigned char *tile_entity) {
return 1;
}
// Animated 3D Chest
static ContainerMenu *ContainerMenu_injection(ContainerMenu *container_menu, Container *container, int32_t param_1) {
// Call Original Method
ContainerMenu_constructor(container_menu, container, param_1);
// Play Animation
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
bool is_client = tile_entity->is_client;
if (!is_client) {
container->vtable->startOpen(container);
}
// Return
return container_menu;
}
static ContainerMenu *ContainerMenu_destructor_injection(ContainerMenu *container_menu) {
// Play Animation
Container *container = container_menu->container;
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
bool is_client = tile_entity->is_client;
if (!is_client) {
container->vtable->stopOpen(container);
}
// Call Original Method
return ContainerMenu_destructor_complete_non_virtual(container_menu);
}
#ifndef MCPI_HEADLESS_MODE
// Custom Outline Color
static void glColor4f_injection(__attribute__((unused)) GLfloat red, __attribute__((unused)) GLfloat green, __attribute__((unused)) GLfloat blue, __attribute__((unused)) GLfloat alpha) {
// Set Color
glColor4f(0, 0, 0, 0.4);
// Find Line Width
char *custom_line_width = getenv("MCPI_BLOCK_OUTLINE_WIDTH");
float line_width;
if (custom_line_width != NULL) {
// Custom
line_width = strtof(custom_line_width, NULL);
} else {
// Guess
line_width = 2 / Gui_InvGuiScale;
}
// Clamp Line Width
float range[2];
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
if (range[1] < line_width) {
line_width = range[1];
} else if (range[0] > line_width) {
line_width = range[0];
}
// Set Line Width
glLineWidth(line_width);
}
#endif
// Fix Furnace Visual Bug
static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity *furnace, int max) {
// Call Original Method
int ret = FurnaceTileEntity_getLitProgress(furnace, max);
// Fix Bug
if (ret > max) {
ret = max;
}
// Return
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
for (int i = 0; i <= 15; i++) {
float f1 = 1.0f - (((float) i) / 15.0f);
self->light_ramp[i] = ((1.0f - f1) / (f1 * 3.0f + 1.0f)) * (1.0f - 0.1f) + 0.1f;
// Default Light Ramp:
// float fVar4 = 1.0 - ((float) i * 0.0625);
// self->light_ramp[i] = ((1.0 - fVar4) / (fVar4 * 3.0 + 1.0)) * 0.95 + 0.15;
}
}
// Init
static void nop() {
}
void init_misc() {
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
if (feature_has("Remove Invalid Item Background", server_disabled)) {
unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x63c98, invalid_item_background_patch);
}
// Classic HUD
Gui_blit_renderHearts_original = Gui_blit;
if (feature_has("Classic HUD", server_disabled)) {
use_classic_hud = 1;
overwrite_call((void *) 0x26758, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x2656c, (void *) Gui_renderHearts_GuiComponent_blit_armor_injection);
overwrite_call((void *) 0x268c4, (void *) Gui_renderBubbles_GuiComponent_blit_injection);
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
Gui_blit_renderHearts_original = Gui_renderHearts_GuiComponent_blit_hearts_injection;
}
// Food overlay
if (feature_has("Food Overlay", server_disabled)) {
overwrite_calls((void *) Gui_renderHearts, Gui_renderHearts_injection);
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_empty_injection);
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection);
}
// Render Selected Item Text + Hide Chat Messages
hide_chat_messages = feature_has("Hide Chat Messages", server_disabled);
render_selected_item_text = feature_has("Render Selected Item Text", server_disabled);
overwrite_calls((void *) Gui_renderChatMessages, (void *) Gui_renderChatMessages_injection);
overwrite_calls((void *) Gui_tick, (void *) Gui_tick_injection);
overwrite_calls((void *) Inventory_selectSlot, (void *) Inventory_selectSlot_injection);
// Translucent Toolbar
if (feature_has("Translucent Toolbar", server_disabled)) {
overwrite_calls((void *) Gui_renderToolBar, (void *) Gui_renderToolBar_injection);
overwrite_call((void *) 0x26c5c, (void *) Gui_renderToolBar_glColor4f_injection);
}
// Fix Screen Rendering When GUI is Hidden
overwrite_calls((void *) Screen_render_non_virtual, (void *) Screen_render_injection);
// Sanitize Username
patch_address(LoginPacket_read_vtable_addr, (void *) LoginPacket_read_injection);
// Fix RakNet::RakString Security Bug
overwrite_calls((void *) RakNet_RakString_constructor, (void *) RakNet_RakString_injection);
// Print Error Message If RakNet Startup Fails
overwrite_call((void *) 0x73778, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection);
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
overwrite_calls((void *) RakNetInstance_constructor, (void *) RakNetInstance_injection);
// Close Current Screen On Death To Prevent Bugs
if (feature_has("Close Current Screen On Death", server_disabled)) {
patch_address(LocalPlayer_die_vtable_addr, (void *) LocalPlayer_die_injection);
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
if (feature_has("Fix Furnace Not Checking Item Auxiliary", server_disabled)) {
overwrite_calls((void *) FurnaceScreen_handleAddItem, (void *) FurnaceScreen_handleAddItem_injection);
}
#ifdef MCPI_HEADLESS_MODE
// Don't Render Game In Headless Mode
overwrite_calls((void *) GameRenderer_render, (void *) nop);
overwrite_calls((void *) NinecraftApp_initGLStates, (void *) nop);
overwrite_calls((void *) Gui_onConfigChanged, (void *) nop);
overwrite_calls((void *) LevelRenderer_generateSky, (void *) nop);
#else
// Improved Cursor Rendering
if (feature_has("Improved Cursor Rendering", server_disabled)) {
// Disable Normal Cursor Rendering
unsigned char disable_cursor_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4a6c0, disable_cursor_patch);
// Add Custom Cursor Rendering
overwrite_calls((void *) GameRenderer_render, (void *) GameRenderer_render_injection);
}
#endif
// Disable V-Sync
if (feature_has("Disable V-Sync", server_enabled)) {
media_disable_vsync();
}
// Force EGL
if (feature_has("Force EGL", server_disabled)) {
media_force_egl();
}
// Remove Forced GUI Lag
if (feature_has("Remove Forced GUI Lag (Can Break Joining Servers)", server_enabled)) {
overwrite_calls((void *) Common_sleepMs, (void *) nop);
}
#ifndef MCPI_HEADLESS_MODE
// Properly Generate Buffers
overwrite((void *) Common_anGenBuffers, (void *) anGenBuffers_injection);
#endif
// Fix Graphics Bug When Switching To First-Person While Sneaking
patch_address(PlayerRenderer_render_vtable_addr, (void *) HumanoidMobRenderer_render_injection);
// Disable Speed Bridging
if (feature_has("Disable Speed Bridging", server_disabled)) {
unsigned char disable_speed_bridging_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
patch((void *) 0x494b4, disable_speed_bridging_patch);
}
// Disable Creative Mode Mining Delay
if (feature_has("Disable Creative Mode Mining Delay", server_disabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x19fa0, nop_patch);
}
// Change Grass Color
if (feature_has("Add Biome Colors To Grass", server_disabled)) {
patch_address((void *) GrassTile_getColor_vtable_addr, (void *) GrassTile_getColor_injection);
patch_address((void *) TallGrass_getColor_vtable_addr, (void *) TallGrass_getColor_injection);
}
// Generate Caves
if (feature_has("Generate Caves", server_auto)) {
overwrite_calls((void *) RandomLevelSource_buildSurface, (void *) RandomLevelSource_buildSurface_injection);
}
// Disable Block Tinting
if (feature_has("Disable Block Tinting", server_disabled)) {
patch_address((void *) GrassTile_getColor_vtable_addr, (void *) Tile_getColor_injection);
patch_address((void *) TallGrass_getColor_vtable_addr, (void *) Tile_getColor_injection);
patch_address((void *) StemTile_getColor_vtable_addr, (void *) Tile_getColor_injection);
patch_address((void *) LeafTile_getColor_vtable_addr, (void *) Tile_getColor_injection);
overwrite((void *) LiquidTile_getColor_non_virtual, (void *) Tile_getColor_injection);
}
// Custom GUI Scale
const char *gui_scale_str = getenv("MCPI_GUI_SCALE");
if (gui_scale_str != NULL) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x173e8, nop_patch);
patch((void *) 0x173f0, nop_patch);
float gui_scale = strtof(gui_scale_str, NULL);
uint32_t gui_scale_raw;
memcpy(&gui_scale_raw, &gui_scale, sizeof (gui_scale_raw));
patch_address((void *) 0x17520, (void *) gui_scale_raw);
}
// Disable Hostile AI In Creative Mode
if (feature_has("Disable Hostile AI In Creative Mode", server_enabled)) {
overwrite_call((void *) 0x83b8c, (void *) PathfinderMob_findAttackTarget_injection);
}
// 3D Chests
if (feature_has("3D Chest Model", server_disabled)) {
overwrite_call((void *) 0x5e830, (void *) Tile_getRenderShape_injection);
overwrite_calls((void *) ChestTileEntity_constructor, (void *) ChestTileEntity_injection);
overwrite_call((void *) 0x6655c, (void *) ModelPart_render_injection);
overwrite_call((void *) 0x66568, (void *) ModelPart_render_injection);
overwrite_call((void *) 0x66574, (void *) ModelPart_render_injection);
overwrite_calls((void *) Tesselator_vertexUV, (void *) Tesselator_vertexUV_injection);
unsigned char chest_model_patch[4] = {0x13, 0x20, 0xa0, 0xe3}; // "mov r2, #0x13"
patch((void *) 0x66fc8, chest_model_patch);
unsigned char chest_color_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x66404, chest_color_patch);
// Animation
overwrite_calls((void *) ContainerMenu_constructor, (void *) ContainerMenu_injection);
overwrite_calls((void *) ContainerMenu_destructor_complete_non_virtual, (void *) ContainerMenu_destructor_injection);
}
patch_address((void *) 0x115b48, (void *) ChestTileEntity_shouldSave_injection);
#ifndef MCPI_HEADLESS_MODE
// Replace Block Highlight With Outline
if (feature_has("Replace Block Highlight With Outline", server_disabled)) {
overwrite((void *) LevelRenderer_renderHitSelect, (void *) LevelRenderer_renderHitOutline);
unsigned char fix_outline_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4d830, fix_outline_patch);
overwrite_call((void *) 0x4d764, (void *) glColor4f_injection);
}
#endif
// Fix Furnace Visual Bug
overwrite_calls((void *) FurnaceTileEntity_getLitProgress, (void *) FurnaceTileEntity_getLitProgress_injection);
// Send the full level, not only changed chunks
if (feature_has("Send Full Level When Hosting Game", server_enabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x717c4, nop_patch);
unsigned char mov_r3_ff[4] = {0xff, 0x30, 0xa0, 0xe3}; // "mov r3, #0xff"
patch((void *) 0x7178c, mov_r3_ff);
}
// Java Light Ramp
if (feature_has("Use Java Beta 1.3 Light Ramp", server_disabled)) {
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);
// Fix invalid ItemInHandRenderer texture cache
if (feature_has("Disable Buggy Held Item Caching", server_disabled)) {
// This works by forcing MCPI to always use the branch that enables using the
// cache, but then patches that as well to do the opposite
uchar ensure_equal_patch[] = {0x07, 0x00, 0x57, 0xe1}; // "cmp r7, r7"
patch((void *) 0x4b938, ensure_equal_patch);
uchar set_true_patch[] = {0x01, 0x30, 0xa0, 0x03}; // "moveq r3, #0x1"
patch((void *) 0x4b93c, set_true_patch);
}
// Init C++ And Logging
_init_misc_cpp();
_init_misc_logging();
_init_misc_api();
}

View File

@ -1,17 +1,636 @@
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cmath>
#include <string>
#include <fstream>
#include <streambuf>
#include <algorithm>
#include <cstring>
#ifndef MCPI_HEADLESS_MODE
#include <GLES/gl.h>
#endif
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <SDL/SDL.h>
#include <media-layer/core.h>
#include <mods/init/init.h>
#include <mods/feature/feature.h>
#include "misc-internal.h"
#include <mods/misc/misc.h>
// Heart food overlay
static int heal_amount = 0, heal_amount_drawing = 0;
static void Gui_renderHearts_injection(Gui_renderHearts_t original, Gui *gui) {
// Get heal_amount
heal_amount = heal_amount_drawing = 0;
Inventory *inventory = gui->minecraft->player->inventory;
ItemInstance *held_ii = Inventory_getSelected(inventory);
if (held_ii) {
Item *held = Item_items[held_ii->id];
if (held->vtable->isFood(held) && held_ii->id) {
int nutrition = ((FoodItem *) held)->nutrition;
int cur_health = gui->minecraft->player->health;
int heal_num = fmin(cur_health + nutrition, 20) - cur_health;
heal_amount = heal_amount_drawing = heal_num;
}
}
// Call original
original(gui);
}
#define PINK_HEART_FULL 70
#define PINK_HEART_HALF 79
static Gui_blit_t Gui_blit_renderHearts_original = nullptr;
static void Gui_renderHearts_GuiComponent_blit_overlay_empty_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) {
// Call original
Gui_blit_renderHearts_original(gui, x1, y1, x2, y2, w1, h1, w2, h2);
// Render the overlay
if (heal_amount_drawing == 1) {
// Half heart
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_HALF, 0, w1, h1, w2, h2);
heal_amount_drawing = 0;
} else if (heal_amount_drawing > 0) {
// Full heart
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
heal_amount_drawing -= 2;
}
}
static void Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection(Gui *gui, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t w1, int32_t h1, int32_t w2, int32_t h2) {
// Offset the overlay
if (x2 == 52) {
heal_amount_drawing += 2;
} else if (x2 == 61 && heal_amount) {
// Half heart, flipped
Gui_blit_renderHearts_original(gui, x1, y1, PINK_HEART_FULL, 0, w1, h1, w2, h2);
heal_amount_drawing += 1;
};
// Call original
Gui_blit_renderHearts_original(gui, x1, y1, x2, y2, w1, h1, w2, h2);
heal_amount_drawing = fmin(heal_amount_drawing, heal_amount);
}
// Classic HUD
#define DEFAULT_HUD_PADDING 2
#define NEW_HUD_PADDING 1
#define HUD_ELEMENT_WIDTH 82
#define HUD_ELEMENT_HEIGHT 9
#define TOOLBAR_HEIGHT 22
#define SLOT_WIDTH 20
#define DEFAULT_BUBBLES_PADDING 1
#define NUMBER_OF_SLOTS 9
static int use_classic_hud = 0;
static void Gui_renderHearts_GuiComponent_blit_hearts_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
Minecraft *minecraft = component->minecraft;
x_dest -= DEFAULT_HUD_PADDING;
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
y_dest -= DEFAULT_HUD_PADDING;
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
// Call Original Method
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
static void Gui_renderHearts_GuiComponent_blit_armor_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
Minecraft *minecraft = component->minecraft;
x_dest -= DEFAULT_HUD_PADDING + HUD_ELEMENT_WIDTH;
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
x_dest += width - ((width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2) - HUD_ELEMENT_WIDTH;
y_dest -= DEFAULT_HUD_PADDING;
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - NEW_HUD_PADDING;
// Call Original Method
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
static void Gui_renderBubbles_GuiComponent_blit_injection(Gui *component, int32_t x_dest, int32_t y_dest, int32_t x_src, int32_t y_src, int32_t width_dest, int32_t height_dest, int32_t width_src, int32_t height_src) {
Minecraft *minecraft = component->minecraft;
x_dest -= DEFAULT_HUD_PADDING;
float width = ((float) minecraft->screen_width) * Gui_InvGuiScale;
float height = ((float) minecraft->screen_height) * Gui_InvGuiScale;
x_dest += (width - (NUMBER_OF_SLOTS * SLOT_WIDTH)) / 2;
y_dest -= DEFAULT_HUD_PADDING + DEFAULT_BUBBLES_PADDING + HUD_ELEMENT_HEIGHT;
y_dest += height - HUD_ELEMENT_HEIGHT - TOOLBAR_HEIGHT - HUD_ELEMENT_HEIGHT - NEW_HUD_PADDING;
// Call Original Method
Gui_blit(component, x_dest, y_dest, x_src, y_src, width_dest, height_dest, width_src, height_src);
}
// Additional GUI Rendering
static int hide_chat_messages = 0;
bool is_in_chat = 0;
static int render_selected_item_text = 0;
static void Gui_renderChatMessages_injection(Gui_renderChatMessages_t original, Gui *gui, int32_t y_offset, uint32_t max_messages, bool disable_fading, Font *font) {
// Handle Classic HUD
if (use_classic_hud) {
Minecraft *minecraft = gui->minecraft;
if (!Minecraft_isCreativeMode(minecraft)) {
y_offset -= (HUD_ELEMENT_HEIGHT * 2) + NEW_HUD_PADDING;
}
}
// Call Original Method
if (!hide_chat_messages && !is_in_chat) {
original(gui, y_offset, max_messages, disable_fading, font);
}
// Render Selected Item Text
if (render_selected_item_text) {
// Fix GL Mode
#ifndef MCPI_HEADLESS_MODE
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
// Calculate Selected Item Text Scale
Minecraft *minecraft = gui->minecraft;
int32_t screen_width = minecraft->screen_width;
float scale = ((float) screen_width) * Gui_InvGuiScale;
// Render Selected Item Text
Gui_renderOnSelectItemNameText(gui, (int32_t) scale, font, y_offset - 0x13);
}
}
// Reset Selected Item Text Timer On Slot Select
static uint32_t reset_selected_item_text_timer = 0;
static void Gui_tick_injection(Gui_tick_t original, Gui *gui) {
// Call Original Method
original(gui);
// Handle Reset
if (render_selected_item_text) {
float *selected_item_text_timer = &gui->selected_item_text_timer;
if (reset_selected_item_text_timer) {
// Reset
*selected_item_text_timer = 0;
reset_selected_item_text_timer = 0;
}
}
}
// Trigger Reset Selected Item Text Timer On Slot Select
static void Inventory_selectSlot_injection(Inventory_selectSlot_t original, Inventory *inventory, int32_t slot) {
// Call Original Method
original(inventory, slot);
// Trigger Reset Selected Item Text Timer
if (render_selected_item_text) {
reset_selected_item_text_timer = 1;
}
}
// Translucent Toolbar
static void Gui_renderToolBar_injection(Gui_renderToolBar_t original, Gui *gui, float param_1, int32_t param_2, int32_t param_3) {
// Call Original Method
#ifndef MCPI_HEADLESS_MODE
int was_blend_enabled = glIsEnabled(GL_BLEND);
if (!was_blend_enabled) {
glEnable(GL_BLEND);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
original(gui, param_1, param_2, param_3);
#ifndef MCPI_HEADLESS_MODE
if (!was_blend_enabled) {
glDisable(GL_BLEND);
}
#endif
}
static void Gui_renderToolBar_glColor4f_injection(GLfloat red, GLfloat green, GLfloat blue, __attribute__((unused)) GLfloat alpha) {
// Fix Alpha
#ifndef MCPI_HEADLESS_MODE
glColor4f(red, green, blue, 1.0f);
#else
(void) red;
(void) green;
(void) blue;
#endif
}
// Fix Screen Rendering When GUI is Hidden
static void Screen_render_injection(Screen_render_t original, Screen *screen, int32_t param_1, int32_t param_2, float param_3) {
// Fix
#ifndef MCPI_HEADLESS_MODE
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
// Call Original Method
original(screen, param_1, param_2, param_3);
}
// Sanitize Username
#define MAX_USERNAME_LENGTH 16
static void LoginPacket_read_injection(LoginPacket_read_t original, LoginPacket *packet, RakNet_BitStream *bit_stream) {
// Call Original Method
original(packet, bit_stream);
// Prepare
RakNet_RakString *rak_string = &packet->username;
// Get Original Username
RakNet_RakString_SharedString *shared_string = rak_string->sharedString;
char *c_str = shared_string->c_str;
// Sanitize
char *new_username = strdup(c_str);
ALLOC_CHECK(new_username);
sanitize_string(&new_username, MAX_USERNAME_LENGTH, 0);
// Set New Username
RakNet_RakString_Assign(rak_string, new_username);
// Free
free(new_username);
}
// Fix RakNet::RakString Security Bug
//
// RakNet::RakString's format constructor is often given unsanitized user input and is never used for formatting,
// this is a massive security risk, allowing clients to run arbitrary format specifiers, this disables the
// formatting functionality.
static RakNet_RakString *RakNet_RakString_injection(RakNet_RakString *rak_string, const char *format, ...) {
// Call Original Method
return RakNet_RakString_constructor(rak_string, "%s", format);
}
// Print Error Message If RakNet Startup Fails
static const char *RAKNET_ERROR_NAMES[] = {
"Success",
"Already Started",
"Invalid Socket Descriptors",
"Invalid Max Connections",
"Socket Family Not Supported",
"Part Already In Use",
"Failed To Bind Port",
"Failed Test Send",
"Port Cannot Be 0",
"Failed To Create Network Thread",
"Couldn't Generate GUID",
"Unknown"
};
#ifdef MCPI_SERVER_MODE
#define PRINT_RAKNET_STARTUP_FAILURE ERR
#else
#define PRINT_RAKNET_STARTUP_FAILURE WARN
#endif
static RakNet_StartupResult RakNetInstance_host_RakNet_RakPeer_Startup_injection(RakNet_RakPeer *rak_peer, unsigned short maxConnections, unsigned char *socketDescriptors, uint32_t socketDescriptorCount, int32_t threadPriority) {
// Call Original Method
RakNet_StartupResult result = rak_peer->vtable->Startup(rak_peer, maxConnections, socketDescriptors, socketDescriptorCount, threadPriority);
// Print Error
if (result != RAKNET_STARTED) {
PRINT_RAKNET_STARTUP_FAILURE("Failed To Start RakNet: %s", RAKNET_ERROR_NAMES[result]);
}
// Return
return result;
}
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
static RakNetInstance *RakNetInstance_injection(RakNetInstance_constructor_t original, RakNetInstance *rak_net_instance) {
// Call Original Method
RakNetInstance *result = original(rak_net_instance);
// Fix
rak_net_instance->pinging_for_hosts = 0;
// Return
return result;
}
// Close Current Screen On Death To Prevent Bugs
static void LocalPlayer_die_injection(LocalPlayer_die_t original, LocalPlayer *entity, Entity *cause) {
// Close Screen
Minecraft *minecraft = entity->minecraft;
Minecraft_setScreen(minecraft, nullptr);
// Call Original Method
original(entity, cause);
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
static int32_t FurnaceScreen_handleAddItem_injection(FurnaceScreen_handleAddItem_t original, FurnaceScreen *furnace_screen, int32_t slot, ItemInstance *item) {
// Get Existing Item
FurnaceTileEntity *tile_entity = furnace_screen->tile_entity;
ItemInstance *existing_item = tile_entity->vtable->getItem(tile_entity, slot);
// Check Item
int valid;
if (item->id == existing_item->id && item->auxiliary == existing_item->auxiliary) {
// Item Matches, Is Valid
valid = 1;
} else {
// Item Doesn't Match, Check If Existing Item Is Empty
if ((existing_item->id | existing_item->count | existing_item->auxiliary) == 0) {
// Existing Item Is Empty, Is Valid
valid = 1;
} else {
// Existing Item Isn't Empty, Isn't Valid
valid = 0;
}
}
// Call Original Method
if (valid) {
// Valid
return original(furnace_screen, slot, item);
} else {
// Invalid
return 0;
}
}
// Custom Cursor Rendering
//
// The default behavior for Touch GUI is to only render the cursor when the mouse is clicking, this fixes that.
// This also makes the cursor always render if the mouse is unlocked, instead of just when there is a Screen showing.
#ifndef MCPI_HEADLESS_MODE
static void GameRenderer_render_injection(GameRenderer_render_t original, GameRenderer *game_renderer, float param_1) {
// Call Original Method
original(game_renderer, param_1);
// Check If Cursor Should Render
if (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
// Fix GL Mode
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Get X And Y
float x = Mouse_getX() * Gui_InvGuiScale;
float y = Mouse_getY() * Gui_InvGuiScale;
// Render Cursor
Minecraft *minecraft = game_renderer->minecraft;
Common_renderCursor(x, y, minecraft);
}
}
#endif
// Get Real Selected Slot
int32_t misc_get_real_selected_slot(Player *player) {
// Get Selected Slot
Inventory *inventory = player->inventory;
int32_t selected_slot = inventory->selectedSlot;
// Linked Slots
int32_t linked_slots_length = inventory->linked_slots_length;
if (selected_slot < linked_slots_length) {
int32_t *linked_slots = inventory->linked_slots;
selected_slot = linked_slots[selected_slot];
}
// Return
return selected_slot;
}
#ifndef MCPI_HEADLESS_MODE
// Properly Generate Buffers
static void anGenBuffers_injection(int32_t count, uint32_t *buffers) {
glGenBuffers(count, buffers);
}
#endif
// Fix Graphics Bug When Switching To First-Person While Sneaking
static void PlayerRenderer_render_injection(PlayerRenderer *model_renderer, Entity *entity, float param_2, float param_3, float param_4, float param_5, float param_6) {
(*HumanoidMobRenderer_render_vtable_addr)((HumanoidMobRenderer *) model_renderer, entity, param_2, param_3, param_4, param_5, param_6);
HumanoidModel *model = model_renderer->model;
model->is_sneaking = false;
}
// Custom API Port
HOOK(bind, int, (int sockfd, const struct sockaddr *addr, socklen_t addrlen)) {
const sockaddr *new_addr = addr;
sockaddr_in in_addr = {};
if (addr->sa_family == AF_INET) {
in_addr = *(const struct sockaddr_in *) new_addr;
if (in_addr.sin_port == ntohs(4711)) {
const char *new_port_str = getenv("MCPI_API_PORT");
long int new_port;
if (new_port_str != nullptr && (new_port = strtol(new_port_str, nullptr, 0)) != 0L) {
in_addr.sin_port = htons(new_port);
}
}
new_addr = (const struct sockaddr *) &in_addr;
}
ensure_bind();
return real_bind(sockfd, new_addr, addrlen);
}
// Change Grass Color
static int32_t get_color(LevelSource *level_source, int32_t x, int32_t z) {
Biome *biome = level_source->vtable->getBiome(level_source, x, z);
if (biome == nullptr) {
return 0;
}
return biome->color;
}
#define BIOME_BLEND_SIZE 7
static int32_t GrassTile_getColor_injection(__attribute__((unused)) Tile *tile, LevelSource *level_source, int32_t x, __attribute__((unused)) int32_t y, int32_t z) {
int r_sum = 0;
int g_sum = 0;
int b_sum = 0;
int color_sum = 0;
int x_start = x - (BIOME_BLEND_SIZE / 2);
int z_start = z - (BIOME_BLEND_SIZE / 2);
for (int x_offset = 0; x_offset < BIOME_BLEND_SIZE; x_offset++) {
for (int z_offset = 0; z_offset < BIOME_BLEND_SIZE; z_offset++) {
int32_t color = get_color(level_source, x_start + x_offset, z_start + z_offset);
r_sum += (color >> 16) & 0xff;
g_sum += (color >> 8) & 0xff;
b_sum += color & 0xff;
color_sum++;
}
}
int r_avg = r_sum / color_sum;
int g_avg = g_sum / color_sum;
int b_avg = b_sum / color_sum;
return (r_avg << 16) | (g_avg << 8) | b_avg;
}
static int32_t TallGrass_getColor_injection(TallGrass_getColor_t original, TallGrass *tile, LevelSource *level_source, int32_t x, int32_t y, int32_t z) {
int32_t original_color = original(tile, level_source, x, y, z);
if (original_color == 0x339933) {
return GrassTile_getColor_injection((Tile *) tile, level_source, x, y, z);
} else {
return original_color;
}
}
// Generate Caves
static void RandomLevelSource_buildSurface_injection(RandomLevelSource_buildSurface_t original, RandomLevelSource *random_level_source, int32_t chunk_x, int32_t chunk_y, unsigned char *chunk_data, Biome **biomes) {
// Call Original Method
original(random_level_source, chunk_x, chunk_y, chunk_data, biomes);
// Get Level
Level *level = random_level_source->level;
// Get Cave Feature
LargeCaveFeature *cave_feature = &random_level_source->cave_feature;
// Generate
cave_feature->vtable->apply(cave_feature, (ChunkSource *) random_level_source, level, chunk_x, chunk_y, chunk_data, 0);
}
// No Block Tinting
static int32_t Tile_getColor_injection() {
return 0xffffff;
}
// Disable Hostile AI In Creative Mode
static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
// Call Original Method
Entity *target = mob->vtable->findAttackTarget(mob);
// Only modify the AI of monsters
if (mob->vtable->getCreatureBaseType(mob) != 1) {
return target;
}
// Check If Creative Mode
if (target != nullptr && target->vtable->isPlayer(target)) {
Player *player = (Player *) target;
Inventory *inventory = player->inventory;
bool is_creative = inventory->is_creative;
if (is_creative) {
target = nullptr;
}
}
// Return
return target;
}
// 3D Chests
static int32_t Tile_getRenderShape_injection(Tile *tile) {
if (tile == Tile_chest) {
// Don't Render "Simple" Chest Model
return -1;
} else {
// Call Original Method
return tile->vtable->getRenderShape(tile);
}
}
static ChestTileEntity *ChestTileEntity_injection(ChestTileEntity_constructor_t original, ChestTileEntity *tile_entity) {
// Call Original Method
original(tile_entity);
// Enable Renderer
tile_entity->renderer_id = 1;
// Return
return tile_entity;
}
static bool is_rendering_chest = false;
static void ModelPart_render_injection(ModelPart *model_part, float scale) {
// Start
is_rendering_chest = true;
// Call Original Method
ModelPart_render(model_part, scale);
// Stop
is_rendering_chest = false;
}
static void Tesselator_vertexUV_injection(Tesselator_vertexUV_t original, Tesselator *tesselator, float x, float y, float z, float u, float v) {
// Fix Chest Texture
if (is_rendering_chest) {
v /= 2;
}
// Call Original Method
original(tesselator, x, y, z, u, v);
}
static bool ChestTileEntity_shouldSave_injection(__attribute__((unused)) unsigned char *tile_entity) {
return true;
}
// Animated 3D Chest
static ContainerMenu *ContainerMenu_injection(ContainerMenu_constructor_t original, ContainerMenu *container_menu, Container *container, int32_t param_1) {
// Call Original Method
original(container_menu, container, param_1);
// Play Animation
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
bool is_client = tile_entity->is_client;
if (!is_client) {
container->vtable->startOpen(container);
}
// Return
return container_menu;
}
static ContainerMenu *ContainerMenu_destructor_injection(ContainerMenu_destructor_complete_t original, ContainerMenu *container_menu) {
// Play Animation
Container *container = container_menu->container;
ChestTileEntity *tile_entity = (ChestTileEntity *) (((unsigned char *) container) - offsetof(ChestTileEntity, container));
bool is_client = tile_entity->is_client;
if (!is_client) {
container->vtable->stopOpen(container);
}
// Call Original Method
return original(container_menu);
}
#ifndef MCPI_HEADLESS_MODE
// Custom Outline Color
static void glColor4f_injection(__attribute__((unused)) GLfloat red, __attribute__((unused)) GLfloat green, __attribute__((unused)) GLfloat blue, __attribute__((unused)) GLfloat alpha) {
// Set Color
glColor4f(0, 0, 0, 0.4);
// Find Line Width
char *custom_line_width = getenv("MCPI_BLOCK_OUTLINE_WIDTH");
float line_width;
if (custom_line_width != nullptr) {
// Custom
line_width = strtof(custom_line_width, nullptr);
} else {
// Guess
line_width = 2 / Gui_InvGuiScale;
}
// Clamp Line Width
float range[2];
glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
if (range[1] < line_width) {
line_width = range[1];
} else if (range[0] > line_width) {
line_width = range[0];
}
// Set Line Width
glLineWidth(line_width);
}
#endif
// Fix Furnace Visual Bug
static int FurnaceTileEntity_getLitProgress_injection(FurnaceTileEntity_getLitProgress_t original, FurnaceTileEntity *furnace, int max) {
// Call Original Method
int ret = original(furnace, max);
// Fix Bug
if (ret > max) {
ret = max;
}
// Return
return ret;
}
// Fix used items transferring durability
static int selected_slot = -1;
static void Player_startUsingItem_injection(Player_startUsingItem_t original, Player *self, ItemInstance *item_instance, int time) {
selected_slot = self->inventory->selectedSlot;
original(self, item_instance, time);
}
static void Player_stopUsingItem_injection(Player_stopUsingItem_t original, Player *self) {
if (selected_slot != self->inventory->selectedSlot) {
self->itemBeingUsed.id = 0;
}
original(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
for (int i = 0; i <= 15; i++) {
float f1 = 1.0f - (((float) i) / 15.0f);
self->light_ramp[i] = ((1.0f - f1) / (f1 * 3.0f + 1.0f)) * (1.0f - 0.1f) + 0.1f;
// Default Light Ramp:
// float fVar4 = 1.0 - ((float) i * 0.0625);
// self->light_ramp[i] = ((1.0 - fVar4) / (fVar4 * 3.0 + 1.0)) * 0.95 + 0.15;
}
}
// Read Asset File
static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injection(__attribute__((unused)) AppPlatform *app_platform, std::string const& path) {
// Open File
@ -20,13 +639,14 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio
// Does Not Exist
AppPlatform_readAssetFile_return_value ret;
ret.length = -1;
ret.data = NULL;
ret.data = nullptr;
return ret;
}
// Read File
long len = stream.tellg();
std::streamoff len = stream.tellg();
char *buf = new char[len];
stream.seekg(0, stream.beg);
ALLOC_CHECK(buf);
stream.seekg(0, std::ifstream::beg);
stream.read(buf, len);
stream.close();
// Return String
@ -37,14 +657,14 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio
}
// Add Missing Buttons To Pause Menu
static void PauseScreen_init_injection(PauseScreen *screen) {
static void PauseScreen_init_injection(PauseScreen_init_t original, PauseScreen *screen) {
// Call Original Method
PauseScreen_init_non_virtual(screen);
original(screen);
// Check If Server
Minecraft *minecraft = screen->minecraft;
RakNetInstance *rak_net_instance = minecraft->rak_net_instance;
if (rak_net_instance != NULL) {
if (rak_net_instance != nullptr) {
if (rak_net_instance->vtable->isServer(rak_net_instance)) {
// Add Button
std::vector<Button *> *rendered_buttons = &screen->rendered_buttons;
@ -67,7 +687,7 @@ void PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_inje
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) {
if (craftingRemainingItem != nullptr) {
// Add or drop remainder
LocalPlayer *player = self->minecraft->player;
if (!player->inventory->vtable->add(player->inventory, craftingRemainingItem)) {
@ -81,14 +701,14 @@ void PaneCraftingScreen_craftSelectedItem_PaneCraftingScreen_recheckRecipes_inje
}
ItemInstance *Item_getCraftingRemainingItem_injection(Item *self, ItemInstance *item_instance) {
if (self->craftingRemainingItem != NULL) {
if (self->craftingRemainingItem != nullptr) {
ItemInstance *ret = alloc_ItemInstance();
ret->id = self->craftingRemainingItem->id;
ret->count = item_instance->count;
ret->auxiliary = 0;
return ret;
}
return NULL;
return nullptr;
}
// Sort Chunks
@ -108,7 +728,7 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkS
Chunk *chunk = chunks_begin[i];
float distance = Chunk_distanceToSqr(chunk, (Entity *) sorter.mob);
if ((1024.0 <= distance) && chunk->y < 0x40) {
distance = distance * 10.0;
distance *= 10.0;
}
data[i].chunk = chunk;
data[i].distance = distance;
@ -127,7 +747,7 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkS
static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, int time) {
// From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84
time_t tt = time;
struct tm t;
tm t = {};
gmtime_r(&tt, &t);
char buf[2048];
strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
@ -135,21 +755,234 @@ static std::string AppPlatform_linux_getDateString_injection(__attribute__((unus
}
// Init
void _init_misc_cpp() {
static void nop() {
}
void init_misc() {
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
if (feature_has("Remove Invalid Item Background", server_disabled)) {
unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x63c98, invalid_item_background_patch);
}
// Classic HUD
Gui_blit_renderHearts_original = Gui_blit;
if (feature_has("Classic HUD", server_disabled)) {
use_classic_hud = 1;
overwrite_call((void *) 0x26758, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x2656c, (void *) Gui_renderHearts_GuiComponent_blit_armor_injection);
overwrite_call((void *) 0x268c4, (void *) Gui_renderBubbles_GuiComponent_blit_injection);
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_hearts_injection);
Gui_blit_renderHearts_original = Gui_renderHearts_GuiComponent_blit_hearts_injection;
}
// Food overlay
if (feature_has("Food Overlay", server_disabled)) {
overwrite_calls(Gui_renderHearts, Gui_renderHearts_injection);
overwrite_call((void *) 0x266f8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_empty_injection);
overwrite_call((void *) 0x267c8, (void *) Gui_renderHearts_GuiComponent_blit_overlay_hearts_injection);
}
// Render Selected Item Text + Hide Chat Messages
hide_chat_messages = feature_has("Hide Chat Messages", server_disabled);
render_selected_item_text = feature_has("Render Selected Item Text", server_disabled);
overwrite_calls(Gui_renderChatMessages, Gui_renderChatMessages_injection);
overwrite_calls(Gui_tick, Gui_tick_injection);
overwrite_calls(Inventory_selectSlot, Inventory_selectSlot_injection);
// Translucent Toolbar
if (feature_has("Translucent Toolbar", server_disabled)) {
overwrite_calls(Gui_renderToolBar, Gui_renderToolBar_injection);
overwrite_call((void *) 0x26c5c, (void *) Gui_renderToolBar_glColor4f_injection);
}
// Fix Screen Rendering When GUI is Hidden
overwrite_virtual_calls(Screen_render, Screen_render_injection);
// Sanitize Username
overwrite_virtual_calls(LoginPacket_read, LoginPacket_read_injection);
// Fix RakNet::RakString Security Bug
overwrite_calls_manual((void *) RakNet_RakString_constructor, (void *) RakNet_RakString_injection);
// Print Error Message If RakNet Startup Fails
overwrite_call((void *) 0x73778, (void *) RakNetInstance_host_RakNet_RakPeer_Startup_injection);
// Fix Bug Where RakNetInstance Starts Pinging Potential Servers Before The "Join Game" Screen Is Opened
overwrite_calls(RakNetInstance_constructor, RakNetInstance_injection);
// Close Current Screen On Death To Prevent Bugs
if (feature_has("Close Current Screen On Death", server_disabled)) {
overwrite_virtual_calls(LocalPlayer_die, LocalPlayer_die_injection);
}
// Fix Furnace Not Checking Item Auxiliary When Inserting New Item
if (feature_has("Fix Furnace Not Checking Item Auxiliary", server_disabled)) {
overwrite_calls(FurnaceScreen_handleAddItem, FurnaceScreen_handleAddItem_injection);
}
#ifdef MCPI_HEADLESS_MODE
// Don't Render Game In Headless Mode
overwrite(GameRenderer_render, nop);
overwrite(NinecraftApp_initGLStates, nop);
overwrite(Gui_onConfigChanged, nop);
overwrite(LevelRenderer_generateSky, nop);
#else
// Improved Cursor Rendering
if (feature_has("Improved Cursor Rendering", server_disabled)) {
// Disable Normal Cursor Rendering
unsigned char disable_cursor_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4a6c0, disable_cursor_patch);
// Add Custom Cursor Rendering
overwrite_calls(GameRenderer_render, GameRenderer_render_injection);
}
#endif
// Disable V-Sync
if (feature_has("Disable V-Sync", server_enabled)) {
media_disable_vsync();
}
// Force EGL
if (feature_has("Force EGL", server_disabled)) {
media_force_egl();
}
// Remove Forced GUI Lag
if (feature_has("Remove Forced GUI Lag (Can Break Joining Servers)", server_enabled)) {
overwrite(Common_sleepMs, nop);
}
#ifndef MCPI_HEADLESS_MODE
// Properly Generate Buffers
overwrite(Common_anGenBuffers, anGenBuffers_injection);
#endif
// Fix Graphics Bug When Switching To First-Person While Sneaking
patch_address(PlayerRenderer_render_vtable_addr, PlayerRenderer_render_injection);
// Disable Speed Bridging
if (feature_has("Disable Speed Bridging", server_disabled)) {
unsigned char disable_speed_bridging_patch[4] = {0x03, 0x00, 0x53, 0xe1}; // "cmp r3, r3"
patch((void *) 0x494b4, disable_speed_bridging_patch);
}
// Disable Creative Mode Mining Delay
if (feature_has("Disable Creative Mode Mining Delay", server_disabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x19fa0, nop_patch);
}
// Change Grass Color
if (feature_has("Add Biome Colors To Grass", server_disabled)) {
patch_address(GrassTile_getColor_vtable_addr, GrassTile_getColor_injection);
overwrite_virtual_calls(TallGrass_getColor, TallGrass_getColor_injection);
}
// Generate Caves
if (feature_has("Generate Caves", server_auto)) {
overwrite_calls(RandomLevelSource_buildSurface, RandomLevelSource_buildSurface_injection);
}
// Disable Block Tinting
if (feature_has("Disable Block Tinting", server_disabled)) {
patch_address(GrassTile_getColor_vtable_addr, Tile_getColor_injection);
patch_address(TallGrass_getColor_vtable_addr, Tile_getColor_injection);
patch_address(StemTile_getColor_vtable_addr, Tile_getColor_injection);
patch_address(LeafTile_getColor_vtable_addr, Tile_getColor_injection);
overwrite(*LiquidTile_getColor_vtable_addr, Tile_getColor_injection);
}
// Custom GUI Scale
const char *gui_scale_str = getenv("MCPI_GUI_SCALE");
if (gui_scale_str != nullptr) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x173e8, nop_patch);
patch((void *) 0x173f0, nop_patch);
float gui_scale = strtof(gui_scale_str, nullptr);
uint32_t gui_scale_raw;
memcpy(&gui_scale_raw, &gui_scale, sizeof (gui_scale_raw));
patch_address((void *) 0x17520, (void *) gui_scale_raw);
}
// Disable Hostile AI In Creative Mode
if (feature_has("Disable Hostile AI In Creative Mode", server_enabled)) {
overwrite_call((void *) 0x83b8c, (void *) PathfinderMob_findAttackTarget_injection);
}
// 3D Chests
if (feature_has("3D Chest Model", server_disabled)) {
overwrite_call((void *) 0x5e830, (void *) Tile_getRenderShape_injection);
overwrite_calls(ChestTileEntity_constructor, ChestTileEntity_injection);
overwrite_call((void *) 0x6655c, (void *) ModelPart_render_injection);
overwrite_call((void *) 0x66568, (void *) ModelPart_render_injection);
overwrite_call((void *) 0x66574, (void *) ModelPart_render_injection);
overwrite_calls(Tesselator_vertexUV, Tesselator_vertexUV_injection);
unsigned char chest_model_patch[4] = {0x13, 0x20, 0xa0, 0xe3}; // "mov r2, #0x13"
patch((void *) 0x66fc8, chest_model_patch);
unsigned char chest_color_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x66404, chest_color_patch);
// Animation
overwrite_calls(ContainerMenu_constructor, ContainerMenu_injection);
overwrite_virtual_calls(ContainerMenu_destructor_complete, ContainerMenu_destructor_injection);
}
patch_address((void *) 0x115b48, (void *) ChestTileEntity_shouldSave_injection);
#ifndef MCPI_HEADLESS_MODE
// Replace Block Highlight With Outline
if (feature_has("Replace Block Highlight With Outline", server_disabled)) {
overwrite((void *) LevelRenderer_renderHitSelect, (void *) LevelRenderer_renderHitOutline);
unsigned char fix_outline_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4d830, fix_outline_patch);
overwrite_call((void *) 0x4d764, (void *) glColor4f_injection);
}
#endif
// Fix Furnace Visual Bug
overwrite_calls(FurnaceTileEntity_getLitProgress, FurnaceTileEntity_getLitProgress_injection);
// Send the full level, not only changed chunks
if (feature_has("Send Full Level When Hosting Game", server_enabled)) {
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x717c4, nop_patch);
unsigned char mov_r3_ff[4] = {0xff, 0x30, 0xa0, 0xe3}; // "mov r3, #0xff"
patch((void *) 0x7178c, mov_r3_ff);
}
// Java Light Ramp
if (feature_has("Use Java Beta 1.3 Light Ramp", server_disabled)) {
overwrite(*Dimension_updateLightRamp_vtable_addr, Dimension_updateLightRamp_injection);
}
// Fix used items transferring durability
overwrite_calls(Player_startUsingItem, Player_startUsingItem_injection);
overwrite_calls(Player_stopUsingItem, Player_stopUsingItem_injection);
// Fix invalid ItemInHandRenderer texture cache
if (feature_has("Disable Buggy Held Item Caching", server_disabled)) {
// This works by forcing MCPI to always use the branch that enables using the
// cache, but then patches that as well to do the opposite
uchar ensure_equal_patch[] = {0x07, 0x00, 0x57, 0xe1}; // "cmp r7, r7"
patch((void *) 0x4b938, ensure_equal_patch);
uchar set_true_patch[] = {0x01, 0x30, 0xa0, 0x03}; // "moveq r3, #0x1"
patch((void *) 0x4b93c, set_true_patch);
}
// Implement AppPlatform::readAssetFile So Translations Work
if (feature_has("Load Language Files", server_enabled)) {
overwrite((void *) *AppPlatform_readAssetFile_vtable_addr, (void *) AppPlatform_readAssetFile_injection);
overwrite(*AppPlatform_readAssetFile_vtable_addr, AppPlatform_readAssetFile_injection);
}
// Fix Pause Menu
if (feature_has("Fix Pause Menu", server_disabled)) {
// Add Missing Buttons To Pause Menu
patch_address(PauseScreen_init_vtable_addr, (void *) PauseScreen_init_injection);
overwrite_virtual_calls(PauseScreen_init, 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);
overwrite(*Item_getCraftingRemainingItem_vtable_addr, Item_getCraftingRemainingItem_injection);
// Replace 2011 std::sort With Optimized(TM) Code
if (feature_has("Optimized Chunk Sorting", server_enabled)) {
@ -158,6 +991,10 @@ void _init_misc_cpp() {
// Display Date In Select World Screen
if (feature_has("Display Date In Select World Screen", server_disabled)) {
patch_address(AppPlatform_linux_getDateString_vtable_addr, (void *) AppPlatform_linux_getDateString_injection);
patch_address(AppPlatform_linux_getDateString_vtable_addr, AppPlatform_linux_getDateString_injection);
}
// Init Logging
_init_misc_logging();
_init_misc_api();
}

View File

@ -113,9 +113,9 @@ static void iterate_servers(std::function<void(const char *address, int port)> c
}
// Ping External Servers
static void RakNetInstance_pingForHosts_injection(RakNetInstance *rak_net_instance, int32_t base_port) {
static void RakNetInstance_pingForHosts_injection(RakNetInstance_pingForHosts_t original, RakNetInstance *rak_net_instance, int32_t base_port) {
// Call Original Method
RakNetInstance_pingForHosts_non_virtual(rak_net_instance, base_port);
original(rak_net_instance, base_port);
// Get RakNet::RakPeer
RakNet_RakPeer *rak_peer = rak_net_instance->peer;
@ -130,6 +130,6 @@ static void RakNetInstance_pingForHosts_injection(RakNetInstance *rak_net_instan
void init_multiplayer() {
// Inject Code
if (feature_has("External Server Support", server_disabled)) {
patch_address(RakNetInstance_pingForHosts_vtable_addr, (void *) RakNetInstance_pingForHosts_injection);
overwrite_virtual_calls(RakNetInstance_pingForHosts, RakNetInstance_pingForHosts_injection);
}
}

View File

@ -1,14 +0,0 @@
#pragma once
#include <symbols/minecraft.h>
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((visibility("internal"))) void _init_options_cpp();
__attribute__((visibility("internal"))) extern Options *stored_options;
#ifdef __cplusplus
}
#endif

View File

@ -1,125 +0,0 @@
#include <string.h>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/feature/feature.h>
#include <mods/init/init.h>
#include "options-internal.h"
// Force Mob Spawning
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) {
return 1;
}
// Get Custom Render Distance
static int get_render_distance() {
char *distance_str = getenv("MCPI_RENDER_DISTANCE");
if (distance_str == NULL) {
distance_str = "Short";
}
if (strcmp("Far", distance_str) == 0) {
return 0;
} else if (strcmp("Normal", distance_str) == 0) {
return 1;
} else if (strcmp("Short", distance_str) == 0) {
return 2;
} else if (strcmp("Tiny", distance_str) == 0) {
return 3;
} else {
ERR("Invalid Render Distance: %s", distance_str);
}
}
// Get Custom Username
static char *get_username() {
char *username = getenv("MCPI_USERNAME");
if (username == NULL) {
username = "StevePi";
}
return username;
}
static char *safe_username = NULL;
__attribute__((destructor)) static void _free_safe_username() {
free(safe_username);
}
static int render_distance;
// Configure Options
Options *stored_options = NULL;
static void Options_initDefaultValue_injection(Options *options) {
// Call Original Method
Options_initDefaultValue(options);
// Default Graphics Settings
#ifndef MCPI_SERVER_MODE
options->fancy_graphics = 1;
options->ambient_occlusion = 1;
#endif
// Store
stored_options = options;
}
static void Minecraft_init_injection(Minecraft *minecraft) {
// Call Original Method
Minecraft_init_non_virtual(minecraft);
Options *options = &minecraft->options;
// Enable Crosshair In Touch GUI
options->split_controls = 1;
// Render Distance
options->render_distance = render_distance;
}
// Smooth Lighting
static void TileRenderer_tesselateBlockInWorld_injection(TileRenderer *tile_renderer, Tile *tile, int32_t x, int32_t y, int32_t z) {
// Set Variable
Minecraft_useAmbientOcclusion = stored_options->ambient_occlusion;
// Call Original Method
TileRenderer_tesselateBlockInWorld(tile_renderer, tile, x, y, z);
}
// Init
void init_options() {
// Force Mob Spawning
if (feature_has("Force Mob Spawning", server_auto)) {
overwrite((void *) LevelData_getSpawnMobs, (void *) LevelData_getSpawnMobs_injection);
}
// Render Distance
render_distance = get_render_distance();
DEBUG("Setting Render Distance: %i", render_distance);
// Set Options
overwrite_calls((void *) Options_initDefaultValue, (void *) Options_initDefaultValue_injection);
overwrite_calls((void *) Minecraft_init_non_virtual, (void *) Minecraft_init_injection);
// Change Username
const char *username = get_username();
DEBUG("Setting Username: %s", username);
if (strcmp(Strings_default_username, "StevePi") != 0) {
ERR("Default Username Is Invalid");
}
safe_username = to_cp437(username);
patch_address((void *) Strings_default_username_pointer, (void *) safe_username);
// Disable Autojump By Default
if (feature_has("Disable Autojump By Default", server_disabled)) {
unsigned char autojump_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0"
patch((void *) 0x44b90, autojump_patch);
}
// Display Nametags By Default
if (feature_has("Display Nametags By Default", server_disabled)) {
// r6 = 0x1
// r5 = 0x0
unsigned char display_nametags_patch[4] = {0x1d, 0x60, 0xc0, 0xe5}; // "strb r6, [r0, #0x1d]"
patch((void *) 0xa6628, display_nametags_patch);
}
// Smooth Lighting
overwrite_calls((void *) TileRenderer_tesselateBlockInWorld, (void *) TileRenderer_tesselateBlockInWorld_injection);
// Init C++
_init_options_cpp();
}

View File

@ -1,15 +1,87 @@
#include <cstring>
#include <string>
#include <vector>
#include <sstream>
#include <string.h>
#include <libreborn/libreborn.h>
#include <symbols/minecraft.h>
#include <mods/feature/feature.h>
#include <mods/init/init.h>
#include <mods/home/home.h>
#include "options-internal.h"
#include <symbols/minecraft.h>
// Force Mob Spawning
static bool LevelData_getSpawnMobs_injection(__attribute__((unused)) unsigned char *level_data) {
return true;
}
// Get Custom Render Distance
static int get_render_distance() {
const char *distance_str = getenv("MCPI_RENDER_DISTANCE");
if (distance_str == nullptr) {
distance_str = "Short";
}
if (strcmp("Far", distance_str) == 0) {
return 0;
} else if (strcmp("Normal", distance_str) == 0) {
return 1;
} else if (strcmp("Short", distance_str) == 0) {
return 2;
} else if (strcmp("Tiny", distance_str) == 0) {
return 3;
} else {
ERR("Invalid Render Distance: %s", distance_str);
}
}
// Get Custom Username
static const char *get_username() {
const char *username = getenv("MCPI_USERNAME");
if (username == nullptr) {
username = "StevePi";
}
return username;
}
static char *safe_username = nullptr;
__attribute__((destructor)) static void _free_safe_username() {
free(safe_username);
}
static int render_distance;
// Configure Options
static Options *stored_options = nullptr;
static void Options_initDefaultValue_injection(Options_initDefaultValue_t original, Options *options) {
// Call Original Method
original(options);
// Default Graphics Settings
#ifndef MCPI_SERVER_MODE
options->fancy_graphics = true;
options->ambient_occlusion = true;
#endif
// Store
stored_options = options;
}
static void Minecraft_init_injection(Minecraft_init_t original, Minecraft *minecraft) {
// Call Original Method
original(minecraft);
Options *options = &minecraft->options;
// Enable Crosshair In Touch GUI
options->split_controls = true;
// Render Distance
options->render_distance = render_distance;
}
// Smooth Lighting
static bool TileRenderer_tesselateBlockInWorld_injection(TileRenderer_tesselateBlockInWorld_t original, TileRenderer *tile_renderer, Tile *tile, int32_t x, int32_t y, int32_t z) {
// Set Variable
Minecraft_useAmbientOcclusion = stored_options->ambient_occlusion;
// Call Original Method
return original(tile_renderer, tile, x, y, z);
}
// Fix Initial Option Button Rendering
// The calling function doesn't exist in MCPE v0.6.1, so its name is unknown.
@ -49,8 +121,8 @@ static std::vector<std::string> OptionsFile_getOptionStrings_injection(OptionsFi
std::vector<std::string> ret;
FILE *stream = fopen(path.c_str(), "r");
char line[128];
if (stream != NULL) {
while (fgets(line, 0x80, stream) != NULL) {
if (stream != nullptr) {
while (fgets(line, 0x80, stream) != nullptr) {
size_t sVar1 = strlen(line);
if (2 < sVar1) {
std::stringstream string_stream(line);
@ -74,9 +146,9 @@ static std::vector<std::string> OptionsFile_getOptionStrings_injection(OptionsFi
// Get New options.txt Path
#ifndef MCPI_SERVER_MODE
static char *get_new_options_txt_path() {
static char *path = NULL;
static char *path = nullptr;
// Path
if (path == NULL) {
if (path == nullptr) {
safe_asprintf(&path, "%s/options.txt", home_get());
}
// Return
@ -94,7 +166,7 @@ static char *get_new_options_txt_path() {
#endif
// Modify Option Toggles
static void OptionsPane_unknown_toggle_creating_function_injection(OptionsPane *options_pane, uint32_t group_id, std::string *name_ptr, Options_Option *option) {
static void OptionsPane_unknown_toggle_creating_function_injection(OptionsPane_unknown_toggle_creating_function_t original, OptionsPane *options_pane, uint32_t group_id, std::string *name_ptr, Options_Option *option) {
// Modify
std::string name = *name_ptr;
std::string new_name = name;
@ -120,23 +192,23 @@ static void OptionsPane_unknown_toggle_creating_function_injection(OptionsPane *
}
// Call Original Method
OptionsPane_unknown_toggle_creating_function(options_pane, group_id, &new_name, option);
original(options_pane, group_id, &new_name, option);
// Add 3D Anaglyph
if (option == &Options_Option_GRAPHICS) {
std::string cpp_string = "3D Anaglyph";
OptionsPane_unknown_toggle_creating_function(options_pane, group_id, &cpp_string, &Options_Option_ANAGLYPH);
original(options_pane, group_id, &cpp_string, &Options_Option_ANAGLYPH);
}
// Add Peaceful Mode
if (option == &Options_Option_SERVER_VISIBLE) {
std::string cpp_string = "Peaceful mode";
OptionsPane_unknown_toggle_creating_function(options_pane, group_id, &cpp_string, &Options_Option_DIFFICULTY);
original(options_pane, group_id, &cpp_string, &Options_Option_DIFFICULTY);
}
}
// Add Missing Options To Options::getBooleanValue
static bool Options_getBooleanValue_injection(Options *options, Options_Option *option) {
static bool Options_getBooleanValue_injection(Options_getBooleanValue_t original, Options *options, Options_Option *option) {
// Check
if (option == &Options_Option_GRAPHICS) {
return options->fancy_graphics;
@ -144,7 +216,7 @@ static bool Options_getBooleanValue_injection(Options *options, Options_Option *
return options->game_difficulty == 0;
} else {
// Call Original Method
return Options_getBooleanValue(options, option);
return original(options, option);
}
}
@ -162,8 +234,46 @@ static void OptionButton_toggle_Options_save_injection(Options *self) {
Options_save(self);
}
// Init C++
void _init_options_cpp() {
// Init
void init_options() {
// Force Mob Spawning
if (feature_has("Force Mob Spawning", server_auto)) {
overwrite((void *) LevelData_getSpawnMobs, (void *) LevelData_getSpawnMobs_injection);
}
// Render Distance
render_distance = get_render_distance();
DEBUG("Setting Render Distance: %i", render_distance);
// Set Options
overwrite_calls(Options_initDefaultValue, Options_initDefaultValue_injection);
overwrite_virtual_calls(Minecraft_init, Minecraft_init_injection);
// Change Username
const char *username = get_username();
DEBUG("Setting Username: %s", username);
if (strcmp(Strings_default_username, "StevePi") != 0) {
ERR("Default Username Is Invalid");
}
safe_username = to_cp437(username);
patch_address((void *) Strings_default_username_pointer, (void *) safe_username);
// Disable Autojump By Default
if (feature_has("Disable Autojump By Default", server_disabled)) {
unsigned char autojump_patch[4] = {0x00, 0x30, 0xa0, 0xe3}; // "mov r3, #0x0"
patch((void *) 0x44b90, autojump_patch);
}
// Display Nametags By Default
if (feature_has("Display Nametags By Default", server_disabled)) {
// r6 = 0x1
// r5 = 0x0
unsigned char display_nametags_patch[4] = {0x1d, 0x60, 0xc0, 0xe5}; // "strb r6, [r0, #0x1d]"
patch((void *) 0xa6628, display_nametags_patch);
}
// Smooth Lighting
overwrite_calls(TileRenderer_tesselateBlockInWorld, TileRenderer_tesselateBlockInWorld_injection);
// NOP
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
@ -182,10 +292,10 @@ void _init_options_cpp() {
patch((void *) 0x3577c, this_works_slider_patch);
// Modify Option Toggles
overwrite_calls((void *) OptionsPane_unknown_toggle_creating_function, (void *) OptionsPane_unknown_toggle_creating_function_injection);
overwrite_calls(OptionsPane_unknown_toggle_creating_function, OptionsPane_unknown_toggle_creating_function_injection);
// Add Missing Options To Options::getBooleanValue
overwrite_calls((void *) Options_getBooleanValue, (void *) Options_getBooleanValue_injection);
overwrite_calls(Options_getBooleanValue, Options_getBooleanValue_injection);
// Fix Difficulty When Toggling
overwrite_call((void *) 0x1cd00, (void *) OptionButton_toggle_Options_save_injection);
@ -198,7 +308,7 @@ void _init_options_cpp() {
// When Loading, options.txt Should Be Opened In Read Mode
patch_address((void *) Strings_options_txt_fopen_mode_when_loading_pointer, (void *) "r");
// Fix OptionsFile::getOptionStrings
overwrite_calls((void *) OptionsFile_getOptionStrings, (void *) OptionsFile_getOptionStrings_injection);
overwrite(OptionsFile_getOptionStrings, OptionsFile_getOptionStrings_injection);
// Sensitivity Loading/Saving Is Broken, Disable It
patch((void *) 0x1931c, nop_patch);

View File

@ -1,7 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <unistd.h>
#include <fcntl.h>
@ -16,9 +16,9 @@ HOOK(access, int, (const char *pathname, int mode)) {
char *new_path = override_get_path(pathname);
// Open File
ensure_access();
int ret = real_access(new_path != NULL ? new_path : pathname, mode);
int ret = real_access(new_path != nullptr ? new_path : pathname, mode);
// Free Data
if (new_path != NULL) {
if (new_path != nullptr) {
free(new_path);
}
// Return
@ -36,11 +36,11 @@ char *override_get_path(const char *filename) {
// Get MCPI Home Path
char *home_path = home_get();
// Get Asset Override Path
char *overrides = NULL;
char *overrides = nullptr;
safe_asprintf(&overrides, "%s/overrides", home_path);
// Data Prefiix
char *data_prefix = "data/";
const char *data_prefix = "data/";
int data_prefix_length = strlen(data_prefix);
// Folders To Check
@ -48,20 +48,20 @@ char *override_get_path(const char *filename) {
overrides,
getenv("MCPI_REBORN_ASSETS_PATH"),
getenv("MCPI_VANILLA_ASSETS_PATH"),
NULL
nullptr
};
// Check For Override
char *new_path = NULL;
char *new_path = nullptr;
if (starts_with(filename, data_prefix)) {
// Test Asset Folders
for (int i = 0; asset_folders[i] != NULL; i++) {
for (int i = 0; asset_folders[i] != nullptr; i++) {
safe_asprintf(&new_path, "%s/%s", asset_folders[i], &filename[data_prefix_length]);
ensure_access();
if (real_access(new_path, F_OK) == -1) {
// Not Found In Asset Folder
free(new_path);
new_path = NULL;
new_path = nullptr;
continue;
} else {
// Found
@ -82,9 +82,9 @@ HOOK(fopen, FILE *, (const char *filename, const char *mode)) {
char *new_path = override_get_path(filename);
// Open File
ensure_fopen();
FILE *file = real_fopen(new_path != NULL ? new_path : filename, mode);
FILE *file = real_fopen(new_path != nullptr ? new_path : filename, mode);
// Free Data
if (new_path != NULL) {
if (new_path != nullptr) {
free(new_path);
}
// Return File
@ -96,9 +96,9 @@ HOOK(fopen64, FILE *, (const char *filename, const char *mode)) {
char *new_path = override_get_path(filename);
// Open File
ensure_fopen64();
FILE *file = real_fopen64(new_path != NULL ? new_path : filename, mode);
FILE *file = real_fopen64(new_path != nullptr ? new_path : filename, mode);
// Free Data
if (new_path != NULL) {
if (new_path != nullptr) {
free(new_path);
}
// Return File

View File

@ -1,22 +0,0 @@
#define __USE_LARGEFILE64
#include <stddef.h>
#include <stdint.h>
#include <dirent.h>
// Minecraft: Pi Edition Was Not Compiled With 64-Bit Filesystem Support, So This Shims readdir() To Read Directories Properly
#define FILENAME_SIZE 256
struct dirent *readdir(DIR *dirp) {
struct dirent64 *original = readdir64(dirp);
if (original == NULL) {
return NULL;
}
static struct dirent new;
for (int i = 0; i < FILENAME_SIZE; i++) {
new.d_name[i] = original->d_name[i];
}
new.d_type = original->d_type;
return &new;
}

View File

@ -0,0 +1,22 @@
#define __USE_LARGEFILE64
#include <cstddef>
#include <cstdint>
#include <dirent.h>
// Minecraft: Pi Edition Was Not Compiled With 64-Bit Filesystem Support, So This Shims readdir() To Read Directories Properly
#define FILENAME_SIZE 256
dirent *readdir(DIR *dirp) {
dirent64 *original = readdir64(dirp);
if (original == nullptr) {
return nullptr;
}
static dirent new_dirent;
for (int i = 0; i < FILENAME_SIZE; i++) {
new_dirent.d_name[i] = original->d_name[i];
}
new_dirent.d_type = original->d_type;
return &new_dirent;
}

View File

@ -1,9 +1,9 @@
#include <stdlib.h>
#include <stdio.h>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <ctime>
#include <cstring>
#include <cerrno>
#include <sys/stat.h>
#include "stb_image.h"
@ -16,7 +16,7 @@
// Ensure Screenshots Folder Exists
static void ensure_screenshots_folder(char *screenshots) {
// Check Screenshots Folder
struct stat obj;
struct stat obj = {};
if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
// Create Screenshots Folder
int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
@ -40,12 +40,12 @@ static int save_png(const char *filename, unsigned char *pixels, int line_size,
}
void screenshot_take(char *home) {
// Get Directory
char *screenshots = NULL;
char *screenshots = nullptr;
safe_asprintf(&screenshots, "%s/screenshots", home);
// Get Timestamp
time_t rawtime;
struct tm *timeinfo;
tm *timeinfo = {};
time(&rawtime);
timeinfo = localtime(&rawtime);
char time[TIME_SIZE];
@ -56,11 +56,11 @@ void screenshot_take(char *home) {
// Prevent Overwriting Screenshots
int num = 1;
char *file = NULL;
char *file = nullptr;
safe_asprintf(&file, "%s/%s.png", screenshots, time);
while (access(file, F_OK) != -1) {
free(file);
file = NULL;
file = nullptr;
safe_asprintf(&file, "%s/%s-%i.png", screenshots, time, num);
num++;
}

View File

@ -88,7 +88,7 @@ static void start_world(Minecraft *minecraft) {
LevelSettings settings;
settings.game_type = get_server_properties().get_int("game-mode", DEFAULT_GAME_MODE);
std::string seed_str = get_server_properties().get_string("seed", DEFAULT_SEED);
int32_t seed = seed_str.length() > 0 ? std::stoi(seed_str) : time(NULL);
int32_t seed = seed_str.length() > 0 ? std::stoi(seed_str) : time(nullptr);
settings.seed = seed;
// Select Level
@ -202,12 +202,12 @@ static void ban_callback(Minecraft *minecraft, std::string username, Player *pla
}
}
// Reload
is_ip_in_blacklist(NULL);
is_ip_in_blacklist(nullptr);
}
// Kill Player
static void kill_callback(__attribute__((unused)) Minecraft *minecraft, __attribute__((unused)) std::string username, Player *player) {
player->vtable->hurt(player, NULL, INT32_MAX);
player->vtable->hurt(player, nullptr, INT32_MAX);
INFO("Killed: %s", username.c_str());
}
@ -222,7 +222,7 @@ static void handle_server_stop(Minecraft *minecraft) {
INFO("Stopping Server");
// Save And Exit
Level *level = get_level(minecraft);
if (level != NULL) {
if (level != nullptr) {
Level_saveLevelData_injection(level);
}
Minecraft_leaveGame(minecraft, false);
@ -263,7 +263,7 @@ static ServerSideNetworkHandler *get_server_side_network_handler(Minecraft *mine
// Read STDIN Thread
static volatile bool stdin_buffer_complete = false;
static volatile char *stdin_buffer = NULL;
static volatile char *stdin_buffer = nullptr;
static void *read_stdin_thread(__attribute__((unused)) void *data) {
// Loop
while (1) {
@ -278,7 +278,7 @@ static void *read_stdin_thread(__attribute__((unused)) void *data) {
// Read Data
char x = buffer[i];
if (x == '\n') {
if (stdin_buffer == NULL) {
if (stdin_buffer == nullptr) {
stdin_buffer = (volatile char *) malloc(1);
stdin_buffer[0] = '\0';
}
@ -289,12 +289,12 @@ static void *read_stdin_thread(__attribute__((unused)) void *data) {
}
}
}
return NULL;
return nullptr;
}
__attribute__((destructor)) static void _free_stdin_buffer() {
if (stdin_buffer != NULL) {
if (stdin_buffer != nullptr) {
free((void *) stdin_buffer);
stdin_buffer = NULL;
stdin_buffer = nullptr;
}
}
@ -303,9 +303,9 @@ static void handle_commands(Minecraft *minecraft) {
// Check If Level Is Generated
if (Minecraft_isLevelGenerated(minecraft) && stdin_buffer_complete) {
// Command Ready; Run It
if (stdin_buffer != NULL) {
if (stdin_buffer != nullptr) {
ServerSideNetworkHandler *server_side_network_handler = get_server_side_network_handler(minecraft);
if (server_side_network_handler != NULL) {
if (server_side_network_handler != nullptr) {
std::string data((char *) stdin_buffer);
static std::string ban_command("ban ");
@ -322,7 +322,7 @@ static void handle_commands(Minecraft *minecraft) {
find_players(minecraft, ban_username, ban_callback, false);
} else if (data == reload_command) {
INFO("Reloading %s", is_whitelist() ? "Whitelist" : "Blacklist");
is_ip_in_blacklist(NULL);
is_ip_in_blacklist(nullptr);
} else if (data.rfind(kill_command, 0) == 0) {
// Kill Target Username
std::string kill_username = data.substr(kill_command.length());
@ -365,7 +365,7 @@ static void handle_commands(Minecraft *minecraft) {
// Free
free((void *) stdin_buffer);
stdin_buffer = NULL;
stdin_buffer = nullptr;
}
stdin_buffer_complete = false;
}
@ -398,7 +398,7 @@ static void Minecraft_update_injection(Minecraft *minecraft) {
// Check Blacklist/Whitelist
static bool is_ip_in_blacklist(const char *ip) {
static std::vector<std::string> ips;
if (ip == NULL) {
if (ip == nullptr) {
// Reload
ips.clear();
// Check banned-ips.txt
@ -449,7 +449,7 @@ static Player *ServerSideNetworkHandler_onReady_ClientGeneration_ServerSideNetwo
Player *player = ServerSideNetworkHandler_popPendingPlayer(server_side_network_handler, guid);
// Check If Player Is Null
if (player != NULL) {
if (player != nullptr) {
// Get Data
std::string *username = &player->username;
Minecraft *minecraft = server_side_network_handler->minecraft;
@ -565,7 +565,7 @@ static void server_init() {
blacklist_file.close();
}
// Load Blacklist/Whitelist
is_ip_in_blacklist(NULL);
is_ip_in_blacklist(nullptr);
// Prevent Main Player From Loading
unsigned char player_patch[4] = {0x00, 0x20, 0xa0, 0xe3}; // "mov r2, #0x0"
@ -592,7 +592,7 @@ static void server_init() {
// Start Reading STDIN
pthread_t read_stdin_thread_obj;
pthread_create(&read_stdin_thread_obj, NULL, read_stdin_thread, NULL);
pthread_create(&read_stdin_thread_obj, nullptr, read_stdin_thread, nullptr);
}
// Init Server

View File

@ -10,7 +10,7 @@
#include <mods/sign/sign.h>
// Handle Backspace
static int32_t sdl_key_to_minecraft_key_injection(int32_t sdl_key) {
static int32_t sdl_key_to_minecraft_key_injection(Common_sdl_key_to_minecraft_key_t original, int32_t sdl_key) {
if (sdl_key == SDLK_BACKSPACE) {
return 0x8;
} else if (sdl_key == SDLK_DELETE) {
@ -25,7 +25,7 @@ static int32_t sdl_key_to_minecraft_key_injection(int32_t sdl_key) {
return 0x74;
} else {
// Call Original Method
return Common_sdl_key_to_minecraft_key(sdl_key);
return original(sdl_key);
}
}
@ -53,5 +53,5 @@ void init_sign() {
}
// Handle Backspace
overwrite_calls((void *) Common_sdl_key_to_minecraft_key, (void *) sdl_key_to_minecraft_key_injection);
overwrite_calls(Common_sdl_key_to_minecraft_key, sdl_key_to_minecraft_key_injection);
}

View File

@ -66,7 +66,7 @@ static void load_pending_skins(__attribute__((unused)) Minecraft *minecraft) {
// Skin Server
static std::string get_skin_server() {
const char *custom_server = getenv("MCPI_SKIN_SERVER");
if (custom_server != NULL) {
if (custom_server != nullptr) {
return custom_server;
} else {
return MCPI_SKIN_SERVER;
@ -85,12 +85,12 @@ static void *loader_thread(void *user_data) {
// Download
std::string url = get_skin_server() + '/' + data->name + ".png";
int return_code;
const char *command[] = {"wget", "-O", "-", url.c_str(), NULL};
const char *command[] = {"wget", "-O", "-", url.c_str(), nullptr};
size_t output_size = 0;
char *output = run_command(command, &return_code, &output_size);
// Check Success
if (output != NULL && is_exit_status_success(return_code)) {
if (output != nullptr && is_exit_status_success(return_code)) {
// Success
DEBUG("Downloaded Skin: %s", data->name.c_str());
@ -110,13 +110,13 @@ static void *loader_thread(void *user_data) {
// Free
delete data;
return NULL;
return nullptr;
}
// Intercept Texture Creation
static int32_t Textures_assignTexture_injection(Textures *textures, std::string *name, unsigned char *data) {
static int32_t Textures_assignTexture_injection(Textures_assignTexture_t original, Textures *textures, std::string *name, unsigned char *data) {
// Call Original Method
int32_t id = Textures_assignTexture(textures, name, data);
int32_t id = original(textures, name, data);
// Load Skin
if (starts_with(name->c_str(), "$")) {
@ -126,7 +126,7 @@ static int32_t Textures_assignTexture_injection(Textures *textures, std::string
user_data->texture_id = id;
// Start Thread
pthread_t thread;
pthread_create(&thread, NULL, loader_thread, (void *) user_data);
pthread_create(&thread, nullptr, loader_thread, (void *) user_data);
}
// Return
@ -136,7 +136,7 @@ static int32_t Textures_assignTexture_injection(Textures *textures, std::string
// Init
void _init_skin_loader() {
// Intercept Texture Creation
overwrite_calls((void *) Textures_assignTexture, (void *) Textures_assignTexture_injection);
overwrite_calls(Textures_assignTexture, Textures_assignTexture_injection);
// Pending Skins
misc_run_on_tick(load_pending_skins);
// Log

View File

@ -350,7 +350,7 @@ std::unordered_map<std::string, std::vector<std::string>> sound_repository = {
// Set rand() Seed
__attribute__((constructor)) static void init_rand_seed() {
srand(time(NULL));
srand(time(nullptr));
}
// Pick Sound
std::string _sound_pick(std::string sound) {

View File

@ -28,7 +28,7 @@ std::string _sound_get_source_file() {
// Handle Overrides
char *overridden_full_path = override_get_path(path);
if (overridden_full_path != NULL) {
if (overridden_full_path != nullptr) {
free(path);
path = overridden_full_path;
}
@ -90,7 +90,7 @@ static void SoundEngine_update_injection(SoundEngine *sound_engine, Mob *listene
volume = sound_enabled ? 1 : 0;
// Position And Rotation
if (listener_mob != NULL) {
if (listener_mob != nullptr) {
// Values
x = listener_mob->x;
y = listener_mob->y;
@ -104,9 +104,9 @@ static void SoundEngine_update_injection(SoundEngine *sound_engine, Mob *listene
// Resolve All Sounds On Init
// SoundEngine::init Is Called After The Audio Engine Has Been Loaded
static void SoundEngine_init_injection(SoundEngine *sound_engine, Minecraft *minecraft, Options *options) {
static void SoundEngine_init_injection(SoundEngine_init_t original, SoundEngine *sound_engine, Minecraft *minecraft, Options *options) {
// Call Original Method
SoundEngine_init(sound_engine, minecraft, options);
original(sound_engine, minecraft, options);
// Resolve Sounds
_sound_resolve_all();
@ -116,9 +116,9 @@ static void SoundEngine_init_injection(SoundEngine *sound_engine, Minecraft *min
void init_sound() {
// Implement Sound Engine
if (feature_has("Implement Sound Engine", server_disabled)) {
overwrite((void *) SoundEngine_playUI, (void *) SoundEngine_playUI_injection);
overwrite((void *) SoundEngine_play, (void *) SoundEngine_play_injection);
overwrite((void *) SoundEngine_update, (void *) SoundEngine_update_injection);
overwrite_calls((void *) SoundEngine_init, (void *) SoundEngine_init_injection);
overwrite(SoundEngine_playUI, SoundEngine_playUI_injection);
overwrite(SoundEngine_play, SoundEngine_play_injection);
overwrite(SoundEngine_update, SoundEngine_update_injection);
overwrite_calls(SoundEngine_init, SoundEngine_init_injection);
}
}

View File

@ -4,32 +4,36 @@
// VTable
void TextInputScreen::setup(Screen_vtable *vtable) {
static Screen_keyPressed_t original_keyPressed = vtable->keyPressed;
vtable->keyPressed = [](Screen *super2, int key) {
Screen_keyPressed_non_virtual(super2, key);
original_keyPressed(super2, key);
TextInputScreen *self = (TextInputScreen *) super2;
for (int i = 0; i < int(self->m_textInputs->size()); i++) {
TextInputBox *textInput = (*self->m_textInputs)[i];
textInput->keyPressed(key);
}
};
static Screen_keyboardNewChar_t original_keyboardNewChar = vtable->keyboardNewChar;
vtable->keyboardNewChar = [](Screen *super2, char key) {
Screen_keyboardNewChar_non_virtual(super2, key);
original_keyboardNewChar(super2, key);
TextInputScreen *self = (TextInputScreen *) super2;
for (int i = 0; i < int(self->m_textInputs->size()); i++) {
TextInputBox *textInput = (*self->m_textInputs)[i];
textInput->charPressed(key);
}
};
static Screen_mouseClicked_t original_mouseClicked = vtable->mouseClicked;
vtable->mouseClicked = [](Screen *super2, int x, int y, int param_1) {
Screen_mouseClicked_non_virtual(super2, x, y, param_1);
original_mouseClicked(super2, x, y, param_1);
TextInputScreen *self = (TextInputScreen *) super2;
for (int i = 0; i < int(self->m_textInputs->size()); i++) {
TextInputBox *textInput = (*self->m_textInputs)[i];
textInput->onClick(x, y);
}
};
static Screen_render_t original_render = vtable->render;
vtable->render = [](Screen *super2, int x, int y, float param_1) {
Screen_render_non_virtual(super2, x, y, param_1);
original_render(super2, x, y, param_1);
TextInputScreen *self = (TextInputScreen *) super2;
for (int i = 0; i < int(self->m_textInputs->size()); i++) {
TextInputBox *textInput = (*self->m_textInputs)[i];
@ -37,13 +41,15 @@ void TextInputScreen::setup(Screen_vtable *vtable) {
textInput->render();
}
};
static Screen_init_t original_init = vtable->init;
vtable->init = [](Screen *super2) {
Screen_init_non_virtual(super2);
original_init(super2);
TextInputScreen *self = (TextInputScreen *) super2;
self->m_textInputs = new std::vector<TextInputBox *>;
};
static Screen_removed_t original_removed = vtable->removed;
vtable->removed = [](Screen *super2) {
Screen_removed_non_virtual(super2);
original_removed(super2);
TextInputScreen *self = (TextInputScreen *) super2;
delete self->m_textInputs;
};

View File

@ -7,7 +7,7 @@ static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) A
Texture out;
out.width = 0;
out.height = 0;
out.data = NULL;
out.data = nullptr;
out.field3_0xc = 0;
out.field4_0x10 = true;
out.field5_0x11 = false;

View File

@ -19,7 +19,7 @@
static void Minecraft_tick_injection(Minecraft *minecraft) {
// Tick Dynamic Textures
Textures *textures = minecraft->textures;
if (textures != NULL) {
if (textures != nullptr) {
Textures_tick(textures, true);
}
}
@ -180,7 +180,7 @@ static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) A
// Empty Texture
out.width = 0;
out.height = 0;
out.data = NULL;
out.data = nullptr;
out.field3_0xc = 0;
out.field4_0x10 = true;
out.field5_0x11 = false;
@ -234,5 +234,5 @@ void init_textures() {
overwrite_call((void *) 0x53274, (void *) Textures_tick_glTexSubImage2D_injection);
// Load Textures
overwrite((void *) AppPlatform_linux_loadTexture_non_virtual, (void *) AppPlatform_linux_loadTexture_injection);
overwrite(*AppPlatform_linux_loadTexture_vtable_addr, AppPlatform_linux_loadTexture_injection);
}

View File

@ -22,9 +22,9 @@ static void StartMenuScreen_render_Screen_renderBackground_injection(Screen *scr
}
// Add Buttons Back To Classic Start Screen
static void StartMenuScreen_init_injection(StartMenuScreen *screen) {
static void StartMenuScreen_init_injection(StartMenuScreen_init_t original, StartMenuScreen *screen) {
// Call Original Method
StartMenuScreen_init_non_virtual(screen);
original(screen);
// Add Button
std::vector<Button *> *rendered_buttons = &screen->rendered_buttons;
@ -38,14 +38,14 @@ static void StartMenuScreen_init_injection(StartMenuScreen *screen) {
}
// Add Functionality To Quit Button
static void StartMenuScreen_buttonClicked_injection(StartMenuScreen *screen, Button *button) {
static void StartMenuScreen_buttonClicked_injection(StartMenuScreen_buttonClicked_t original, StartMenuScreen *screen, Button *button) {
Button *quit_button = &screen->create_button;
if (button == quit_button) {
// Quit
compat_request_exit();
} else {
// Call Original Method
StartMenuScreen_buttonClicked_non_virtual(screen, button);
original(screen, button);
}
}
@ -68,7 +68,7 @@ static Screen *last_screen = nullptr;
static std::string current_splash;
static void StartMenuScreen_render_Screen_render_injection(Screen *screen, int x, int y, float param_1) {
// Call Original Method
Screen_render_non_virtual(screen, x, y, param_1);
(*Screen_render_vtable_addr)(screen, x, y, param_1);
// Load Splashes
static std::vector<std::string> splashes;
@ -130,7 +130,7 @@ void init_title_screen() {
// Improved Classic Title Screen
if (feature_has("Improved Classic Title Screen", server_disabled)) {
// Add Options Button Back To Classic Start Screen
patch_address(StartMenuScreen_init_vtable_addr, (void *) StartMenuScreen_init_injection);
overwrite_virtual_calls(StartMenuScreen_init, StartMenuScreen_init_injection);
// Fix Classic UI Button Size
unsigned char classic_button_height_patch[4] = {0x18, 0x30, 0xa0, 0xe3}; // "mov r3, #0x18"
@ -154,7 +154,7 @@ void init_title_screen() {
patch_address((void *) Strings_classic_create_button_text_pointer, (void *) "Quit");
// Add Functionality To Quit Button
patch_address(StartMenuScreen_buttonClicked_vtable_addr, (void *) StartMenuScreen_buttonClicked_injection);
overwrite_virtual_calls(StartMenuScreen_buttonClicked, StartMenuScreen_buttonClicked_injection);
}
// Add Splashes
@ -162,6 +162,6 @@ void init_title_screen() {
overwrite_call((void *) 0x39764, (void *) StartMenuScreen_render_Screen_render_injection);
overwrite_call((void *) 0x3e0c4, (void *) StartMenuScreen_render_Screen_render_injection);
// Init Random
srand(time(NULL));
srand(time(nullptr));
}
}

View File

@ -33,7 +33,7 @@ static int32_t Button_hovered_injection(__attribute__((unused)) Button *button,
}
static void LargeImageButton_render_GuiComponent_drawCenteredString_injection(GuiComponent *component, Font *font, std::string *text, int32_t x, int32_t y, int32_t color) {
// Change Color On Hover
if (color == 0xe0e0e0 && Button_hovered_injection((Button *) component, NULL, 0, 0)) {
if (color == 0xe0e0e0 && Button_hovered_injection((Button *) component, nullptr, 0, 0)) {
color = 0xffffa0;
}

View File

@ -6,9 +6,9 @@
// Get New Version
char *version_get() {
static char *version = NULL;
static char *version = nullptr;
// Load
if (version == NULL) {
if (version == nullptr) {
safe_asprintf(&version, "%s / Reborn v%s", Strings_minecraft_pi_version, reborn_get_version());
}
// Return

View File

@ -12,7 +12,7 @@ property int game_difficulty = 0xe8;
property bool anaglyph_3d = 0x15;
property bool ambient_occlusion = 0x18;
property bool hide_gui = 0xec;
property bool third_person = 0xed;
property uchar third_person = 0xed; // Technically This Is A Boolean
property int render_distance = 0x10;
property int sound = 0x4;
property bool debug = 0xee;

View File

@ -1 +1,3 @@
vtable 0x102540;
virtual-method int tickBuild(Player *player, uint *build_action_intention_return) = 0xc;

View File

@ -1,3 +1,7 @@
vtable-destructor-offset 0x4; // Why
vtable 0x1090f0;
virtual-method void levelGenerated(Level *level) = 0x0;
virtual-method void onDisconnect(RakNet_RakNetGUID *guid) = 0x18;
virtual-method void handle_SignUpdatePacket(RakNet_RakNetGUID *guid, SignUpdatePacket *packet) = 0xcc;
virtual-method void handle_ChatPacket(RakNet_RakNetGUID *rak_net_guid, uchar *packet) = 0xc8;
virtual-method void handle_ChatPacket(RakNet_RakNetGUID *rak_net_guid, ChatPacket *packet) = 0xc8;