Add Cake #81

Merged
TheBrokenRail merged 22 commits from bigjango13/minecraft-pi-reborn:master into master 2024-02-07 06:47:47 +00:00
3 changed files with 109 additions and 15 deletions
Showing only changes of commit 6060fdd4e1 - Show all commits

@ -1 +1 @@
Subproject commit 8e6c8d7effc54f8aecd30eda17069588298f4ada
Subproject commit b4c3ef9d0fdf46845f3e81e5d989dab06e71e6c1
bigjango13 marked this conversation as resolved Outdated

Why did you downgrade GLFW?

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?

I have no idea, I just git pulled, and when I git added it was there. How would I undo it?

Figured it out

Figured it out

View File

@ -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
Review

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?
Review

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.

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

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?

Done 👍

Done 👍
} else if (type_id == 65) {
// TNT
message += " was blown apart";
} else if (cause->vtable->isHangingEntity(cause)) {
// Painting?
message += " admired too much art";

When would this ever happen?

When would this ever happen?

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
Review

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)
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)
Review

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 " has died". As for your question, yes, all of those have been tested.

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

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);
}
}

View File

@ -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;