Skip to content

Commit

Permalink
refactor: PlayerDeathEvent
Browse files Browse the repository at this point in the history
  • Loading branch information
wu-vincent committed Jan 25, 2025
1 parent c9a8d9b commit 67e5726
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 70 deletions.
1 change: 0 additions & 1 deletion src/bedrock/server/server_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
class ServerPlayer : public Player {
public:
~ServerPlayer() override = 0;
ENDSTONE_HOOK void die(const ActorDamageSource &source) override;
ENDSTONE_HOOK void disconnect();
ENDSTONE_HOOK void setLocalPlayerAsInitialized();
};
2 changes: 0 additions & 2 deletions src/bedrock/symbol_generator/symbols.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ version = "1.21.50"
"?_createNewPlayer@ServerNetworkHandler@@AEAAAEAVServerPlayer@@AEBVNetworkIdentifier@@AEBVSubClientConnectionRequest@@W4SubClientId@@@Z" = 14291952
"?_isServerTextEnabled@ServerNetworkHandler@@AEBA_NAEBW4ServerTextEvent@@@Z" = 14311280
# ServerPlayer
"?die@ServerPlayer@@UEAAXAEBVActorDamageSource@@@Z" = 20376160
"?disconnect@ServerPlayer@@QEAAXXZ" = 20376320
"?setLocalPlayerAsInitialized@ServerPlayer@@QEAAXXZ" = 20449488
# ServerScoreboard
Expand Down Expand Up @@ -182,7 +181,6 @@ version = "1.21.50"
"_ZN20ServerNetworkHandler16_createNewPlayerERK17NetworkIdentifierRK26SubClientConnectionRequest11SubClientId" = 91671520
"_ZNK20ServerNetworkHandler20_isServerTextEnabledERK15ServerTextEvent" = 91584688
# ServerPlayer
"_ZN12ServerPlayer3dieERK17ActorDamageSource" = 103631264
"_ZN12ServerPlayer10disconnectEv" = 103650656
"_ZN12ServerPlayer27setLocalPlayerAsInitializedEv" = 103657312
# ServerScoreboard
Expand Down
23 changes: 9 additions & 14 deletions src/bedrock/world/level/player_death_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "bedrock/core/utility/pub_sub/publisher.h"
#include "bedrock/core/utility/pub_sub/thread_model.h"
#include "bedrock/forward.h"

class IPlayerDeathManagerProxy : public Bedrock::EnableNonOwnerReferences {
public:
Expand All @@ -24,26 +25,20 @@ class IPlayerDeathManagerProxy : public Bedrock::EnableNonOwnerReferences {
[[nodiscard]] virtual bool shouldShowDeathMessages() const = 0;
};

class PlayerDeathManagerBase { // TODO(fixme): figure out the name
class IPlayerDeathManagerConnector {
public:
virtual ~PlayerDeathManagerBase() = default;
virtual ~IPlayerDeathManagerConnector() = default;
virtual Bedrock::PubSub::Connector<void(Player &)> &getOnPlayerDeathConnector() = 0;
};

class PlayerDeathManager
: public PlayerDeathManagerBase,
public Bedrock::PubSub::Publisher<void(Player &), Bedrock::PubSub::ThreadModel::MultiThreaded> {
class PlayerDeathManager : public IPlayerDeathManagerConnector {
public:
[[nodiscard]] gsl::not_null<IPlayerDeathManagerProxy *> getPlayerDeathManagerProxy() const
{
return proxy_.get();
}

void resetPacketSender() // Endstone
{
sender_.reset();
}
PlayerDeathManager(std::unique_ptr<IPlayerDeathManagerProxy>);

private:
friend class endstone::core::EndstoneServer;

Bedrock::PubSub::Publisher<void(Player &), Bedrock::PubSub::ThreadModel::MultiThreaded> on_player_death_publisher_;
std::unique_ptr<IPlayerDeathManagerProxy> proxy_; // +136
Bedrock::NonOwnerPointer<PacketSender> sender_; // +144
};
Expand Down
43 changes: 42 additions & 1 deletion src/endstone/core/event/handlers/player_gameplay_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "endstone/core/event/handlers/player_gameplay_handler.h"

#include "bedrock/entity/components/replay_state_component.h"
#include "bedrock/locale/i18n.h"
#include "bedrock/network/packet/death_info_packet.h"
#include "bedrock/network/packet/update_player_game_type_packet.h"
#include "bedrock/world/actor/actor.h"
#include "endstone/core/block/block.h"
Expand All @@ -23,6 +25,7 @@
#include "endstone/core/json.h"
#include "endstone/core/player.h"
#include "endstone/core/server.h"
#include "endstone/event/player/player_death_event.h"
#include "endstone/event/player/player_emote_event.h"
#include "endstone/event/player/player_game_mode_change_event.h"
#include "endstone/event/player/player_interact_actor_event.h"
Expand All @@ -40,7 +43,8 @@ HandlerResult EndstonePlayerGameplayHandler::handleEvent(const PlayerGameplayEve
{
auto visitor = [&](auto &&arg) -> HandlerResult {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Details::ValueOrRef<const PlayerFormResponseEvent>> ||
if constexpr (std::is_same_v<T, Details::ValueOrRef<const PlayerDamageEvent>> ||
std::is_same_v<T, Details::ValueOrRef<const PlayerFormResponseEvent>> ||
std::is_same_v<T, Details::ValueOrRef<const PlayerFormCloseEvent>>) {
if (!handleEvent(arg.value())) {
return HandlerResult::BypassListeners;
Expand Down Expand Up @@ -84,6 +88,43 @@ GameplayHandlerResult<CoordinatorResult> EndstonePlayerGameplayHandler::handleEv
return std::visit(visitor, event.variant);
}

bool EndstonePlayerGameplayHandler::handleEvent(const PlayerDamageEvent &event)
{
if (auto *player = WeakEntityRef(event.player).tryUnwrap<::Player>(); player) {
auto &server = entt::locator<EndstoneServer>::value();
auto &endstone_player = player->getEndstoneActor<EndstonePlayer>();
if (player->isAlive()) {
// TODO: PlayerHurtEvent
}
else {
// Close any open form on player death
endstone_player.closeForm();

// Fire player death event
auto death_cause_message = event.damage_source->getDeathMessage(player->getName(), player);
auto death_message = getI18n().get(death_cause_message.first, death_cause_message.second, nullptr);
const auto e = std::make_unique<PlayerDeathEvent>(endstone_player, death_message);
server.getPluginManager().callEvent(*static_cast<PlayerEvent *>(e.get()));
if (e->getDeathMessage() != death_message) {
death_cause_message.first = e->getDeathMessage();
death_cause_message.second.clear();
}

// Send death info
const auto packet = MinecraftPackets::createPacket(MinecraftPacketIds::DeathInfo);
const auto pk = std::static_pointer_cast<DeathInfoPacket>(packet);
pk->death_cause_message = death_cause_message;
player->sendNetworkPacket(*packet);

// Broadcast death message if not empty
if (!e->getDeathMessage().empty()) {
server.broadcastMessage(Translatable{death_cause_message.first, death_cause_message.second});
}
}
}
return true;
}

bool EndstonePlayerGameplayHandler::handleEvent(const PlayerFormResponseEvent &event)
{
if (auto *player = WeakEntityRef(event.player).tryUnwrap<::Player>(); player) {
Expand Down
1 change: 1 addition & 0 deletions src/endstone/core/event/handlers/player_gameplay_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class EndstonePlayerGameplayHandler final : public PlayerGameplayHandler {
GameplayHandlerResult<CoordinatorResult> handleEvent(MutablePlayerGameplayEvent<CoordinatorResult> &event) override;

private:
bool handleEvent(const PlayerDamageEvent &event);
bool handleEvent(const PlayerFormResponseEvent &event);
bool handleEvent(const PlayerFormCloseEvent &event);
bool handleEvent(const PlayerRespawnEvent &event);
Expand Down
5 changes: 3 additions & 2 deletions src/endstone/core/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ void EndstoneServer::setLevel(::Level &level)
level_ = std::make_unique<EndstoneLevel>(level);
scoreboard_ = std::make_unique<EndstoneScoreboard>(level.getScoreboard());
command_map_ = std::make_unique<EndstoneCommandMap>(*this);
loadResourcePacks();
registerGameplayHandlers();
level._getPlayerDeathManager()->sender_.reset(); // prevent BDS from sending the death message
enablePlugins(PluginLoadOrder::PostWorld);
ServerLoadEvent event{ServerLoadEvent::LoadType::Startup};
getPluginManager().callEvent(event);
loadResourcePacks();
registerGameplayHandlers();
}

void EndstoneServer::setResourcePackRepository(Bedrock::NotNullNonOwnerPtr<IResourcePackRepository> repo)
Expand Down
50 changes: 0 additions & 50 deletions src/endstone/runtime/bedrock_hooks/server_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@
#include <utility>

#include "bedrock/locale/i18n.h"
#include "bedrock/network/packet.h"
#include "bedrock/network/packet/death_info_packet.h"
#include "bedrock/world/level/level.h"
#include "endstone/color_format.h"
#include "endstone/core/message.h"
#include "endstone/core/server.h"
#include "endstone/event/player/player_death_event.h"
#include "endstone/event/player/player_join_event.h"
#include "endstone/event/player/player_quit_event.h"
#include "endstone/lang/translatable.h"
Expand All @@ -32,52 +28,6 @@
using endstone::core::EndstonePlayer;
using endstone::core::EndstoneServer;

void ServerPlayer::die(const ActorDamageSource &source)
{
// Note: reset the packet sender in PlayerDeathManager to prevent BDS
// from sending the death message as we will take over it
auto *player_death_manager = getLevel()._getPlayerDeathManager();
player_death_manager->resetPacketSender();

ENDSTONE_HOOK_CALL_ORIGINAL(&ServerPlayer::die, this, source);

auto &server = entt::locator<EndstoneServer>::value();
auto &endstone_player = getEndstoneActor<EndstonePlayer>();
endstone_player.closeForm();

// Do a server side translation for logging
auto death_cause_message = source.getDeathMessage(getName(), this);
auto death_message = getI18n().get(death_cause_message.first, death_cause_message.second, nullptr);

// Fire player death event
const auto e = std::make_unique<endstone::PlayerDeathEvent>(endstone_player, death_message);
server.getPluginManager().callEvent(*static_cast<endstone::PlayerEvent *>(e.get()));
if (e->getDeathMessage() != death_message) {
death_cause_message.first = e->getDeathMessage();
death_cause_message.second.clear();
}

// Send death info
const auto packet = MinecraftPackets::createPacket(MinecraftPacketIds::DeathInfo);
const auto pk = std::static_pointer_cast<DeathInfoPacket>(packet);
pk->death_cause_message = death_cause_message;
sendNetworkPacket(*packet);

// Log death message to console if not empty
if (e->getDeathMessage().empty()) {
return;
}
server.getLogger().info(e->getDeathMessage());

// Broadcast death messages
if (player_death_manager->getPlayerDeathManagerProxy()->shouldShowDeathMessages()) {
endstone::Translatable tr{death_cause_message.first, death_cause_message.second};
for (const auto &player : server.getOnlinePlayers()) {
player->sendMessage(tr);
}
}
}

void ServerPlayer::setLocalPlayerAsInitialized()
{
ENDSTONE_HOOK_CALL_ORIGINAL(&ServerPlayer::setLocalPlayerAsInitialized, this);
Expand Down

0 comments on commit 67e5726

Please sign in to comment.