minecraft-pi-reborn/mods/src/death/death.cpp

147 lines
5.5 KiB
C++
Raw Permalink Normal View History

#include <string>
#include <libreborn/libreborn.h>
2021-09-12 03:18:12 +00:00
#include <symbols/minecraft.h>
2022-06-25 21:30:08 +00:00
#include <mods/init/init.h>
#include <mods/feature/feature.h>
// Death Messages
static const char *monster_names[] = {"Zombie", "Creeper", "Skeleton", "Spider", "Zombie Pigman"};
std::string get_death_message(Player *player, Entity *cause, bool was_shot = false) {
// Prepare Death Message
std::string message = player->username;
if (cause) {
// Entity cause
2024-05-15 09:02:19 +00:00
int type_id = cause->getEntityTypeId();
int aux = cause->getAuxData();
bool is_player = cause->isPlayer();
if (cause->getCreatureBaseType() != 0 || is_player) {
// Killed by a creature
if (was_shot) {
message += " was shot by ";
} else {
message += " was killed by ";
}
if (is_player) {
// Killed by a player
message += ((Player *) cause)->username;
} else if (32 <= type_id && type_id <= 36) {
// Normal monster
message += "a ";
message += monster_names[type_id - 32];
} else {
// Unknown creature
message += "a Mysterious Beast";
}
return message;
} else if (aux) {
// Killed by a throwable with owner
Level *level = player->level;
2024-05-15 09:02:19 +00:00
Entity *shooter = level->getEntity(aux);
return get_death_message(player, shooter, true);
} else if (type_id == 65) {
// Blown up by TNT
return message + " was blown apart";
2024-05-15 09:02:19 +00:00
} else if (cause->isHangingEntity()) {
// Painting?
return message + " admired too much art";
}
}
if (was_shot) {
// Throwable with invalid owner
return message + " was shot under mysterious circumstances";
} else if (cause) {
// Unknown entity
return message + " was killed";
} else {
// Anything else
return message + " has died";
}
// Return
return message;
}
static bool is_hurt = false;
2024-04-03 07:19:12 +00:00
static bool Mob_hurt_injection(Mob_hurt_t original, Mob *mob, Entity *source, int dmg) {
is_hurt = true;
2024-04-03 07:19:12 +00:00
bool ret = original(mob, source, dmg);
is_hurt = false;
return ret;
}
2024-01-06 11:30:23 +00:00
// Death Message Logic
2024-05-05 00:46:15 +00:00
#define Player_die_injections(type, original_method_self) \
static void type##_die_injection(original_method_self##_die_t original, type *player, Entity *cause) { \
/* Call Original Method */ \
2024-05-05 00:46:15 +00:00
original((original_method_self *) player, cause); \
\
/* Get Variable */ \
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
/* Only Run On Server-Side */ \
2024-05-15 09:02:19 +00:00
if (rak_net_instance->isServer()) { \
/* 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; \
2024-05-15 09:02:19 +00:00
server_side_network_handler->displayGameMessage(&message); \
} \
2024-04-03 07:19:12 +00:00
}
#define Player_actuallyHurt_injections(type) \
static void type##_actuallyHurt_injection(type *player, int32_t damage) { \
2024-01-06 11:30:23 +00:00
/* Store Old Health */ \
int32_t old_health = player->health; \
\
/* Call Original Method */ \
2024-04-03 07:19:12 +00:00
(*Mob_actuallyHurt_vtable_addr)((Mob *) player, damage); \
if (is_hurt == true) return; \
2024-01-06 11:30:23 +00:00
\
/* Store New Health */ \
int32_t new_health = player->health; \
\
/* Get Variables */ \
RakNetInstance *rak_net_instance = player->minecraft->rak_net_instance; \
2024-01-06 11:30:23 +00:00
/* Only Run On Server-Side */ \
2024-05-15 09:02:19 +00:00
if (rak_net_instance->isServer()) { \
2024-01-06 11:30:23 +00:00
/* Check Health */ \
if (new_health < 1 && old_health >= 1) { \
/* Get Death Message */ \
2024-04-02 23:22:01 +00:00
std::string message = get_death_message((Player *) player, nullptr); \
2024-01-06 11:30:23 +00:00
\
/* Post Death Message */ \
ServerSideNetworkHandler *server_side_network_handler = (ServerSideNetworkHandler *) player->minecraft->network_handler; \
2024-05-15 09:02:19 +00:00
server_side_network_handler->displayGameMessage(&message); \
2024-01-06 11:30:23 +00:00
} \
} \
}
2024-05-05 00:46:15 +00:00
Player_die_injections(LocalPlayer, LocalPlayer)
Player_die_injections(ServerPlayer, Player)
2024-04-03 07:19:12 +00:00
Player_actuallyHurt_injections(LocalPlayer)
Player_actuallyHurt_injections(ServerPlayer)
// Init
void init_death() {
// Death Messages
if (feature_has("Implement Death Messages", server_auto)) {
2024-05-05 00:46:15 +00:00
patch_vtable(ServerPlayer_die, [](ServerPlayer *player, Entity *cause) {
ServerPlayer_die_injection(*Player_die_vtable_addr, player, cause);
});
overwrite_virtual_calls(LocalPlayer_die, LocalPlayer_die_injection);
patch_vtable(LocalPlayer_actuallyHurt, LocalPlayer_actuallyHurt_injection);
patch_vtable(ServerPlayer_actuallyHurt, ServerPlayer_actuallyHurt_injection);
2024-04-03 07:19:12 +00:00
overwrite_virtual_calls(Mob_hurt, Mob_hurt_injection);
2021-07-04 23:02:45 +00:00
}
2024-02-12 05:44:38 +00:00
// Fix TNT
2024-04-02 23:22:01 +00:00
// This changes PrimedTnt_explode from Level::explode(nullptr, x, y, z, 3.1f) to Level::explode(this, x, y, z, 3.1f)
2024-02-12 05:44:38 +00:00
unsigned char cpy_r1_r0_patch[4] = {0x00, 0x10, 0xa0, 0xe1}; // "cpy r1, r0"
patch((void *) 0x87998, cpy_r1_r0_patch);
2024-02-12 05:44:38 +00:00
unsigned char ldr_r0_24_patch[4] = {0x24, 0x00, 0x90, 0xe5}; // "ldr r0, [r0, #0x24]"
patch((void *) 0x8799c, ldr_r0_24_patch);
}