mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-22 20:52:49 +00:00
chore: foundations for struct based packets and game messages
First step of moving hand written bitstream code to struct based messages (see docs/PacketArchitecture.md). No wire changes. - GameMsg is now only a server-internal event (delivered to handlers registered with RegisterMsg); NetGameMsg is a wire message with Send(sysAddr) (UNASSIGNED broadcasts), SendToClient(sysAddr) (one client, never broadcasts), WritePacket, Serialize, Deserialize and Handle. Mixing them up is now a compile error. NetGameMsgEvent<T> / DeliverLocally carry a wire message to local handlers; loot drops, pickup, the object debugger, GM invisibility and model RequestUse use them. The GM invisibility message keeps its target, so its bytes are unchanged. - Behaviour change: GameMessageHandler logs and drops messages whose Deserialize fails instead of handling them with default fields (the 4 messages already registered: RequestUse, RequestServerObjectInfo, ShootingGalleryFire, PickupItem). - LUBitStream (kept as on main) gets a virtual destructor (Mail deleted derived packets through the base) and WritePacket, also used by ChatPackets::SendRoutedMsg with identical bytes. - BitStreamUtils::WriteOptional/ReadOptional for default-flag fields and WriteLengthPrefixed/ReadLengthPrefixed for length prefixed strings. - Every message ID enumerator (MessageType::*, ServiceType, Mail's wire enums) is pinned with static_asserts, so renumbering or removing one fails to compile. - Tests: dServerMock copies each sent packet (it kept a pointer to the caller's destroyed BitStream); PacketTestUtils.h compares packets bit for bit; helper tests use hand computed golden bytes and equality with the hand written patterns they replace; compile-time checks keep the wire/internal split in place. - docs/PacketArchitecture.md: survey, target architecture, conventions, verification method and migration plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2222,7 +2222,8 @@ void Entity::RegisterMsg(const MessageType::Game msgId, std::function<bool(GameM
|
||||
m_MsgHandlers.emplace(msgId, handler);
|
||||
}
|
||||
|
||||
bool Entity::MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfo& requestInfo) {
|
||||
bool Entity::MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfoEvent& event) {
|
||||
const auto& requestInfo = event.msg;
|
||||
AMFArrayValue response;
|
||||
response.Insert("visible", true);
|
||||
response.Insert("objectID", std::to_string(m_ObjectID));
|
||||
@@ -2264,7 +2265,8 @@ bool Entity::MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfo& r
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Entity::MsgDropClientLoot(GameMessages::DropClientLoot& dropLootMsg) {
|
||||
bool Entity::MsgDropClientLoot(GameMessages::DropClientLootEvent& event) {
|
||||
const auto& dropLootMsg = event.msg;
|
||||
if (dropLootMsg.item != LOT_NULL && dropLootMsg.item != 0) {
|
||||
Loot::Info info{
|
||||
.id = dropLootMsg.lootID,
|
||||
@@ -2308,7 +2310,8 @@ bool Entity::MsgGetFactionTokenType(GameMessages::GetFactionTokenType& tokenMsg)
|
||||
return tokenMsg.tokenType != LOT_NULL;
|
||||
}
|
||||
|
||||
bool Entity::MsgPickupItem(GameMessages::PickupItem& pickupItemMsg) {
|
||||
bool Entity::MsgPickupItem(GameMessages::PickupItemEvent& event) {
|
||||
const auto& pickupItemMsg = event.msg;
|
||||
if (GetObjectID() == pickupItemMsg.lootOwnerID) {
|
||||
PickupItem(pickupItemMsg.lootID);
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
namespace GameMessages {
|
||||
struct GameMsg;
|
||||
template<typename Msg> struct NetGameMsgEvent;
|
||||
struct ActivityNotify;
|
||||
struct ShootingGalleryFire;
|
||||
struct ChildLoaded;
|
||||
@@ -182,11 +183,11 @@ public:
|
||||
|
||||
void AddComponent(eReplicaComponentType componentId, Component* component);
|
||||
|
||||
bool MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfo& msg);
|
||||
bool MsgDropClientLoot(GameMessages::DropClientLoot& msg);
|
||||
bool MsgRequestServerObjectInfo(GameMessages::NetGameMsgEvent<GameMessages::RequestServerObjectInfo>& event);
|
||||
bool MsgDropClientLoot(GameMessages::NetGameMsgEvent<GameMessages::DropClientLoot>& event);
|
||||
bool MsgGetFlag(GameMessages::GetFlag& msg);
|
||||
bool MsgGetFactionTokenType(GameMessages::GetFactionTokenType& msg);
|
||||
bool MsgPickupItem(GameMessages::PickupItem& msg);
|
||||
bool MsgPickupItem(GameMessages::NetGameMsgEvent<GameMessages::PickupItem>& event);
|
||||
bool MsgChildRemoved(GameMessages::ChildRemoved& msg);
|
||||
|
||||
// This is expceted to never return nullptr, an assert checks this.
|
||||
|
||||
@@ -783,7 +783,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
||||
lootMsg.spawnPos = m_Parent->GetPosition();
|
||||
lootMsg.sourceID = source;
|
||||
lootMsg.item = LOT_NULL;
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
character->SetCoins(coinsTotal, eLootSourceType::DELETION);
|
||||
}
|
||||
}
|
||||
@@ -1022,17 +1022,17 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) {
|
||||
lootMsg.spawnPos = m_Parent->GetPosition();
|
||||
lootMsg.sourceID = source;
|
||||
lootMsg.item = LOT_NULL;
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
lootMsg.Send(m_Parent->GetSystemAddress());
|
||||
while (coinsToDrop > MAX_TO_DROP_PER_GM) {
|
||||
LOG("Dropping 100,000, %llu left", coinsToDrop);
|
||||
lootMsg.currency = 100'000;
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
lootMsg.Send(m_Parent->GetSystemAddress());
|
||||
coinsToDrop -= 100'000;
|
||||
}
|
||||
lootMsg.currency = coinsToDrop;
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
lootMsg.Send(m_Parent->GetSystemAddress());
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -68,7 +68,9 @@ void GhostComponent::GhostEntity(LWOOBJID id) {
|
||||
m_ObservedEntities.erase(id);
|
||||
}
|
||||
|
||||
bool GhostComponent::OnToggleGMInvis(GameMessages::ToggleGMInvis& gmInvisMsg) {
|
||||
bool GhostComponent::OnToggleGMInvis(GameMessages::ToggleGMInvisEvent& event) {
|
||||
auto& gmInvisMsg = event.msg;
|
||||
gmInvisMsg.target = event.target; // the wire message goes out with the target the event was delivered to
|
||||
gmInvisMsg.bStateOut = !m_IsGMInvisible;
|
||||
m_IsGMInvisible = !m_IsGMInvisible;
|
||||
LOG_DEBUG("GM Invisibility toggled to: %s", m_IsGMInvisible ? "true" : "false");
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
|
||||
void GhostEntity(const LWOOBJID id);
|
||||
|
||||
bool OnToggleGMInvis(GameMessages::ToggleGMInvis& msg);
|
||||
bool OnToggleGMInvis(GameMessages::ToggleGMInvisEvent& event);
|
||||
|
||||
bool OnGetGMInvis(GameMessages::GetGMInvis& msg);
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ bool ModelComponent::OnResetModelToDefaults(GameMessages::ResetModelToDefaults&
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModelComponent::OnRequestUse(GameMessages::RequestUse& requestUse) {
|
||||
bool ModelComponent::OnRequestUse(GameMessages::RequestUseEvent& event) {
|
||||
auto& requestUse = event.msg;
|
||||
bool toReturn = false;
|
||||
if (!m_IsPaused) {
|
||||
for (auto& behavior : m_Behaviors) behavior.HandleMsg(requestUse);
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
void LoadBehaviors();
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
bool OnRequestUse(GameMessages::RequestUse& requestUse);
|
||||
bool OnRequestUse(GameMessages::RequestUseEvent& event);
|
||||
bool OnResetModelToDefaults(GameMessages::ResetModelToDefaults& resetModelToDefaults);
|
||||
bool OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& reportInfo);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
namespace {
|
||||
using enum MessageType::Game;
|
||||
using namespace GameMessages;
|
||||
using MessageCreator = std::function<std::unique_ptr<GameMessages::GameMsg>()>;
|
||||
using MessageCreator = std::function<std::unique_ptr<GameMessages::NetGameMsg>()>;
|
||||
std::map<MessageType::Game, MessageCreator> g_MessageHandlers = {
|
||||
{ REQUEST_USE, []() { return std::make_unique<RequestUse>(); }},
|
||||
{ REQUEST_SERVER_OBJECT_INFO, []() { return std::make_unique<RequestServerObjectInfo>(); } },
|
||||
@@ -87,7 +87,10 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
}
|
||||
}
|
||||
|
||||
msg->Deserialize(inStream);
|
||||
if (!msg->Deserialize(inStream)) {
|
||||
LOG("Dropping malformed GM %4i, %s from (%llu) targeting (%llu)", messageID, StringifiedEnum::ToString(messageID).data(), usr->GetLoggedInChar(), objectID);
|
||||
return;
|
||||
}
|
||||
msg->Handle(*entity, sysAddr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6285,14 +6285,24 @@ namespace GameMessages {
|
||||
return Send();
|
||||
}
|
||||
|
||||
void GameMsg::Send(const SystemAddress& sysAddr) const {
|
||||
CBITSTREAM;
|
||||
void NetGameMsg::WritePacket(RakNet::BitStream& bitStream) const {
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(target); // Who this message will be sent to on the (a) client
|
||||
bitStream.Write(msgId); // the ID of this message
|
||||
|
||||
Serialize(bitStream); // write the message data
|
||||
}
|
||||
|
||||
void NetGameMsg::SendToClient(const SystemAddress& sysAddr) const {
|
||||
CBITSTREAM;
|
||||
WritePacket(bitStream);
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void NetGameMsg::Send(const SystemAddress& sysAddr) const {
|
||||
CBITSTREAM;
|
||||
WritePacket(bitStream);
|
||||
|
||||
// Send to everyone if someone sent unassigned system address, or to one specific client.
|
||||
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) {
|
||||
@@ -6378,8 +6388,10 @@ namespace GameMessages {
|
||||
|
||||
void RequestServerObjectInfo::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
||||
auto* handlingEntity = Game::entityManager->GetEntity(targetForReport);
|
||||
if (handlingEntity) handlingEntity->HandleMsg(*this);
|
||||
else LOG("Failed to find target %llu", targetForReport);
|
||||
if (handlingEntity) {
|
||||
RequestServerObjectInfoEvent event(*this);
|
||||
handlingEntity->HandleMsg(event);
|
||||
} else LOG("Failed to find target %llu", targetForReport);
|
||||
}
|
||||
|
||||
bool RequestUse::Deserialize(RakNet::BitStream& stream) {
|
||||
@@ -6418,7 +6430,8 @@ namespace GameMessages {
|
||||
interactedObject->OnUse(&entity);
|
||||
}
|
||||
|
||||
interactedObject->HandleMsg(*this);
|
||||
RequestUseEvent event(*this);
|
||||
interactedObject->HandleMsg(event);
|
||||
|
||||
//Perform use task if possible:
|
||||
auto missionComponent = entity.GetComponent<MissionComponent>();
|
||||
@@ -6480,7 +6493,8 @@ namespace GameMessages {
|
||||
LOG("Has team %i picking up %llu:%llu", team != nullptr, lootID, lootOwnerID);
|
||||
if (team) {
|
||||
for (const auto memberId : team->members) {
|
||||
this->Send(memberId);
|
||||
PickupItemEvent event(*this);
|
||||
event.Send(memberId);
|
||||
TeamPickupItem teamPickupMsg{};
|
||||
teamPickupMsg.target = lootID;
|
||||
teamPickupMsg.lootID = lootID;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "dCommonVars.h"
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "eMovementPlatformState.h"
|
||||
@@ -53,26 +54,78 @@ enum class eCameraTargetCyclingMode : int32_t {
|
||||
};
|
||||
|
||||
namespace GameMessages {
|
||||
/**
|
||||
* A server-internal event, delivered only to the handlers entities/components/scripts registered with
|
||||
* RegisterMsg. It never goes on the wire: it has no Serialize and no way to send it to a client.
|
||||
*/
|
||||
struct GameMsg {
|
||||
GameMsg(MessageType::Game gmId, eGameMasterLevel lvl) : msgId{ gmId }, requiredGmLevel{ lvl } {}
|
||||
GameMsg(MessageType::Game gmId) : GameMsg(gmId, eGameMasterLevel::CIVILIAN) {}
|
||||
GameMsg(MessageType::Game gmId) : msgId{ gmId } {}
|
||||
virtual ~GameMsg() = default;
|
||||
|
||||
// Sends a message to the entity manager to route to the target
|
||||
// Delivers the message to the handlers registered on the target entity.
|
||||
bool Send();
|
||||
bool Send(const LWOOBJID _target);
|
||||
|
||||
MessageType::Game msgId;
|
||||
LWOOBJID target{ LWOOBJID_EMPTY };
|
||||
};
|
||||
|
||||
/**
|
||||
* A game message that goes on the wire, to (Serialize) or from (Deserialize + Handle) a client.
|
||||
* It is not a GameMsg, so it cannot be delivered to local handlers by mistake. When local handlers need to
|
||||
* observe a network message, wrap it in a NetGameMsgEvent.
|
||||
*/
|
||||
struct NetGameMsg {
|
||||
NetGameMsg(MessageType::Game gmId, eGameMasterLevel lvl) : msgId{ gmId }, requiredGmLevel{ lvl } {}
|
||||
NetGameMsg(MessageType::Game gmId) : NetGameMsg(gmId, eGameMasterLevel::CIVILIAN) {}
|
||||
virtual ~NetGameMsg() = default;
|
||||
|
||||
// Sends the message to the specified client or
|
||||
// all clients if UNASSIGNED_SYSTEM_ADDRESS is specified
|
||||
void Send(const SystemAddress& sysAddr) const;
|
||||
|
||||
// Sends the message to the specified client only and never broadcasts. Given UNASSIGNED_SYSTEM_ADDRESS
|
||||
// nothing is delivered (RakNet rejects a non-broadcast send without an address).
|
||||
void SendToClient(const SystemAddress& sysAddr) const;
|
||||
|
||||
// Writes the complete client packet (CLIENT/GAME_MSG header, target, msgId, then Serialize()) into bitStream.
|
||||
// This is exactly what Send(sysAddr) puts on the wire; tests use it to compare bytes without a server.
|
||||
void WritePacket(RakNet::BitStream& bitStream) const;
|
||||
|
||||
virtual void Serialize(RakNet::BitStream& bitStream) const {}
|
||||
virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; }
|
||||
|
||||
// Called for messages received from a client, after a successful Deserialize.
|
||||
virtual void Handle(Entity& entity, const SystemAddress& sysAddr) {};
|
||||
|
||||
MessageType::Game msgId;
|
||||
LWOOBJID target{ LWOOBJID_EMPTY };
|
||||
|
||||
// Minimum GM level the sending client needs for Handle to be called.
|
||||
eGameMasterLevel requiredGmLevel;
|
||||
};
|
||||
|
||||
/**
|
||||
* A server-internal event carrying a network message, so entity/component handlers can react to a message
|
||||
* received from (or about to be sent to) a client. Uses the network message's msgId for local dispatch.
|
||||
*/
|
||||
template<typename Msg>
|
||||
struct NetGameMsgEvent : public GameMsg {
|
||||
static_assert(std::is_base_of_v<NetGameMsg, Msg>, "NetGameMsgEvent carries a NetGameMsg");
|
||||
NetGameMsgEvent() : GameMsg(Msg{}.msgId) {}
|
||||
NetGameMsgEvent(const Msg& message) : GameMsg(message.msgId), msg{ message } { target = message.target; }
|
||||
|
||||
Msg msg;
|
||||
};
|
||||
|
||||
// Delivers a copy of a network message to the local handlers registered on msg.target (never to a client).
|
||||
// Returns whether a handler handled it. Handlers see (and may modify) only the copy.
|
||||
template<typename Msg>
|
||||
bool DeliverLocally(const Msg& msg) {
|
||||
NetGameMsgEvent<Msg> event(msg);
|
||||
return event.Send();
|
||||
}
|
||||
|
||||
class PropertyDataMessage;
|
||||
void SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender);
|
||||
void SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation = false);
|
||||
@@ -705,8 +758,8 @@ namespace GameMessages {
|
||||
// This is a client gm however its default values are exactly what we need to get around the invisible inventory item issues.
|
||||
void SendUpdateInventoryUi(LWOOBJID objectId, const SystemAddress& sysAddr);
|
||||
|
||||
struct DisplayTooltip : public GameMsg {
|
||||
DisplayTooltip() : GameMsg(MessageType::Game::DISPLAY_TOOLTIP) {}
|
||||
struct DisplayTooltip : public NetGameMsg {
|
||||
DisplayTooltip() : NetGameMsg(MessageType::Game::DISPLAY_TOOLTIP) {}
|
||||
bool doOrDie{};
|
||||
bool noRepeat{};
|
||||
bool noRevive{};
|
||||
@@ -721,8 +774,8 @@ namespace GameMessages {
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
};
|
||||
|
||||
struct UseItemOnClient : public GameMsg {
|
||||
UseItemOnClient() : GameMsg(MessageType::Game::USE_ITEM_ON_CLIENT) {}
|
||||
struct UseItemOnClient : public NetGameMsg {
|
||||
UseItemOnClient() : NetGameMsg(MessageType::Game::USE_ITEM_ON_CLIENT) {}
|
||||
LWOOBJID playerId{};
|
||||
LWOOBJID itemToUse{};
|
||||
uint32_t itemType{};
|
||||
@@ -741,14 +794,14 @@ namespace GameMessages {
|
||||
LwoNameValue racingSettings{};
|
||||
};
|
||||
|
||||
struct SetModelToBuild : public GameMsg {
|
||||
SetModelToBuild() : GameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {}
|
||||
struct SetModelToBuild : public NetGameMsg {
|
||||
SetModelToBuild() : NetGameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
LOT modelLot{ -1 };
|
||||
};
|
||||
|
||||
struct SpawnModelBricks : public GameMsg {
|
||||
SpawnModelBricks() : GameMsg(MessageType::Game::SPAWN_MODEL_BRICKS) {}
|
||||
struct SpawnModelBricks : public NetGameMsg {
|
||||
SpawnModelBricks() : NetGameMsg(MessageType::Game::SPAWN_MODEL_BRICKS) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
|
||||
float amount{ 0.0f };
|
||||
@@ -761,8 +814,8 @@ namespace GameMessages {
|
||||
LwoNameValue notification{};
|
||||
};
|
||||
|
||||
struct ShootingGalleryFire : public GameMsg {
|
||||
ShootingGalleryFire() : GameMsg(MessageType::Game::SHOOTING_GALLERY_FIRE) {}
|
||||
struct ShootingGalleryFire : public NetGameMsg {
|
||||
ShootingGalleryFire() : NetGameMsg(MessageType::Game::SHOOTING_GALLERY_FIRE) {}
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
|
||||
@@ -781,15 +834,16 @@ namespace GameMessages {
|
||||
PlayerResurrectionFinished() : GameMsg(MessageType::Game::PLAYER_RESURRECTION_FINISHED) {}
|
||||
};
|
||||
|
||||
struct RequestServerObjectInfo : public GameMsg {
|
||||
struct RequestServerObjectInfo : public NetGameMsg {
|
||||
bool bVerbose{};
|
||||
LWOOBJID clientId{};
|
||||
LWOOBJID targetForReport{};
|
||||
|
||||
RequestServerObjectInfo() : GameMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, eGameMasterLevel::DEVELOPER) {}
|
||||
RequestServerObjectInfo() : NetGameMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, eGameMasterLevel::DEVELOPER) {}
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
};
|
||||
using RequestServerObjectInfoEvent = NetGameMsgEvent<RequestServerObjectInfo>;
|
||||
|
||||
struct GetObjectReportInfo : public GameMsg {
|
||||
AMFArrayValue* info{};
|
||||
@@ -797,11 +851,11 @@ namespace GameMessages {
|
||||
bool bVerbose{};
|
||||
LWOOBJID clientID{};
|
||||
|
||||
GetObjectReportInfo() : GameMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, eGameMasterLevel::DEVELOPER) {}
|
||||
GetObjectReportInfo() : GameMsg(MessageType::Game::GET_OBJECT_REPORT_INFO) {}
|
||||
};
|
||||
|
||||
struct RequestUse : public GameMsg {
|
||||
RequestUse() : GameMsg(MessageType::Game::REQUEST_USE) {}
|
||||
struct RequestUse : public NetGameMsg {
|
||||
RequestUse() : NetGameMsg(MessageType::Game::REQUEST_USE) {}
|
||||
|
||||
bool Deserialize(RakNet::BitStream& stream) override;
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
@@ -819,11 +873,12 @@ namespace GameMessages {
|
||||
// Used only for multi-interaction, is of the enum type InteractionType
|
||||
int multiInteractType{};
|
||||
};
|
||||
using RequestUseEvent = NetGameMsgEvent<RequestUse>;
|
||||
|
||||
struct Smash : public GameMsg {
|
||||
Smash() : GameMsg(MessageType::Game::SMASH) {}
|
||||
struct Smash : public NetGameMsg {
|
||||
Smash() : NetGameMsg(MessageType::Game::SMASH) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const;
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
|
||||
bool bIgnoreObjectVisibility{};
|
||||
bool force{};
|
||||
@@ -831,19 +886,19 @@ namespace GameMessages {
|
||||
LWOOBJID killerID{};
|
||||
};
|
||||
|
||||
struct UnSmash : public GameMsg {
|
||||
UnSmash() : GameMsg(MessageType::Game::UN_SMASH) {}
|
||||
struct UnSmash : public NetGameMsg {
|
||||
UnSmash() : NetGameMsg(MessageType::Game::UN_SMASH) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const;
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
|
||||
LWOOBJID builderID{ LWOOBJID_EMPTY };
|
||||
float duration{ 3.0f };
|
||||
};
|
||||
|
||||
struct PlayBehaviorSound : public GameMsg {
|
||||
PlayBehaviorSound() : GameMsg(MessageType::Game::PLAY_BEHAVIOR_SOUND) {}
|
||||
struct PlayBehaviorSound : public NetGameMsg {
|
||||
PlayBehaviorSound() : NetGameMsg(MessageType::Game::PLAY_BEHAVIOR_SOUND) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const;
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
|
||||
int32_t soundID{ -1 };
|
||||
};
|
||||
@@ -857,8 +912,8 @@ namespace GameMessages {
|
||||
bool bResetBehaviors{ true };
|
||||
};
|
||||
|
||||
struct EmotePlayed : public GameMsg {
|
||||
EmotePlayed() : GameMsg(MessageType::Game::EMOTE_PLAYED), emoteID(0), targetID(0) {}
|
||||
struct EmotePlayed : public NetGameMsg {
|
||||
EmotePlayed() : NetGameMsg(MessageType::Game::EMOTE_PLAYED), emoteID(0), targetID(0) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
|
||||
@@ -880,8 +935,8 @@ namespace GameMessages {
|
||||
bool bIgnoreChecks{ false };
|
||||
};
|
||||
|
||||
struct DropClientLoot : public GameMsg {
|
||||
DropClientLoot() : GameMsg(MessageType::Game::DROP_CLIENT_LOOT) {}
|
||||
struct DropClientLoot : public NetGameMsg {
|
||||
DropClientLoot() : NetGameMsg(MessageType::Game::DROP_CLIENT_LOOT) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
LWOOBJID sourceID{ LWOOBJID_EMPTY };
|
||||
@@ -894,6 +949,7 @@ namespace GameMessages {
|
||||
LWOOBJID lootID{ LWOOBJID_EMPTY };
|
||||
LWOOBJID ownerID{ LWOOBJID_EMPTY };
|
||||
};
|
||||
using DropClientLootEvent = NetGameMsgEvent<DropClientLoot>;
|
||||
|
||||
struct GetMissionState : public GameMsg {
|
||||
GetMissionState() : GameMsg(MessageType::Game::GET_MISSION_STATE) {}
|
||||
@@ -923,17 +979,18 @@ namespace GameMessages {
|
||||
LOT item{};
|
||||
};
|
||||
|
||||
struct PickupItem : public GameMsg {
|
||||
PickupItem() : GameMsg(MessageType::Game::PICKUP_ITEM) {}
|
||||
struct PickupItem : public NetGameMsg {
|
||||
PickupItem() : NetGameMsg(MessageType::Game::PICKUP_ITEM) {}
|
||||
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
bool Deserialize(RakNet::BitStream& stream) override;
|
||||
LWOOBJID lootID{};
|
||||
LWOOBJID lootOwnerID{};
|
||||
};
|
||||
using PickupItemEvent = NetGameMsgEvent<PickupItem>;
|
||||
|
||||
struct TeamPickupItem : public GameMsg {
|
||||
TeamPickupItem() : GameMsg(MessageType::Game::TEAM_PICKUP_ITEM) {}
|
||||
struct TeamPickupItem : public NetGameMsg {
|
||||
TeamPickupItem() : NetGameMsg(MessageType::Game::TEAM_PICKUP_ITEM) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
LWOOBJID lootID{};
|
||||
@@ -946,13 +1003,14 @@ namespace GameMessages {
|
||||
bool bDead{};
|
||||
};
|
||||
|
||||
struct ToggleGMInvis : public GameMsg {
|
||||
ToggleGMInvis() : GameMsg(MessageType::Game::TOGGLE_GM_INVIS) {}
|
||||
struct ToggleGMInvis : public NetGameMsg {
|
||||
ToggleGMInvis() : NetGameMsg(MessageType::Game::TOGGLE_GM_INVIS) {}
|
||||
|
||||
void Serialize(RakNet::BitStream& stream) const override;
|
||||
bool bStateOut{ false };
|
||||
|
||||
};
|
||||
using ToggleGMInvisEvent = NetGameMsgEvent<ToggleGMInvis>;
|
||||
|
||||
struct GetGMInvis : public GameMsg {
|
||||
GetGMInvis() : GameMsg(MessageType::Game::GET_GM_INVIS) {}
|
||||
@@ -966,8 +1024,8 @@ namespace GameMessages {
|
||||
LWOOBJID childID{};
|
||||
};
|
||||
|
||||
struct UseSkillSet : public GameMsg {
|
||||
UseSkillSet() : GameMsg(MessageType::Game::USE_SKILL_SET) {}
|
||||
struct UseSkillSet : public NetGameMsg {
|
||||
UseSkillSet() : NetGameMsg(MessageType::Game::USE_SKILL_SET) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
|
||||
bool bRemove{};
|
||||
|
||||
@@ -136,7 +136,7 @@ void DropFactionLoot(Entity& player, GameMessages::DropClientLoot& lootMsg) {
|
||||
lootMsg.lootID = ObjectIDManager::GenerateObjectID();
|
||||
CalcFinalDropPos(lootMsg);
|
||||
// Register the drop on the player
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
// Visually drop it for the player
|
||||
lootMsg.Send(player.GetSystemAddress());
|
||||
}
|
||||
@@ -165,7 +165,7 @@ void DropFactionLoot(const Team& team, GameMessages::DropClientLoot& lootMsg, co
|
||||
lootMsg.lootID = ObjectIDManager::GenerateObjectID();
|
||||
CalcFinalDropPos(lootMsg);
|
||||
// Register the drop on this team member
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
// Show the rewards on all connected members of the team. Only the loot owner will be able to pick the tokens up.
|
||||
DistrbuteMsgToTeam(lootMsg, team);
|
||||
}
|
||||
@@ -184,7 +184,7 @@ void DropPowerupLoot(Entity& player, GameMessages::DropClientLoot& lootMsg) {
|
||||
lootMsg.target = playerID;
|
||||
|
||||
// Register the drop on the player
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
// Visually drop it for the player
|
||||
lootMsg.Send(player.GetSystemAddress());
|
||||
}
|
||||
@@ -210,7 +210,7 @@ void DropPowerupLoot(const Team& team, GameMessages::DropClientLoot& lootMsg, co
|
||||
|
||||
lootMsg.target = member;
|
||||
// By sending this message with the same ID to all players on the team, all players on the team are allowed to pick it up.
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
// No need to send to all members in a loop since that will happen by using the outer loop above and also since there is no owner
|
||||
// sending to all will do nothing.
|
||||
const auto* const memberEntity = Game::entityManager->GetEntity(member);
|
||||
@@ -232,7 +232,7 @@ void DropMissionLoot(Entity& player, GameMessages::DropClientLoot& lootMsg) {
|
||||
lootMsg.lootID = ObjectIDManager::GenerateObjectID();
|
||||
CalcFinalDropPos(lootMsg);
|
||||
// Register the drop with the player
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
// Visually drop the loot to be picked up
|
||||
lootMsg.Send(player.GetSystemAddress());
|
||||
}
|
||||
@@ -261,7 +261,7 @@ void DropMissionLoot(const Team& team, GameMessages::DropClientLoot& lootMsg, co
|
||||
lootMsg.lootID = ObjectIDManager::GenerateObjectID();
|
||||
CalcFinalDropPos(lootMsg);
|
||||
// Register the drop with the player
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
DistrbuteMsgToTeam(lootMsg, team);
|
||||
}
|
||||
}
|
||||
@@ -279,7 +279,7 @@ void DropRegularLoot(Entity& player, GameMessages::DropClientLoot& lootMsg) {
|
||||
lootMsg.target = playerID;
|
||||
lootMsg.ownerID = playerID;
|
||||
// Register the drop with the player
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
// Visually drop the loot to be picked up
|
||||
lootMsg.Send(player.GetSystemAddress());
|
||||
|
||||
@@ -309,14 +309,14 @@ void DropRegularLoot(Team& team, GameMessages::DropClientLoot& lootMsg, const bo
|
||||
if (team.lootOption == 0 /* Shared loot */) {
|
||||
lootMsg.target = earningPlayer;
|
||||
lootMsg.ownerID = earningPlayer;
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
} else /* Free for all loot */ {
|
||||
lootMsg.ownerID = LWOOBJID_EMPTY;
|
||||
// By sending the loot with NO owner and to ALL members of the team,
|
||||
// its a first come, first serve with who picks the item up.
|
||||
for (const auto ffaMember : team.members) {
|
||||
lootMsg.target = ffaMember;
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ void DropLoot(Entity* player, const LWOOBJID source, const std::map<LOT, LootDro
|
||||
lootMsg.sourceID = source;
|
||||
lootMsg.item = LOT_NULL;
|
||||
CalcFinalDropPos(lootMsg);
|
||||
lootMsg.Send();
|
||||
GameMessages::DeliverLocally(lootMsg);
|
||||
const auto* const memberEntity = Game::entityManager->GetEntity(member);
|
||||
if (memberEntity) lootMsg.Send(memberEntity->GetSystemAddress());
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace DEVGMCommands {
|
||||
GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN);
|
||||
entity->SetGMLevel(eGameMasterLevel::CIVILIAN);
|
||||
|
||||
GameMessages::ToggleGMInvis msg;
|
||||
GameMessages::ToggleGMInvisEvent msg;
|
||||
msg.Send(entity->GetObjectID());
|
||||
|
||||
GameMessages::SendSlashCommandFeedbackText(entity, u"Your game master level has been changed, you may not be able to use all commands.");
|
||||
@@ -1593,7 +1593,8 @@ namespace DEVGMCommands {
|
||||
objectInfo.target = closest->GetObjectID();
|
||||
objectInfo.targetForReport = closest->GetObjectID();
|
||||
objectInfo.clientId = entity->GetObjectID();
|
||||
closest->HandleMsg(objectInfo);
|
||||
GameMessages::RequestServerObjectInfoEvent objectInfoEvent(objectInfo);
|
||||
closest->HandleMsg(objectInfoEvent);
|
||||
|
||||
Game::entityManager->SerializeEntity(closest);
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace GMGreaterThanZeroCommands {
|
||||
}
|
||||
|
||||
void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||
GameMessages::ToggleGMInvis msg;
|
||||
GameMessages::ToggleGMInvisEvent msg;
|
||||
msg.Send(entity->GetObjectID());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user