Add Cake #81
|
@ -1 +1 @@
|
|||
Subproject commit 8e6c8d7effc54f8aecd30eda17069588298f4ada
|
||||
Subproject commit b4c3ef9d0fdf46845f3e81e5d989dab06e71e6c1
|
||||
bigjango13 marked this conversation as resolved
Outdated
|
|
@ -7,55 +7,140 @@
|
|||
#include <mods/feature/feature.h>
|
||||
|
||||
// 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;
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
Shouldn't this check if this was an arrow? What if another entity has aux data? Shouldn't this check if this was an arrow? What if another entity has aux data?
bigjango13
commented
That's intended, only throwables have aux values:
So if I egg you to death, it still says that I'm the one who did it. That's intended, only throwables have aux values:
```
// The owner entity id for arrows/throwables, else 0
virtual-method int getAuxData() = 0xf4;
```
So if I egg you to death, it still says that I'm the one who did it.
|
||||
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";
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
A lot of these death messages are duplicated. Is there any chance these could be consolidated into fewer if statements? A lot of these death messages are duplicated. Is there any chance these could be consolidated into fewer if statements?
bigjango13
commented
Done 👍 Done 👍
|
||||
} else if (type_id == 65) {
|
||||
// TNT
|
||||
message += " was blown apart";
|
||||
} else if (cause->vtable->isHangingEntity(cause)) {
|
||||
// Painting?
|
||||
message += " admired too much art";
|
||||
TheBrokenRail
commented
When would this ever happen? When would this ever happen?
bigjango13
commented
No idea, I thought it might be useful in case the paintings ever try to take over. No idea, I thought it might be useful in case the paintings ever try to take over.
|
||||
} 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) { \
|
||||
bigjango13 marked this conversation as resolved
TheBrokenRail
commented
IIRC when originally implementing death message, that hooking Did you test:
IIRC when originally implementing death message, that hooking `Player::die` caused some issues on servers.
Did you test:
- Host player dying (in LAN)
- Guest player dying (in LAN)
- Server killing player (`kill` console command)
bigjango13
commented
That's why I also hooked That's why I also hooked `actuallyHurt` as it did before. There are quite a few ways to die without calling `Player::die`, falling into the void is a notable one. If the player dies without calling `Player::die`, it will just post the usual "<username> has died". As for your question, yes, all of those have been tested.
|
||||
/* 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
|
||||
bigjango13 marked this conversation as resolved
Outdated
TheBrokenRail
commented
So, uh, what does these patches actually do? Does it set an entity ID somewhere? Because that should probably be in the comment. So, uh, what does these patches actually do? Does it set an entity ID somewhere? Because that should probably be in the comment.
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Why did you downgrade GLFW?
I have no idea, I just git pulled, and when I git added it was there. How would I undo it?
Figured it out