diff --git a/libreborn/include/libreborn/minecraft.h b/libreborn/include/libreborn/minecraft.h index b3d08fe..a3cf7a3 100644 --- a/libreborn/include/libreborn/minecraft.h +++ b/libreborn/include/libreborn/minecraft.h @@ -5,6 +5,11 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" +// bool In C +#ifndef __cplusplus +typedef uint32_t bool; +#endif + // Globals static char **default_path = (char **) 0xe264; // /.minecraft/ @@ -98,8 +103,11 @@ static Minecraft_releaseMouse_t Minecraft_releaseMouse = (Minecraft_releaseMouse typedef void (*Minecraft_grabMouse_t)(unsigned char *minecraft); static Minecraft_grabMouse_t Minecraft_grabMouse = (Minecraft_grabMouse_t) 0x15d10; +typedef void (*Minecraft_leaveGame_t)(unsigned char *minecraft, bool save_remote_level); +static Minecraft_leaveGame_t Minecraft_leaveGame = (Minecraft_leaveGame_t) 0x15ea0; + static uint32_t Minecraft_screen_width_property_offset = 0x20; // int32_t -static uint32_t Minecraft_server_side_network_handler_property_offset = 0x174; // ServerSideNetworkHandler * +static uint32_t Minecraft_network_handler_property_offset = 0x174; // NetEventCallback * static uint32_t Minecraft_rak_net_instance_property_offset = 0x170; // RakNetInstance * static uint32_t Minecraft_level_property_offset = 0x188; // Level * static uint32_t Minecraft_textures_property_offset = 0x164; // Textures * @@ -110,6 +118,7 @@ static uint32_t Minecraft_hit_result_property_offset = 0xc38; // HitResult static uint32_t Minecraft_progress_property_offset = 0xc60; // int32_t static uint32_t Minecraft_command_server_property_offset = 0xcc0; // CommandServer * static uint32_t Minecraft_screen_property_offset = 0xc10; // Screen * +static uint32_t Minecraft_gui_property_offset = 0x198; // Gui // CommandServer @@ -147,14 +156,31 @@ static Player_isUsingItem_t Player_isUsingItem = (Player_isUsingItem_t) 0x8f15c; static uint32_t Player_username_property_offset = 0xbf4; // char * +// Entity + +typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause); +static uint32_t Entity_die_vtable_offset = 0x130; + +// Mob + +typedef void (*Mob_actuallyHurt_t)(unsigned char *entity, int32_t damage); +static Mob_actuallyHurt_t Mob_actuallyHurt = (Mob_actuallyHurt_t) 0x7f11c; + +static uint32_t Mob_health_property_offset = 0xec; // int32_t + // LocalPlayer +static Mob_actuallyHurt_t LocalPlayer_actuallyHurt = (Mob_actuallyHurt_t) 0x44010; +static void *LocalPlayer_actuallyHurt_vtable_addr = (void *) 0x10639c; + static void *LocalPlayer_openTextEdit_vtable_addr = (void *) 0x106460; static uint32_t LocalPlayer_minecraft_property_offset = 0xc90; // Minecraft * // ServerPlayer +static void *ServerPlayer_actuallyHurt_vtable_addr = (void *) 0x109fa4; + static uint32_t ServerPlayer_minecraft_property_offset = 0xc8c; // Minecraft * static uint32_t ServerPlayer_guid_property_offset = 0xc08; // RakNetGUID @@ -169,9 +195,17 @@ static Gui_handleClick_t Gui_handleClick = (Gui_handleClick_t) 0x2599c; typedef void (*Gui_renderOnSelectItemNameText_t)(unsigned char *gui, int32_t param_1, unsigned char *font, int32_t param_2); static Gui_renderOnSelectItemNameText_t Gui_renderOnSelectItemNameText = (Gui_renderOnSelectItemNameText_t) 0x26aec; +typedef void (*Gui_renderChatMessages_t)(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font); +static Gui_renderChatMessages_t Gui_renderChatMessages = (Gui_renderChatMessages_t) 0x273d8; + static uint32_t Gui_minecraft_property_offset = 0x9f4; // Minecraft * static uint32_t Gui_selected_item_text_timer_property_offset = 0x9fc; // float +// Textures + +typedef void (*Textures_tick_t)(unsigned char *textures, bool param_1); +static Textures_tick_t Textures_tick = (Textures_tick_t) 0x531c4; + // GameMode Constructors #define CREATOR_MODE_SIZE 0x18 @@ -274,6 +308,14 @@ static uint32_t RakNetInstance_peer_property_offset = 0x4; typedef struct RakNet_SystemAddress (*RakNet_RakPeer_GetSystemAddressFromGuid_t)(unsigned char *rak_peer, struct RakNet_RakNetGUID guid); static uint32_t RakNet_RakPeer_GetSystemAddressFromGuid_vtable_offset = 0xd0; +typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rak_peer, const char *ip); +static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4; + +// RakNet::SystemAddress + +typedef char *(*RakNet_SystemAddress_ToString_t)(struct RakNet_SystemAddress *system_address, bool print_delimiter, char delimiter); +static RakNet_SystemAddress_ToString_t RakNet_SystemAddress_ToString = (RakNet_SystemAddress_ToString_t) 0xd6198; + // ServerSideNetworkHandler typedef void (*ServerSideNetworkHandler_onDisconnect_t)(unsigned char *server_side_network_handler, unsigned char *guid); @@ -283,13 +325,10 @@ static void *ServerSideNetworkHandler_onDisconnect_vtable_addr = (void *) 0x109b typedef unsigned char *(*ServerSideNetworkHandler_getPlayer_t)(unsigned char *server_side_network_handler, unsigned char *guid); static ServerSideNetworkHandler_getPlayer_t ServerSideNetworkHandler_getPlayer = (ServerSideNetworkHandler_getPlayer_t) 0x75464; +typedef void (*ServerSideNetworkHandler_handle_t)(unsigned char *server_side_network_handler, unsigned char *rak_net_guid, unsigned char *packet); + static void *ServerSideNetworkHandler_handle_ChatPacket_vtable_addr = (void *) 0x109c60; -// Entity - -typedef void (*Entity_die_t)(unsigned char *entity, unsigned char *cause); -static uint32_t Entity_die_vtable_offset = 0x130; - // Inventory typedef void (*Inventory_selectSlot_t)(unsigned char *inventory, int32_t slot); @@ -326,6 +365,11 @@ static ItemRenderer_renderGuiItemCorrect_t ItemRenderer_renderGuiItemCorrect = ( // Structures +struct AppPlatform_readAssetFile_return_value { + char *data; + int32_t length; +}; + struct ConnectedClient { uint32_t sock; std::string str; @@ -337,10 +381,6 @@ struct ConnectedClient { typedef void (*AppPlatform_saveScreenshot_t)(unsigned char *app_platform, std::string const& param1, std::string const& param_2); static void *AppPlatform_linux_saveScreenshot_vtable_addr = (void *) 0x102160; -struct AppPlatform_readAssetFile_return_value { - char *data; - int32_t length; -}; typedef AppPlatform_readAssetFile_return_value (*AppPlatform_readAssetFile_t)(unsigned char *app_platform, std::string const& path); static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_readAssetFile_t) 0x12b10; @@ -349,9 +389,6 @@ static AppPlatform_readAssetFile_t AppPlatform_readAssetFile = (AppPlatform_read typedef void (*Minecraft_selectLevel_t)(unsigned char *minecraft, std::string const& level_dir, std::string const& level_name, LevelSettings const& vsettings); static Minecraft_selectLevel_t Minecraft_selectLevel = (Minecraft_selectLevel_t) 0x16f38; -typedef void (*Minecraft_leaveGame_t)(unsigned char *minecraft, bool save_remote_level); -static Minecraft_leaveGame_t Minecraft_leaveGame = (Minecraft_leaveGame_t) 0x15ea0; - // CommandServer typedef std::string (*CommandServer_parse_t)(unsigned char *command_server, struct ConnectedClient &client, std::string const& command); @@ -367,24 +404,6 @@ static Level_addParticle_t Level_addParticle = (Level_addParticle_t) 0xa449c; typedef void (*Gui_addMessage_t)(unsigned char *gui, std::string const& text); static Gui_addMessage_t Gui_addMessage = (Gui_addMessage_t) 0x27820; -typedef void (*Gui_renderChatMessages_t)(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font); -static Gui_renderChatMessages_t Gui_renderChatMessages = (Gui_renderChatMessages_t) 0x273d8; - -// Textures - -typedef void (*Textures_tick_t)(unsigned char *textures, bool param_1); -static Textures_tick_t Textures_tick = (Textures_tick_t) 0x531c4; - -// RakNet::RakPeer - -typedef bool (*RakNet_RakPeer_IsBanned_t)(unsigned char *rak_peer, const char *ip); -static RakNet_RakPeer_IsBanned_t RakNet_RakPeer_IsBanned = (RakNet_RakPeer_IsBanned_t) 0xda3b4; - -// RakNet::SystemAddress - -typedef char *(*RakNet_SystemAddress_ToString_t)(struct RakNet_SystemAddress *system_address, bool print_delimiter, char delimiter); -static RakNet_SystemAddress_ToString_t RakNet_SystemAddress_ToString = (RakNet_SystemAddress_ToString_t) 0xd6198; - // ServerSideNetworkHandler typedef void (*ServerSideNetworkHandler_displayGameMessage_t)(unsigned char *server_side_network_handler, std::string const& message); diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp index 4832848..b0ee998 100644 --- a/mods/src/chat/chat.cpp +++ b/mods/src/chat/chat.cpp @@ -49,7 +49,7 @@ static void CommandServer_parse_CommandServer_dispatchPacket_injection(unsigned if ((*RakNetInstance_isServer)(rak_net_instance)) { // Hosting Multiplayer char *message = *(char **) (packet + ChatPacket_message_property_offset); - unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_server_side_network_handler_property_offset); + unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset); send_message(server_side_network_handler, *default_username, message); } else { // Client diff --git a/mods/src/chat/ui.c b/mods/src/chat/ui.c index 7fa1c4a..1f01a41 100644 --- a/mods/src/chat/ui.c +++ b/mods/src/chat/ui.c @@ -78,6 +78,7 @@ static void *chat_thread(__attribute__((unused)) void *nop) { char *output = run_command("echo \"${CHAT_WINDOW_TCL}\" | wish -name \"Minecraft - Pi edition\"", &return_code); // Handle Message if (output != NULL) { + // Check Return Code if (return_code == 0) { // Remove Ending Newline int length = strlen(output); @@ -85,10 +86,13 @@ static void *chat_thread(__attribute__((unused)) void *nop) { output[length - 1] = '\0'; } length = strlen(output); - // Submit - chat_queue_message(output); + // Don't Allow Empty Strings + if (length > 0) { + // Submit + chat_queue_message(output); + } } - // Free + // Free Output free(output); } // Update Counter diff --git a/mods/src/misc/misc.c b/mods/src/misc/misc.c index 2222dcf..7765209 100644 --- a/mods/src/misc/misc.c +++ b/mods/src/misc/misc.c @@ -8,6 +8,38 @@ #define NEW_PATH "/.minecraft-pi/" +// Render Selected Item Text +static void Gui_renderChatMessages_injection(unsigned char *gui, int32_t param_1, uint32_t param_2, uint32_t param_3, unsigned char *font) { + // Call Original Method + (*Gui_renderChatMessages)(gui, param_1, param_2, param_3, font); + // Calculate Selected Item Text Scale + unsigned char *minecraft = *(unsigned char **) (gui + Gui_minecraft_property_offset); + int32_t screen_width = *(int32_t *) (minecraft + Minecraft_screen_width_property_offset); + float scale = ((float) screen_width) * *InvGuiScale; + // Render Selected Item Text + (*Gui_renderOnSelectItemNameText)(gui, (int32_t) scale, font, param_1 - 0x13); +} +// Reset Selected Item Text Timer On Slot Select +static uint32_t reset_selected_item_text_timer = 0; +static void Gui_tick_injection(unsigned char *gui) { + // Call Original Method + (*Gui_tick)(gui); + // Handle Reset + float *selected_item_text_timer = (float *) (gui + Gui_selected_item_text_timer_property_offset); + 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(unsigned char *inventory, int32_t slot) { + // Call Original Method + (*Inventory_selectSlot)(inventory, slot); + // Trigger Reset Selected Item Text Timer + reset_selected_item_text_timer = 1; +} + void init_misc() { // Store Data In ~/.minecraft-pi Instead Of ~/.minecraft patch_address((void *) default_path, (void *) NEW_PATH); @@ -18,6 +50,11 @@ void init_misc() { patch((void *) 0x63c98, invalid_item_background_patch); } + // Fix Selected Item Text + 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); + // Init C++ init_misc_cpp(); } \ No newline at end of file diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp index ce9c06f..ffb5a20 100644 --- a/mods/src/misc/misc.cpp +++ b/mods/src/misc/misc.cpp @@ -25,6 +25,7 @@ static AppPlatform_readAssetFile_return_value AppPlatform_readAssetFile_injectio return ret; } +// Add Item To Inventory static void inventory_add_item(unsigned char *inventory, unsigned char *item, bool is_tile) { unsigned char *item_instance = (unsigned char *) ::operator new(ITEM_INSTANCE_SIZE); ALLOC_CHECK(item_instance); @@ -67,38 +68,6 @@ static int32_t Inventory_setupDefault_FillingContainer_addItem_call_injection(un return ret; } -// Render Selected Item Text -static void Gui_renderChatMessages_injection(unsigned char *gui, int32_t param_1, uint32_t param_2, bool param_3, unsigned char *font) { - // Call Original Method - (*Gui_renderChatMessages)(gui, param_1, param_2, param_3, font); - // Calculate Selected Item Text Scale - unsigned char *minecraft = *(unsigned char **) (gui + Gui_minecraft_property_offset); - int32_t screen_width = *(int32_t *) (minecraft + Minecraft_screen_width_property_offset); - float scale = ((float) screen_width) * *InvGuiScale; - // Render Selected Item Text - (*Gui_renderOnSelectItemNameText)(gui, (int32_t) scale, font, param_1 - 0x13); -} -// Reset Selected Item Text Timer On Slot Select -static bool reset_selected_item_text_timer = false; -static void Gui_tick_injection(unsigned char *gui) { - // Call Original Method - (*Gui_tick)(gui); - // Handle Reset - float *selected_item_text_timer = (float *) (gui + Gui_selected_item_text_timer_property_offset); - if (reset_selected_item_text_timer) { - // Reset - *selected_item_text_timer = 0; - reset_selected_item_text_timer = false; - } -} -// Trigger Reset Selected Item Text Timer On Slot Select -static void Inventory_selectSlot_injection(unsigned char *inventory, int32_t slot) { - // Call Original Method - (*Inventory_selectSlot)(inventory, slot); - // Trigger Reset Selected Item Text Timer - reset_selected_item_text_timer = true; -} - // Print Chat To Log static bool Gui_addMessage_recursing = false; static void Gui_addMessage_injection(unsigned char *gui, std::string const& text) { @@ -120,6 +89,57 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text } } +// Death Messages +static std::string get_death_message(unsigned char *player) { + // Get Username + char *username = *(char **) (player + Player_username_property_offset); + + // Prepare Death Message + std::string message; + message.append(username); + message.append(" has died"); + + // Return + return message; +} +// Common Death Message Logic +static void Player_actuallyHurt_injection_helper(unsigned char *player, int32_t damage, bool is_local_player) { + // Store Old Health + int32_t old_health = *(int32_t *) (player + Mob_health_property_offset); + + // Call Original Method + (*(is_local_player ? LocalPlayer_actuallyHurt : Mob_actuallyHurt))(player, damage); + + // Store New Health + int32_t health = *(int32_t *) (player + Mob_health_property_offset); + + // Get Variables + unsigned char *minecraft = *(unsigned char **) (player + (is_local_player ? LocalPlayer_minecraft_property_offset : ServerPlayer_minecraft_property_offset)); + unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset); + unsigned char *rak_net_instance_vtable = *(unsigned char **) rak_net_instance; + // Only Run On Server-Side + RakNetInstance_isServer_t RakNetInstance_isServer = *(RakNetInstance_isServer_t *) (rak_net_instance_vtable + RakNetInstance_isServer_vtable_offset); + if ((*RakNetInstance_isServer)(rak_net_instance)) { + // Check Health + if (health < 1 && old_health >= 1) { + // Get Death Message + std::string message = get_death_message(player); + + // Post Death Message + unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset); + (*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, message); + } + } +} +// ServerPlayer Death Message Logic +static void ServerPlayer_actuallyHurt_injection(unsigned char *player, int32_t damage) { + Player_actuallyHurt_injection_helper(player, damage, false); +} +// LocalPlayer Death Message Logic +static void LocalPlayer_actuallyHurt_injection(unsigned char *player, int32_t damage) { + Player_actuallyHurt_injection_helper(player, damage, true); +} + void init_misc_cpp() { // Implement AppPlatform::readAssetFile So Translations Work overwrite((void *) AppPlatform_readAssetFile, (void *) AppPlatform_readAssetFile_injection); @@ -129,11 +149,10 @@ void init_misc_cpp() { overwrite_call((void *) 0x8e0fc, (void *) Inventory_setupDefault_FillingContainer_addItem_call_injection); } - // Fix Selected Item Text - 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); - // Print Chat To Log overwrite_calls((void *) Gui_addMessage, (void *) Gui_addMessage_injection); + + // Death Messages + patch_address(ServerPlayer_actuallyHurt_vtable_addr, (void *) ServerPlayer_actuallyHurt_injection); + patch_address(LocalPlayer_actuallyHurt_vtable_addr, (void *) LocalPlayer_actuallyHurt_injection); } \ No newline at end of file diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index aa4bd2f..7f9b221 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -267,7 +267,7 @@ static void handle_server_stop(unsigned char *minecraft) { // Get ServerSideNetworkHandler From Minecraft static unsigned char *get_server_side_network_handler(unsigned char *minecraft) { - return *(unsigned char **) (minecraft + Minecraft_server_side_network_handler_property_offset); + return *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset); } // Handle Commands