diff --git a/.gitignore b/.gitignore index 19fef48..8563b98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ out debian/tmp .vscode -build +build* CMakeLists.txt.user *.autosave AppImageBuilder.yml diff --git a/example-mod/.gitignore b/example-mod/.gitignore deleted file mode 100644 index 378eac2..0000000 --- a/example-mod/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/example-mod/README.md b/example-mods/README.md similarity index 58% rename from example-mod/README.md rename to example-mods/README.md index 0ce6607..3f4f2a3 100644 --- a/example-mod/README.md +++ b/example-mods/README.md @@ -1,7 +1,8 @@ -# Example Mod +# Example Mods This is an example of a mod that cane be built using the modding SDK. -This specific mod adds even more items and blocks to the Creative Inventory. It was originally by [@Bigjango13](https://github.com/bigjango13). +* **Expanded Creative Mod**: This specific mod adds even more items and blocks to the Creative Inventory. It was originally by [@Bigjango13](https://github.com/bigjango13). +* **Chat Commands Mod**: This specific mod makes an chat message starting with a ``/`` handled by the MCPI API. ## The SDK The modding SDK is a collection of exported CMake targets that allows anyone to create their own MCPI mod! diff --git a/example-mods/chat-commands/.gitignore b/example-mods/chat-commands/.gitignore new file mode 100644 index 0000000..8563b98 --- /dev/null +++ b/example-mods/chat-commands/.gitignore @@ -0,0 +1,14 @@ +out +debian/tmp +.vscode +build* +CMakeLists.txt.user +*.autosave +AppImageBuilder.yml +appimage-builder-cache +appimage-build +AppDir +*.zsync +*.AppImage +core* +qemu_* diff --git a/example-mods/chat-commands/CMakeLists.txt b/example-mods/chat-commands/CMakeLists.txt new file mode 100644 index 0000000..84fef6a --- /dev/null +++ b/example-mods/chat-commands/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.16.0) + +# Build For ARM +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) +set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) + +# Start Project +project(chat-commands) + +# Include SDK +include("$ENV{HOME}/.minecraft-pi/sdk/lib/minecraft-pi-reborn-client/sdk/sdk.cmake") + +# Build +add_library(chat-commands SHARED chat-commands.cpp) +target_link_libraries(chat-commands mods-headers reborn-patch symbols chat misc) diff --git a/example-mods/chat-commands/chat-commands.cpp b/example-mods/chat-commands/chat-commands.cpp new file mode 100644 index 0000000..64e0f6a --- /dev/null +++ b/example-mods/chat-commands/chat-commands.cpp @@ -0,0 +1,25 @@ +// Headers + +#include +#include +#include +#include + +// The Actual Mod +HOOK(chat_handle_packet_send, void, (unsigned char *minecraft, unsigned char *packet)) { + // Get Message + char *message = *(char **) (packet + ChatPacket_message_property_offset); + if (message[0] == '/') { + // API Command + unsigned char *gui = minecraft + Minecraft_gui_property_offset; + std::string out = chat_send_api_command(minecraft, &message[1]); + if (out.length() > 0 && out[out.length() - 1] == '\n') { + out[out.length() - 1] = '\0'; + } + misc_add_message(gui, out.c_str()); + } else { + // Call Original Method + ensure_chat_handle_packet_send(); + (*real_chat_handle_packet_send)(minecraft, packet); + } +} diff --git a/example-mods/expanded-creative/.gitignore b/example-mods/expanded-creative/.gitignore new file mode 100644 index 0000000..8563b98 --- /dev/null +++ b/example-mods/expanded-creative/.gitignore @@ -0,0 +1,14 @@ +out +debian/tmp +.vscode +build* +CMakeLists.txt.user +*.autosave +AppImageBuilder.yml +appimage-builder-cache +appimage-build +AppDir +*.zsync +*.AppImage +core* +qemu_* diff --git a/example-mod/CMakeLists.txt b/example-mods/expanded-creative/CMakeLists.txt similarity index 100% rename from example-mod/CMakeLists.txt rename to example-mods/expanded-creative/CMakeLists.txt diff --git a/example-mod/expanded-creative.cpp b/example-mods/expanded-creative/expanded-creative.cpp similarity index 100% rename from example-mod/expanded-creative.cpp rename to example-mods/expanded-creative/expanded-creative.cpp diff --git a/mods/include/mods/chat/chat.h b/mods/include/mods/chat/chat.h index 4e2a90d..36caba2 100644 --- a/mods/include/mods/chat/chat.h +++ b/mods/include/mods/chat/chat.h @@ -2,6 +2,12 @@ #include +#ifdef __cplusplus +#include +// Send API Command +std::string chat_send_api_command(unsigned char *minecraft, char *str); +#endif + #ifdef __cplusplus extern "C" { #endif @@ -13,6 +19,7 @@ unsigned int chat_get_counter(); // Override using the HOOK() macro to provide customized chat behavior. void chat_send_message(unsigned char *server_side_network_handler, char *username, char *message); +void chat_handle_packet_send(unsigned char *minecraft, unsigned char *packet); #ifdef __cplusplus } diff --git a/mods/include/mods/misc/misc.h b/mods/include/mods/misc/misc.h index efcf612..3995ae2 100644 --- a/mods/include/mods/misc/misc.h +++ b/mods/include/mods/misc/misc.h @@ -10,6 +10,9 @@ void misc_run_on_tick(misc_update_function_t function); void Level_saveLevelData_injection(unsigned char *level); +// Use this instead of directly calling Gui::addMessage(), it has proper logging! +void misc_add_message(unsigned char *gui, const char *text); + #ifdef __cplusplus } #endif diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp index 92022f7..6b75335 100644 --- a/mods/src/chat/chat.cpp +++ b/mods/src/chat/chat.cpp @@ -29,22 +29,25 @@ int _chat_enabled = 0; #define MAX_CHAT_MESSAGE_LENGTH 512 // Send API Command -#ifndef MCPI_SERVER_MODE -static void send_api_command(unsigned char *minecraft, char *str) { +std::string chat_send_api_command(unsigned char *minecraft, char *str) { struct ConnectedClient client; client.sock = -1; client.str = ""; client.time = 0; unsigned char *command_server = *(unsigned char **) (minecraft + Minecraft_command_server_property_offset); if (command_server != NULL) { - (*CommandServer_parse)(command_server, client, str); + return (*CommandServer_parse)(command_server, client, str); + } else { + return ""; } } + +#ifndef MCPI_SERVER_MODE // Send API Chat Command static void send_api_chat_command(unsigned char *minecraft, char *str) { char *command = NULL; safe_asprintf(&command, "chat.post(%s)\n", str); - send_api_command(minecraft, command); + chat_send_api_command(minecraft, command); free(command); } #endif @@ -57,24 +60,28 @@ void chat_send_message(unsigned char *server_side_network_handler, char *usernam (*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, std::string(full_message)); free(full_message); } +// Handle Chat packet Send +void chat_handle_packet_send(unsigned char *minecraft, unsigned char *packet) { + unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset); + unsigned char *rak_net_instance_vtable = *(unsigned char **) rak_net_instance; + RakNetInstance_isServer_t RakNetInstance_isServer = *(RakNetInstance_isServer_t *) (rak_net_instance_vtable + RakNetInstance_isServer_vtable_offset); + if ((*RakNetInstance_isServer)(rak_net_instance)) { + // Hosting Multiplayer + char *message = *(char **) (packet + ChatPacket_message_property_offset); + unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset); + chat_send_message(server_side_network_handler, *default_username, message); + } else { + // Client + RakNetInstance_send_t RakNetInstance_send = *(RakNetInstance_send_t *) (rak_net_instance_vtable + RakNetInstance_send_vtable_offset); + (*RakNetInstance_send)(rak_net_instance, packet); + } +} // Manually Send (And Loopback) ChatPacket static void CommandServer_parse_CommandServer_dispatchPacket_injection(unsigned char *command_server, unsigned char *packet) { unsigned char *minecraft = *(unsigned char **) (command_server + CommandServer_minecraft_property_offset); if (minecraft != NULL) { - unsigned char *rak_net_instance = *(unsigned char **) (minecraft + Minecraft_rak_net_instance_property_offset); - unsigned char *rak_net_instance_vtable = *(unsigned char **) rak_net_instance; - RakNetInstance_isServer_t RakNetInstance_isServer = *(RakNetInstance_isServer_t *) (rak_net_instance_vtable + RakNetInstance_isServer_vtable_offset); - if ((*RakNetInstance_isServer)(rak_net_instance)) { - // Hosting Multiplayer - char *message = *(char **) (packet + ChatPacket_message_property_offset); - unsigned char *server_side_network_handler = *(unsigned char **) (minecraft + Minecraft_network_handler_property_offset); - chat_send_message(server_side_network_handler, *default_username, message); - } else { - // Client - RakNetInstance_send_t RakNetInstance_send = *(RakNetInstance_send_t *) (rak_net_instance_vtable + RakNetInstance_send_vtable_offset); - (*RakNetInstance_send)(rak_net_instance, packet); - } + chat_handle_packet_send(minecraft, packet); } } diff --git a/mods/src/misc/logging.cpp b/mods/src/misc/logging.cpp index 4554e8b..df9b918 100644 --- a/mods/src/misc/logging.cpp +++ b/mods/src/misc/logging.cpp @@ -35,6 +35,9 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text // Free free(new_message); } +void misc_add_message(unsigned char *gui, const char *text) { + Gui_addMessage_injection(gui, text); +} // Print Progress Reports static int last_progress = -1;