From a5e223859ca7d0b496b14124e646992ace46b2df Mon Sep 17 00:00:00 2001 From: Bigjango13 Date: Mon, 29 Jan 2024 22:17:01 -0500 Subject: [PATCH] Add Death Messages --- mods/src/death/death.cpp | 113 ++++++++++++++++++--- symbols/src/entity/Entity.def | 9 ++ symbols/src/tile/entity/SignTileEntity.def | 1 + 3 files changed, 109 insertions(+), 14 deletions(-) diff --git a/mods/src/death/death.cpp b/mods/src/death/death.cpp index 995829a..8ea2faa 100644 --- a/mods/src/death/death.cpp +++ b/mods/src/death/death.cpp @@ -7,55 +7,140 @@ #include // Death Messages -static std::string get_death_message(Player *player) { - // Get Username - std::string *username = &player->username; - +static const char *monster_names[] = {"Zombie", "Creeper", "Skeleton", "Spider", "Zombie Pigman"}; +static std::string get_death_message(Player *player, Entity *cause, bool was_shot = false) { // Prepare Death Message - std::string message; - message.append(username->c_str()); - message.append(" has died"); + std::string message = player->username; + + // The cause + if (cause) { + // Entity cause + int type_id = cause->vtable->getEntityTypeId(cause); + int aux = cause->vtable->getAuxData(cause); + if (cause->vtable->isPlayer(cause)) { + // Another player + if (was_shot) { + message += " was shot by "; + } else { + message += " was killed by "; + } + message += ((Player *) cause)->username; + } else if (cause->vtable->getCreatureBaseType(cause) == 1) { + // Killed by a monster + if (was_shot) { + message += " was shot by a "; + } else { + message += " was killed by a "; + } + if (32 <= type_id && type_id <= 36) { + message += monster_names[type_id - 32]; + } else { + // Unknown monster + message += "Mysterious Beast"; + } + } else if (aux) { + // Throwable with owner + Level *level = player->level; + Entity *shooter = Level_getEntity(level, aux); + return get_death_message(player, shooter, true); + } else if (80 <= type_id || type_id <= 82) { + // Throwable without owner + message += " was shot under mysterious circumstances"; + } else if (type_id == 65) { + // TNT + message += " was blown apart"; + } else if (cause->vtable->isHangingEntity(cause)) { + // Painting? + message += " admired too much art"; + } else { + if (was_shot) { + message += " was shot under mysterious circumstances"; + } else { + message += " was killed under mysterious circumstances"; + } + } + } else { + // Non-entity cause + if (was_shot) { + // Throwable with invalid owner + message += " was shot under mysterious circumstances"; + } else { + // Anything else + message += " has died"; + } + } // Return return message; } +static bool is_hurt = false; +static bool Mob_hurt_injection(Mob *mob, Entity *source, int dmg) { + // Call Original Method + is_hurt = true; + bool ret = Mob_hurt_non_virtual(mob, source, dmg); + is_hurt = false; + return ret; +} + // Death Message Logic -#define Player_actuallyHurt_injection(type) \ +#define Player_death_injections(type) \ + static void type##Player_die_injection(type##Player *player, Entity *cause) { \ + /* Call Original Method */ \ + type##Player_die_non_virtual(player, cause); \ + \ + /* Get Variable */ \ + RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \ + /* Only Run On Server-Side */ \ + if (rak_net_instance->vtable->isServer(rak_net_instance)) { \ + /* Get Death Message */ \ + std::string message = get_death_message((Player *) player, cause); \ + \ + /* Post Death Message */ \ + ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \ + ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &message); \ + } \ + } \ + \ static void type##Player_actuallyHurt_injection(type##Player *player, int32_t damage) { \ /* Store Old Health */ \ int32_t old_health = player->health; \ \ /* Call Original Method */ \ type##Player_actuallyHurt_non_virtual(player, damage); \ + if (is_hurt == true) return; \ \ /* Store New Health */ \ int32_t new_health = player->health; \ \ /* Get Variables */ \ - Minecraft *minecraft = player->minecraft; \ - RakNetInstance *rak_net_instance = minecraft->rak_net_instance; \ + RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \ /* Only Run On Server-Side */ \ if (rak_net_instance->vtable->isServer(rak_net_instance)) { \ /* Check Health */ \ if (new_health < 1 && old_health >= 1) { \ /* Get Death Message */ \ - std::string message = get_death_message((Player *) player); \ + std::string message = get_death_message((Player *) player, NULL); \ \ /* Post Death Message */ \ - ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) minecraft->network_handler; \ + ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \ ServerSideNetworkHandler_displayGameMessage(server_side_network_handler, &message); \ } \ } \ } -Player_actuallyHurt_injection(Local) -Player_actuallyHurt_injection(Server) + +Player_death_injections(Local); +Player_death_injections(Server); // Init void init_death() { // Death Messages if (feature_has("Implement Death Messages", server_auto)) { + patch_address(ServerPlayer_die_vtable_addr, (void *) ServerPlayer_die_injection); + patch_address(LocalPlayer_die_vtable_addr, (void *) LocalPlayer_die_injection); patch_address(ServerPlayer_actuallyHurt_vtable_addr, (void *) ServerPlayer_actuallyHurt_injection); patch_address(LocalPlayer_actuallyHurt_vtable_addr, (void *) LocalPlayer_actuallyHurt_injection); + patch_address(Mob_hurt_vtable_addr, (void *) Mob_hurt_injection); + overwrite_calls((void *) Mob_hurt_non_virtual, (void *) Mob_hurt_injection); } } diff --git a/symbols/src/entity/Entity.def b/symbols/src/entity/Entity.def index 3c57c4b..44aae8d 100644 --- a/symbols/src/entity/Entity.def +++ b/symbols/src/entity/Entity.def @@ -1,8 +1,17 @@ virtual-method void remove() = 0x10; virtual-method void tick() = 0x34; virtual-method bool interact(Player *with) = 0x6c; +virtual-method bool isPlayer() = 0x94; virtual-method bool hurt(Entity *attacker, int damage) = 0xa4; +// See https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Entity_List for these two virtual-method int getEntityTypeId() = 0xdc; +virtual-method int getCreatureBaseType() = 0xe0; +virtual-method bool isMob() = 0xe8; +virtual-method bool isItemEntity() = 0xec; +// HangingEntity is a painting +virtual-method bool isHangingEntity() = 0xf0; +// The owner entity id for arrows/throwables, else 0 +virtual-method int getAuxData() = 0xf4; method void moveTo(float x, float y, float z, float yaw, float pitch) = 0x7a834; diff --git a/symbols/src/tile/entity/SignTileEntity.def b/symbols/src/tile/entity/SignTileEntity.def index f25f52d..c589e1d 100644 --- a/symbols/src/tile/entity/SignTileEntity.def +++ b/symbols/src/tile/entity/SignTileEntity.def @@ -1 +1,2 @@ extends TileEntity; +