diff --git a/mods/include/mods/chat/chat.h b/mods/include/mods/chat/chat.h index 0626602c..f80ea70a 100644 --- a/mods/include/mods/chat/chat.h +++ b/mods/include/mods/chat/chat.h @@ -10,8 +10,10 @@ extern "C" { std::string chat_send_api_command(const Minecraft *minecraft, const std::string &str); // Override using the HOOK() macro to provide customized chat behavior. -void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, const char *username, const char *message); +void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, Entity *sender, const char *message); void chat_handle_packet_send(const Minecraft *minecraft, ChatPacket *packet); +void chat_set_already_added(bool already_added); +bool chat_already_added(); bool chat_is_sending(); } diff --git a/mods/include/mods/misc/misc.h b/mods/include/mods/misc/misc.h index 731a8b42..e84b346b 100644 --- a/mods/include/mods/misc/misc.h +++ b/mods/include/mods/misc/misc.h @@ -27,11 +27,13 @@ void misc_run_on_game_key_press(const std::function &fun void misc_run_on_key_press(const std::function &func); void misc_run_on_creative_inventory_setup(const std::function &function); void misc_run_on_swap_buffers(const std::function &function); -std::string misc_get_player_username(Player *player, bool convert_to_utf = false); +std::string misc_get_player_username(Player *player); std::map &misc_get_entity_names(); -std::string misc_get_entity_name(Entity *entity); -std::string misc_get_entity_name_upper(Entity *entity); +std::string misc_get_entity_type_name(Entity *entity); +std::string misc_get_entity_name(Entity *entity, bool convert_to_utf = false); +std::string misc_get_entity_name_upper(Entity *entity, bool convert_to_utf = false); Entity *misc_make_entity_from_id(Level *level, int id); +void api_add_chat_event(Entity *sender, const std::string &message); std::string misc_base64_encode(const std::string &data); std::string misc_base64_decode(const std::string &input); diff --git a/mods/src/api/api.cpp b/mods/src/api/api.cpp index e47cc165..88ce368b 100644 --- a/mods/src/api/api.cpp +++ b/mods/src/api/api.cpp @@ -72,7 +72,7 @@ static std::string getEntityData(CommandServer *commandserver, Entity *entity) { // type std::to_string(entity->getEntityTypeId()) + "," + // name - empty_fallback(misc_get_entity_name_upper(entity), entity->id) + "," + + empty_fallback(misc_get_entity_name_upper(entity, true), entity->id) + "," + // x std::to_string(x) + "," + // y @@ -278,7 +278,7 @@ std::string CommandServer_parse_injection(CommandServer_parse_t old, CommandServ if (entity == NULL) { WARN("Player (or Entity) [%i] not found in entity.getName.", id); } - return empty_fallback(misc_get_entity_name_upper(entity), entity->id) + "\n"; + return empty_fallback(misc_get_entity_name_upper(entity, true), entity->id) + "\n"; } else if (cmd == "world.getEntities") { int type; int ret = sscanf(args.c_str(), "%d", &type); @@ -661,21 +661,31 @@ static void Throwable_tick_Throwable_onHit_injection(Throwable *self, HitResult static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, const std::string &text) { static bool recursing = false; - if (recursing) { + if (recursing || chat_already_added()) { + chat_set_already_added(false); original(gui, text); } else { - chatEvents.push(ChatEvent{ - text.substr(gui->minecraft->player->username.size() + 3), - chat_is_sending() ? gui->minecraft->player->id : 0 - }); + if (chat_is_sending()) { + std::string message = text.substr(gui->minecraft->player->username.size() + 3); + api_add_chat_event((Entity *) gui->minecraft->player, text); + } else { + api_add_chat_event(NULL, text); + } recursing = true; original(gui, text); recursing = false; } } +bool enabled = false; +void api_add_chat_event(Entity *sender, const std::string &message) { + if (!enabled) return; + chatEvents.push(ChatEvent{message, sender ? sender->id : 0}); +} + void init_api() { if (feature_has("Implement RaspberryJuice API", server_enabled)) { + enabled = true; overwrite_calls(CommandServer_parse, CommandServer_parse_injection); overwrite_calls(Arrow_tick, Arrow_tick_injection); overwrite_call((void *) 0x8b1e8, (void *) Arrow_tick_HitResult_constructor_injection); diff --git a/mods/src/chat/chat.cpp b/mods/src/chat/chat.cpp index 7bda7ad9..dc6e51f2 100644 --- a/mods/src/chat/chat.cpp +++ b/mods/src/chat/chat.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include "chat-internal.h" @@ -34,7 +35,22 @@ static void send_api_chat_command(const Minecraft *minecraft, const char *str) { std::string _chat_get_prefix(const char *username) { return std::string("<") + username + "> "; } -void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, const char *username, const char *message) { +static bool _chat_already_added = false; +bool chat_already_added() { + return _chat_already_added; +} +void chat_set_already_added(bool already_added) { + _chat_already_added = already_added; +} +void chat_send_message(ServerSideNetworkHandler *server_side_network_handler, Entity *sender, const char *message) { + const char *username = NULL; + if (sender && sender->isPlayer()) { + _chat_already_added = true; + api_add_chat_event(sender, message); + username = ((Player *) sender)->username.c_str(); + } else { + username = Strings::default_username; + } std::string full_message = _chat_get_prefix(username) + message; char *raw_str = strdup(full_message.c_str()); ALLOC_CHECK(raw_str); @@ -50,7 +66,7 @@ void chat_handle_packet_send(const Minecraft *minecraft, ChatPacket *packet) { // Hosting Multiplayer const char *message = packet->message.c_str(); ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) minecraft->network_handler; - chat_send_message(server_side_network_handler, Strings::default_username, (char *) message); + chat_send_message(server_side_network_handler, NULL, (char *) message); } else { // Client rak_net_instance->send(*(Packet *) packet); @@ -69,9 +85,8 @@ static void CommandServer_parse_CommandServer_dispatchPacket_injection(const Com static void ServerSideNetworkHandler_handle_ChatPacket_injection(ServerSideNetworkHandler *server_side_network_handler, const RakNet_RakNetGUID &rak_net_guid, ChatPacket *chat_packet) { const Player *player = server_side_network_handler->getPlayer(rak_net_guid); 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, username, message); + chat_send_message(server_side_network_handler, (Entity *) player, message); } } diff --git a/mods/src/f3/f3.cpp b/mods/src/f3/f3.cpp index 1be17e94..5b034d54 100644 --- a/mods/src/f3/f3.cpp +++ b/mods/src/f3/f3.cpp @@ -128,13 +128,8 @@ static std::vector get_debug_info_right(const Minecraft *minecraft) z = entity->z; type = "Entity"; type_info.push_back("ID: " + std::to_string(entity->id)); - std::string type_str = "Type: "; - if (entity->isPlayer()) { - type_str += "Player"; - } else { - type_str += misc_get_entity_names()[entity->getEntityTypeId()]; - } - type_str += " (" + std::to_string(entity->getEntityTypeId()) + ")"; + std::string type_str = "Type: " + misc_get_entity_type_name(entity) + + " (" + std::to_string(entity->getEntityTypeId()) + ")"; type_info.push_back(type_str); if (entity->isMob()) { Mob *mob = (Mob *) entity; diff --git a/mods/src/misc/api.cpp b/mods/src/misc/api.cpp index 7caca8e9..601cc7ee 100644 --- a/mods/src/misc/api.cpp +++ b/mods/src/misc/api.cpp @@ -135,8 +135,7 @@ void misc_render_background(int color, const Minecraft *minecraft, const int x, } // Get Player's Username -std::string misc_get_player_username(Player *player, bool convert_to_utf) { - if (!convert_to_utf) return player->username; +std::string misc_get_player_username(Player *player) { const std::string *username = &player->username; char *safe_username_c = from_cp437(username->c_str()); std::string safe_username = safe_username_c; @@ -146,8 +145,6 @@ std::string misc_get_player_username(Player *player, bool convert_to_utf) { std::map &misc_get_entity_names() { static std::map entity_names = { - // Unsavables - {0, "Unknown"}, // Animals {10, "Chicken"}, {11, "Cow"}, {12, "Pig"}, {13, "Sheep"}, // Hostiles @@ -161,27 +158,36 @@ std::map &misc_get_entity_names() { }; -std::string misc_get_entity_name(Entity *entity) { - if (entity == NULL) { - return ""; - } else if (entity->isPlayer()) { - return misc_get_player_username((Player *) entity); - } else { - int type = entity->getEntityTypeId(); - std::map &names = misc_get_entity_names(); - if (names.find(type) != names.end()) return names[type]; - return ""; - } +std::string misc_get_entity_name(Entity *entity, bool convert_to_utf) { + if (!entity) return ""; + if (entity->isPlayer()) return convert_to_utf ? misc_get_player_username((Player *) entity) : ((Player *) entity)->username; + return misc_get_entity_type_name(entity); } -std::string misc_get_entity_name_upper(Entity *entity) { - std::string ret = misc_get_entity_name(entity); +std::string misc_get_entity_name_upper(Entity *entity, bool convert_to_utf) { + std::string ret = misc_get_entity_name(entity, convert_to_utf); if (entity != NULL && !entity->isPlayer()) { for (char &c : ret) c = toupper(c); } return ret; } +std::string misc_get_entity_type_name(Entity *entity) { + if (!entity) { + return ""; + } else if (entity->isPlayer()) { + return "Player"; + } else { + int type = entity->getEntityTypeId(); + if (type == 0 && entity->vtable == (Entity_vtable *) Particle_vtable_base) return "Particle"; + if (type == 0 && entity->vtable == (Entity_vtable *) TripodCamera_vtable_base) return "TripodCamera"; + if (type == 0 && entity->vtable == (Entity_vtable *) CameraEntity_vtable_base) return "CameraEntity"; + std::map &names = misc_get_entity_names(); + if (names.find(type) != names.end()) return names[type]; + return ""; + } +} + Entity *misc_make_entity_from_id(Level *level, int id) { if (id < 0x40) { return (Entity *) MobFactory::CreateMob(id, level); diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index eaf59bbd..b9a05176 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -129,7 +129,7 @@ static void find_players(Minecraft *minecraft, const std::string &target_usernam for (std::size_t i = 0; i < players.size(); i++) { // Iterate Players Player *player = players[i]; - std::string username = misc_get_player_username(player, true); + std::string username = misc_get_player_username(player); if (all_players || username == target_username) { // Run Callback callback(minecraft, username, player); diff --git a/symbols/CMakeLists.txt b/symbols/CMakeLists.txt index bea7c21b..ffc13a51 100644 --- a/symbols/CMakeLists.txt +++ b/symbols/CMakeLists.txt @@ -70,6 +70,7 @@ set(SRC src/entity/Arrow.def src/entity/ArrowRenderer.def src/entity/PaintingRenderer.def + src/entity/Particle.def src/entity/Throwable.def src/level/container/FillingContainer.def src/level/container/Container.def diff --git a/symbols/src/entity/Particle.def b/symbols/src/entity/Particle.def new file mode 100644 index 00000000..a236bf9f --- /dev/null +++ b/symbols/src/entity/Particle.def @@ -0,0 +1,3 @@ +extends Entity; + +vtable 0x105b68; \ No newline at end of file