Skip to content

Commit

Permalink
refactor: improve handling of custom death message
Browse files Browse the repository at this point in the history
  • Loading branch information
wu-vincent committed Sep 7, 2024
1 parent 4af561f commit 701b522
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 164 deletions.
25 changes: 25 additions & 0 deletions include/bedrock/network/packet/death_info_packet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <string>

#include "bedrock/network/packet.h"

class DeathInfoPacket : public Packet {
public:
using DeathCauseMessageType = std::pair<std::string, std::vector<std::string>>;
DeathCauseMessageType death_cause_message;
};
145 changes: 0 additions & 145 deletions include/bedrock/world/damagesource/actor_damage_source_wrapper.h

This file was deleted.

3 changes: 2 additions & 1 deletion include/bedrock/world/level/level_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,9 @@ class ILevel : public Bedrock::EnableNonOwnerReferences {
[[nodiscard]] virtual std::weak_ptr<BlockTypeRegistry> getBlockRegistry() const = 0;
virtual void pauseAndFlushTaskGroups() = 0;

virtual PlayerDeathManager *_getPlayerDeathManager() = 0; // Endstone: private -> public

private:
virtual PlayerDeathManager *_getPlayerDeathManager() = 0;
virtual MapDataManager &_getMapDataManager() = 0;
virtual void *getArmorTrimUnloader() = 0;
[[nodiscard]] virtual void *getPlayerSleepManager() const = 0;
Expand Down
27 changes: 22 additions & 5 deletions include/bedrock/world/level/player_death_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,34 @@

#include "bedrock/core/pub_sub.h"

class IPlayerDeathManagerProxy;
class IPlayerDeathManagerProxy : public Bedrock::EnableNonOwnerReferences {
public:
~IPlayerDeathManagerProxy() override = 0;
[[nodiscard]] virtual Actor *fetchActor(ActorUniqueID) const = 0;
[[nodiscard]] virtual bool shouldShowDeathMessages() const = 0;
};

class PlayerDeathManagerBase { // TODO(fixme): figure out the name
public:
virtual ~PlayerDeathManagerBase() = default;
};

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

void resetPacketSender() // Endstone
{
sender_.reset();
}

private:
std::unique_ptr<IPlayerDeathManagerProxy> proxy_; // +128
Bedrock::NonOwnerPointer<PacketSender> sender_; // +136
std::unique_ptr<IPlayerDeathManagerProxy> proxy_; // +136
Bedrock::NonOwnerPointer<PacketSender> sender_; // +144
};
BEDROCK_STATIC_ASSERT_SIZE(PlayerDeathManager, 152, 112);
BEDROCK_STATIC_ASSERT_SIZE(PlayerDeathManager, 160, 120);
47 changes: 34 additions & 13 deletions src/endstone_runtime/bedrock/server/server_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

#include <utility>

#include <bedrock/world/level/level.h>

#include "bedrock/locale/i18n.h"
#include "bedrock/world/damagesource/actor_damage_source_wrapper.h"
#include "bedrock/network/minecraft_packets.h"
#include "bedrock/network/packet/death_info_packet.h"
#include "bedrock/world/level/level.h"
#include "endstone/detail/hook.h"
#include "endstone/detail/server.h"
#include "endstone/event/player/player_death_event.h"
Expand All @@ -30,27 +30,48 @@ using endstone::detail::EndstoneServer;

void ServerPlayer::die(const ActorDamageSource &source)
{
auto death_cause_message = source.getDeathMessage(getName(), this);
auto death_message = getI18n().get(death_cause_message.first, death_cause_message.second, nullptr);
// 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_NAME(&ServerPlayer::die, __FUNCDNAME__, this, source);

auto &server = entt::locator<EndstoneServer>::value();
endstone::Player &endstone_player = getEndstonePlayer();
endstone_player.closeForm();

auto e = std::make_unique<endstone::PlayerDeathEvent>(endstone_player, death_message);
server.getPluginManager().callEvent(*static_cast<endstone::PlayerEvent *>(e.get()));
// 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);

if (!e->getDeathMessage().empty()) {
server.getLogger().info(e->getDeathMessage());
// 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();
}

if (e->getDeathMessage() != death_message) {
auto new_source = endstone::detail::ActorDamageSourceWrapper(source, e->getDeathMessage(), {});
ENDSTONE_HOOK_CALL_ORIGINAL_NAME(&ServerPlayer::die, __FUNCDNAME__, this, new_source);
// 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());

ENDSTONE_HOOK_CALL_ORIGINAL_NAME(&ServerPlayer::die, __FUNCDNAME__, this, source);
// Broadcast death messages
if (!player_death_manager->getPlayerDeathManagerProxy()->shouldShowDeathMessages()) {
return;
}
for (const auto &player : server.getOnlinePlayers()) {
player->sendMessage({death_cause_message.first, death_cause_message.second});
}
}

void ServerPlayer::setLocalPlayerAsInitialized()
Expand Down

0 comments on commit 701b522

Please sign in to comment.