diff --git a/libreborn/include/libreborn/util.h b/libreborn/include/libreborn/util.h index 707fdf0e..d4960a7d 100644 --- a/libreborn/include/libreborn/util.h +++ b/libreborn/include/libreborn/util.h @@ -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" { diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 358e161a..46a42684 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -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 diff --git a/mods/include/mods/bucket/bucket.h b/mods/include/mods/bucket/bucket.h index 54f34e1f..fb141e83 100644 --- a/mods/include/mods/bucket/bucket.h +++ b/mods/include/mods/bucket/bucket.h @@ -2,12 +2,4 @@ #include <symbols/minecraft.h> -#ifdef __cplusplus -extern "C" { -#endif - extern bool buckets_enabled; - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/chat/chat.h b/mods/include/mods/chat/chat.h index f8a10019..8fb3c45e 100644 --- a/mods/include/mods/chat/chat.h +++ b/mods/include/mods/chat/chat.h @@ -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 diff --git a/mods/include/mods/compat/compat.h b/mods/include/mods/compat/compat.h index 0d1150de..c307bc7d 100644 --- a/mods/include/mods/compat/compat.h +++ b/mods/include/mods/compat/compat.h @@ -1,12 +1,4 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - int compat_check_exit_requested(); void compat_request_exit(); - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/creative/creative.h b/mods/include/mods/creative/creative.h index 84a353e2..2b6f63e3 100644 --- a/mods/include/mods/creative/creative.h +++ b/mods/include/mods/creative/creative.h @@ -1,11 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - -int creative_is_restricted(); - -#ifdef __cplusplus -} -#endif +int creative_is_restricted(); \ No newline at end of file diff --git a/mods/include/mods/feature/feature.h b/mods/include/mods/feature/feature.h index cbd1feca..7eea3ff5 100644 --- a/mods/include/mods/feature/feature.h +++ b/mods/include/mods/feature/feature.h @@ -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 diff --git a/mods/include/mods/fps/fps.h b/mods/include/mods/fps/fps.h index 237871a2..702a3447 100644 --- a/mods/include/mods/fps/fps.h +++ b/mods/include/mods/fps/fps.h @@ -1,11 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - extern double fps; - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/home/home.h b/mods/include/mods/home/home.h index 8a3462b4..585163af 100644 --- a/mods/include/mods/home/home.h +++ b/mods/include/mods/home/home.h @@ -1,11 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - char *home_get(); - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/init/init.h b/mods/include/mods/init/init.h index 6dce44d1..288bebc4 100644 --- a/mods/include/mods/init/init.h +++ b/mods/include/mods/init/init.h @@ -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(); \ No newline at end of file diff --git a/mods/include/mods/input/input.h b/mods/include/mods/input/input.h index 78b1a4b7..50f98f47 100644 --- a/mods/include/mods/input/input.h +++ b/mods/include/mods/input/input.h @@ -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 diff --git a/mods/include/mods/misc/misc.h b/mods/include/mods/misc/misc.h index 493d270b..af2ecc53 100644 --- a/mods/include/mods/misc/misc.h +++ b/mods/include/mods/misc/misc.h @@ -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); @@ -32,7 +28,3 @@ void Level_saveLevelData_injection(Level *level); void misc_add_message(Gui *gui, const char *text); extern bool is_in_chat; - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/override/override.h b/mods/include/mods/override/override.h index 331ec466..dcd39aa8 100644 --- a/mods/include/mods/override/override.h +++ b/mods/include/mods/override/override.h @@ -1,11 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - char *override_get_path(const char *filename); - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/screenshot/screenshot.h b/mods/include/mods/screenshot/screenshot.h index e72cb033..f0e063dc 100644 --- a/mods/include/mods/screenshot/screenshot.h +++ b/mods/include/mods/screenshot/screenshot.h @@ -1,11 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - void screenshot_take(char *home); - -#ifdef __cplusplus -} -#endif diff --git a/mods/include/mods/sign/sign.h b/mods/include/mods/sign/sign.h index fd654311..de0a4d43 100644 --- a/mods/include/mods/sign/sign.h +++ b/mods/include/mods/sign/sign.h @@ -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); \ No newline at end of file diff --git a/mods/include/mods/textures/textures.h b/mods/include/mods/textures/textures.h index 3b6e7144..202a4fea 100644 --- a/mods/include/mods/textures/textures.h +++ b/mods/include/mods/textures/textures.h @@ -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 diff --git a/mods/include/mods/title-screen/title-screen.h b/mods/include/mods/title-screen/title-screen.h index cf6330d7..bbe30a43 100644 --- a/mods/include/mods/title-screen/title-screen.h +++ b/mods/include/mods/title-screen/title-screen.h @@ -3,6 +3,4 @@ #include <string> #include <vector> -extern "C" { void title_screen_load_splashes(std::vector<std::string> &splashes); -} diff --git a/mods/include/mods/version/version.h b/mods/include/mods/version/version.h index dd909f00..27c1aaa1 100644 --- a/mods/include/mods/version/version.h +++ b/mods/include/mods/version/version.h @@ -1,11 +1,3 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - char *version_get(); - -#ifdef __cplusplus -} -#endif diff --git a/mods/src/atlas/atlas.cpp b/mods/src/atlas/atlas.cpp index 4c4b13d7..a110fc58 100644 --- a/mods/src/atlas/atlas.cpp +++ b/mods/src/atlas/atlas.cpp @@ -13,7 +13,7 @@ static void ItemRenderer_renderGuiItemCorrect_injection(Font *font, Textures *te // 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; @@ -91,7 +91,7 @@ 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) + // Add Better nullptr-Check (And More UI Fixes When The gui_blocks Atlas Is Disabled) overwrite_calls((void *) ItemRenderer_renderGuiItem_two, (void *) ItemRenderer_renderGuiItem_two_injection); // Disable The gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory diff --git a/mods/src/bucket/bucket.cpp b/mods/src/bucket/bucket.cpp index b2fa7668..bea4614e 100644 --- a/mods/src/bucket/bucket.cpp +++ b/mods/src/bucket/bucket.cpp @@ -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) { @@ -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; @@ -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; } } @@ -280,7 +280,7 @@ static bool is_calm_liquid(int32_t id) { static void Minecraft_handleMouseDown_injection(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; diff --git a/mods/src/cake/cake.cpp b/mods/src/cake/cake.cpp index c9c00343..c7a85b14 100644 --- a/mods/src/cake/cake.cpp +++ b/mods/src/cake/cake.cpp @@ -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 diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp index 857e1eb0..fd499b55 100644 --- a/mods/src/chat/chat.cpp +++ b/mods/src/chat/chat.cpp @@ -26,7 +26,7 @@ std::string chat_send_api_command(Minecraft *minecraft, std::string str) { 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); diff --git a/mods/src/chat/ui.cpp b/mods/src/chat/ui.cpp index 692728f1..66b9b1e9 100644 --- a/mods/src/chat/ui.cpp +++ b/mods/src/chat/ui.cpp @@ -95,7 +95,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(); @@ -147,7 +147,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; diff --git a/mods/src/compat/bcm_host.c b/mods/src/compat/bcm_host.cpp similarity index 100% rename from mods/src/compat/bcm_host.c rename to mods/src/compat/bcm_host.cpp diff --git a/mods/src/compat/compat.c b/mods/src/compat/compat.cpp similarity index 94% rename from mods/src/compat/compat.c rename to mods/src/compat/compat.cpp index cff6a39c..980c7381 100644 --- a/mods/src/compat/compat.c +++ b/mods/src/compat/compat.cpp @@ -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(); diff --git a/mods/src/compat/egl.c b/mods/src/compat/egl.cpp similarity index 97% rename from mods/src/compat/egl.c rename to mods/src/compat/egl.cpp index 5c9d01c3..21f7a6bb 100644 --- a/mods/src/compat/egl.c +++ b/mods/src/compat/egl.cpp @@ -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) { diff --git a/mods/src/compat/x11.c b/mods/src/compat/x11.cpp similarity index 96% rename from mods/src/compat/x11.c rename to mods/src/compat/x11.cpp index ab87d308..b0dadecf 100644 --- a/mods/src/compat/x11.c +++ b/mods/src/compat/x11.cpp @@ -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); diff --git a/mods/src/death/death.cpp b/mods/src/death/death.cpp index 487faba3..241ed9a4 100644 --- a/mods/src/death/death.cpp +++ b/mods/src/death/death.cpp @@ -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; \ @@ -134,7 +134,7 @@ void init_death() { } // 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]" diff --git a/mods/src/feature/feature.c b/mods/src/feature/feature.cpp similarity index 68% rename from mods/src/feature/feature.c rename to mods/src/feature/feature.cpp index 451a4706..498530d1 100644 --- a/mods/src/feature/feature.c +++ b/mods/src/feature/feature.cpp @@ -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); diff --git a/mods/src/game-mode/game-mode.c b/mods/src/game-mode/game-mode.cpp similarity index 79% rename from mods/src/game-mode/game-mode.c rename to mods/src/game-mode/game-mode.cpp index 44f8be71..fafb4de8 100644 --- a/mods/src/game-mode/game-mode.c +++ b/mods/src/game-mode/game-mode.cpp @@ -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,18 +28,18 @@ 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 *self, int32_t new_game_mode) { set_is_survival(!new_game_mode); // Call Original Method - Minecraft_setIsCreativeMode(this, new_game_mode); + Minecraft_setIsCreativeMode(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) { if (is_survival) { - // SurvivalMode, Return NULL - return NULL; + // SurvivalMode, Return nullptr + return nullptr; } else { // CreatorMode, Call Original Method return Minecraft_getCreator(minecraft); @@ -50,7 +50,7 @@ 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); + set_is_survival(true); overwrite_calls((void *) Minecraft_setIsCreativeMode, (void *) Minecraft_setIsCreativeMode_injection); // Replace CreatorLevel With ServerLevel (This Fixes Beds And Mob Spawning) diff --git a/mods/src/home/home.c b/mods/src/home/home.cpp similarity index 91% rename from mods/src/home/home.c rename to mods/src/home/home.cpp index 2fe8bb6c..a8f0c866 100644 --- a/mods/src/home/home.c +++ b/mods/src/home/home.cpp @@ -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 diff --git a/mods/src/init/init.c b/mods/src/init/init.cpp similarity index 100% rename from mods/src/init/init.c rename to mods/src/init/init.cpp diff --git a/mods/src/input/attack.c b/mods/src/input/attack.cpp similarity index 99% rename from mods/src/input/attack.c rename to mods/src/input/attack.cpp index a981bc36..52dcddec 100644 --- a/mods/src/input/attack.c +++ b/mods/src/input/attack.cpp @@ -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 diff --git a/mods/src/input/bow.c b/mods/src/input/bow.cpp similarity index 89% rename from mods/src/input/bow.c rename to mods/src/input/bow.cpp index 1a5ef503..c24411e3 100644 --- a/mods/src/input/bow.c +++ b/mods/src/input/bow.cpp @@ -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); } } diff --git a/mods/src/input/drop.cpp b/mods/src/input/drop.cpp index d966f792..fce6287b 100644 --- a/mods/src/input/drop.cpp +++ b/mods/src/input/drop.cpp @@ -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); diff --git a/mods/src/input/misc.c b/mods/src/input/misc.cpp similarity index 89% rename from mods/src/input/misc.c rename to mods/src/input/misc.cpp index ac0a57a9..a4377077 100644 --- a/mods/src/input/misc.c +++ b/mods/src/input/misc.cpp @@ -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,7 +38,7 @@ 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; } @@ -48,10 +48,10 @@ static int32_t InBedScreen_handleBackEvent_injection(InBedScreen *screen, bool d 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); } } @@ -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); diff --git a/mods/src/input/toggle.c b/mods/src/input/toggle.cpp similarity index 96% rename from mods/src/input/toggle.c rename to mods/src/input/toggle.cpp index cbfe1a72..e106f0d7 100644 --- a/mods/src/input/toggle.c +++ b/mods/src/input/toggle.cpp @@ -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,7 +48,7 @@ static void revert_rotation(Entity *entity) { } } static int is_front_facing = 0; -static LocalPlayer *stored_player = NULL; +static LocalPlayer *stored_player = nullptr; static void GameRenderer_setupCamera_injection(GameRenderer *game_renderer, float param_1, int param_2) { // Get Objects Minecraft *minecraft = game_renderer->minecraft; diff --git a/mods/src/misc/api.cpp b/mods/src/misc/api.cpp index d947cae1..0d3b4de9 100644 --- a/mods/src/misc/api.cpp +++ b/mods/src/misc/api.cpp @@ -89,7 +89,7 @@ SETUP_CALLBACK(tiles_setup, void); // Handle Custom Tiles Setup Behavior static void Tile_initTiles_injection() { // Run Functions - handle_misc_tiles_setup(NULL); + handle_misc_tiles_setup(nullptr); // Call Original Method Tile_initTiles(); @@ -103,7 +103,7 @@ static void Item_initItems_injection() { Item_initItems(); // Run Functions - handle_misc_items_setup(NULL); + handle_misc_items_setup(nullptr); } // Run Functions On Language Setup @@ -114,7 +114,7 @@ static void I18n_loadLanguage_injection(AppPlatform *app, std::string language_n I18n_loadLanguage(app, language_name); // Run Functions - handle_misc_language_setup(NULL); + handle_misc_language_setup(nullptr); } // Run Functions On GUI Key Press diff --git a/mods/src/misc/logging.cpp b/mods/src/misc/logging.cpp index 75321731..baf63360 100644 --- a/mods/src/misc/logging.cpp +++ b/mods/src/misc/logging.cpp @@ -45,7 +45,7 @@ void misc_add_message(Gui *gui, const char *text) { // 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 +53,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) { @@ -99,5 +99,5 @@ void _init_misc_logging() { overwrite_calls((void *) Level_saveLevelData, (void *) Level_saveLevelData_injection); // Disable stdout Buffering - setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stdout, nullptr, _IONBF, 0); } diff --git a/mods/src/misc/misc-internal.h b/mods/src/misc/misc-internal.h index 3f9e8853..806dc412 100644 --- a/mods/src/misc/misc-internal.h +++ b/mods/src/misc/misc-internal.h @@ -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(); diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c deleted file mode 100644 index 332bd81d..00000000 --- a/mods/src/misc/misc.c +++ /dev/null @@ -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(); -} diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp index ef0380ec..eac3dceb 100644 --- a/mods/src/misc/misc.cpp +++ b/mods/src/misc/misc.cpp @@ -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; +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 = nullptr; +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 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 *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, nullptr); + + // 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 = 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 *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 != 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 *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 = 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 *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 true; +} + +// 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 != 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 *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; + } +} + // 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 @@ -44,7 +664,7 @@ static void PauseScreen_init_injection(PauseScreen *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,7 +755,220 @@ 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((void *) Gui_renderHearts, (void *) 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 != 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((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); + } + // Implement AppPlatform::readAssetFile So Translations Work if (feature_has("Load Language Files", server_enabled)) { overwrite((void *) *AppPlatform_readAssetFile_vtable_addr, (void *) AppPlatform_readAssetFile_injection); @@ -160,4 +993,8 @@ void _init_misc_cpp() { if (feature_has("Display Date In Select World Screen", server_disabled)) { patch_address(AppPlatform_linux_getDateString_vtable_addr, (void *) AppPlatform_linux_getDateString_injection); } + + // Init Logging + _init_misc_logging(); + _init_misc_api(); } diff --git a/mods/src/options/options-internal.h b/mods/src/options/options-internal.h deleted file mode 100644 index 4c89a129..00000000 --- a/mods/src/options/options-internal.h +++ /dev/null @@ -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 diff --git a/mods/src/options/options.c b/mods/src/options/options.c deleted file mode 100644 index 400211fd..00000000 --- a/mods/src/options/options.c +++ /dev/null @@ -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(); -} diff --git a/mods/src/options/options.cpp b/mods/src/options/options.cpp index 2661a2c0..f6912791 100644 --- a/mods/src/options/options.cpp +++ b/mods/src/options/options.cpp @@ -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 +Options *stored_options = nullptr; +static void Options_initDefaultValue_injection(Options *options) { + // Call Original Method + Options_initDefaultValue(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 *minecraft) { + // Call Original Method + Minecraft_init_non_virtual(minecraft); + + Options *options = &minecraft->options; + // Enable Crosshair In Touch GUI + options->split_controls = true; + // 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); +} // 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 @@ -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((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); + // NOP unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" diff --git a/mods/src/override/override.c b/mods/src/override/override.cpp similarity index 77% rename from mods/src/override/override.c rename to mods/src/override/override.cpp index 6c38591f..e782095a 100644 --- a/mods/src/override/override.c +++ b/mods/src/override/override.cpp @@ -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 diff --git a/mods/src/readdir/readdir.c b/mods/src/readdir/readdir.c deleted file mode 100644 index 2ecf41bf..00000000 --- a/mods/src/readdir/readdir.c +++ /dev/null @@ -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; -} diff --git a/mods/src/readdir/readdir.cpp b/mods/src/readdir/readdir.cpp new file mode 100644 index 00000000..077f565e --- /dev/null +++ b/mods/src/readdir/readdir.cpp @@ -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; +} diff --git a/mods/src/screenshot/screenshot.c b/mods/src/screenshot/screenshot.cpp similarity index 92% rename from mods/src/screenshot/screenshot.c rename to mods/src/screenshot/screenshot.cpp index c967fbce..edbcd8d6 100644 --- a/mods/src/screenshot/screenshot.c +++ b/mods/src/screenshot/screenshot.cpp @@ -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++; } diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index 9af3d2eb..469f4ffd 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -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 diff --git a/mods/src/skin/loader.cpp b/mods/src/skin/loader.cpp index d3b09dee..2d2c6c79 100644 --- a/mods/src/skin/loader.cpp +++ b/mods/src/skin/loader.cpp @@ -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,7 +110,7 @@ static void *loader_thread(void *user_data) { // Free delete data; - return NULL; + return nullptr; } // Intercept Texture Creation @@ -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 diff --git a/mods/src/sound/repository.cpp b/mods/src/sound/repository.cpp index d9d521f3..7ce6fe56 100644 --- a/mods/src/sound/repository.cpp +++ b/mods/src/sound/repository.cpp @@ -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) { diff --git a/mods/src/sound/sound.cpp b/mods/src/sound/sound.cpp index 55abd9ab..6f44ef48 100644 --- a/mods/src/sound/sound.cpp +++ b/mods/src/sound/sound.cpp @@ -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; diff --git a/mods/src/test/test.c b/mods/src/test/test.cpp similarity index 100% rename from mods/src/test/test.c rename to mods/src/test/test.cpp diff --git a/mods/src/textures/headless.cpp b/mods/src/textures/headless.cpp index 9574c4e1..edfb3d83 100644 --- a/mods/src/textures/headless.cpp +++ b/mods/src/textures/headless.cpp @@ -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; diff --git a/mods/src/textures/textures.cpp b/mods/src/textures/textures.cpp index 6d6d3ceb..e9b886d6 100644 --- a/mods/src/textures/textures.cpp +++ b/mods/src/textures/textures.cpp @@ -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; diff --git a/mods/src/title-screen/title-screen.cpp b/mods/src/title-screen/title-screen.cpp index fc1d0d07..6f109f22 100644 --- a/mods/src/title-screen/title-screen.cpp +++ b/mods/src/title-screen/title-screen.cpp @@ -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)); } } diff --git a/mods/src/touch/touch.cpp b/mods/src/touch/touch.cpp index aa72f936..15207277 100644 --- a/mods/src/touch/touch.cpp +++ b/mods/src/touch/touch.cpp @@ -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; } diff --git a/mods/src/version/version.cpp b/mods/src/version/version.cpp index 86f1dbd2..54f2d6e3 100644 --- a/mods/src/version/version.cpp +++ b/mods/src/version/version.cpp @@ -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 diff --git a/symbols/src/game/options/Options.def b/symbols/src/game/options/Options.def index 556ba567..aa6a7365 100644 --- a/symbols/src/game/options/Options.def +++ b/symbols/src/game/options/Options.def @@ -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;