Skip to content

Commit

Permalink
add msg handling (#1737)
Browse files Browse the repository at this point in the history
  • Loading branch information
EmosewaMC authored Jan 20, 2025
1 parent 1b3cdc6 commit e4c2eec
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 13 deletions.
29 changes: 27 additions & 2 deletions dCommon/Amf3.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class AMFBaseValue {
// AMFValue template class instantiations
template <typename ValueType>
class AMFValue : public AMFBaseValue {
static_assert(!std::is_same_v<ValueType, std::string_view>, "AMFValue cannot be instantiated with std::string_view");
public:
AMFValue() = default;
AMFValue(const ValueType value) : m_Data{ value } {}
Expand All @@ -52,6 +53,15 @@ class AMFValue : public AMFBaseValue {

void SetValue(const ValueType value) { m_Data = value; }

AMFValue<ValueType>& operator=(const AMFValue<ValueType>& other) {
return operator=(other.m_Data);
}

AMFValue<ValueType>& operator=(const ValueType& other) {
m_Data = other;
return *this;
}

protected:
ValueType m_Data;
};
Expand Down Expand Up @@ -211,13 +221,17 @@ class AMFArrayValue : public AMFBaseValue {
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const std::string_view key, std::unique_ptr<AMFBaseValue> value) {
template<typename AmfType>
AmfType& Insert(const std::string_view key, std::unique_ptr<AmfType> value) {
const auto element = m_Associative.find(key);
auto& toReturn = *value;
if (element != m_Associative.cend() && element->second) {
element->second = std::move(value);
} else {
m_Associative.emplace(key, std::move(value));
}

return toReturn;
}

/**
Expand All @@ -229,11 +243,15 @@ class AMFArrayValue : public AMFBaseValue {
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const size_t index, std::unique_ptr<AMFBaseValue> value) {
template<typename AmfType>
AmfType& Insert(const size_t index, std::unique_ptr<AmfType> value) {
auto& toReturn = *value;
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
}

m_Dense.at(index) = std::move(value);
return toReturn;
}

/**
Expand Down Expand Up @@ -349,6 +367,13 @@ class AMFArrayValue : public AMFBaseValue {
m_Dense.clear();
}

template<typename AmfType = AMFArrayValue>
AmfType& PushDebug(const std::string_view name) {
auto* value = PushArray();
value->Insert("name", name.data());
return value->Insert<AmfType>("value", std::make_unique<AmfType>());
}

private:
/**
* The associative portion. These values are key'd with strings to an AMFValue.
Expand Down
14 changes: 14 additions & 0 deletions dGame/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2216,3 +2216,17 @@ int32_t Entity::GetCollisionGroup() const {

return 0;
}

bool Entity::HandleMsg(GameMessages::GameMsg& msg) const {
bool handled = false;
const auto [beg, end] = m_MsgHandlers.equal_range(msg.msgId);
for (auto it = beg; it != end; ++it) {
if (it->second) handled |= it->second(msg);
}

return handled;
}

void Entity::RegisterMsg(const MessageType::Game msgId, std::function<bool(GameMessages::GameMsg&)> handler) {
m_MsgHandlers.emplace(msgId, handler);
}
11 changes: 11 additions & 0 deletions dGame/Entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
#include "Observable.h"

namespace GameMessages {
struct GameMsg;
struct ActivityNotify;
struct ShootingGalleryFire;
struct ChildLoaded;
struct PlayerResurrectionFinished;
};

namespace MessageType {
enum class Game : uint16_t;
}

namespace Loot {
class Info;
};
Expand Down Expand Up @@ -316,6 +321,10 @@ class Entity {
// Scale will only be communicated to the client when the construction packet is sent
void SetScale(const float scale) { m_Scale = scale; };

void RegisterMsg(const MessageType::Game msgId, std::function<bool(GameMessages::GameMsg&)> handler);

bool HandleMsg(GameMessages::GameMsg& msg) const;

/**
* @brief The observable for player entity position updates.
*/
Expand Down Expand Up @@ -377,6 +386,8 @@ class Entity {

// objectID of receiver and map of notification name to script
std::map<LWOOBJID, std::map<std::string, CppScripts::Script*>> m_Subscriptions;

std::multimap<MessageType::Game, std::function<bool(GameMessages::GameMsg&)>> m_MsgHandlers;
};

/**
Expand Down
44 changes: 43 additions & 1 deletion dGame/dComponents/CharacterComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "Mail.h"
#include "ZoneInstanceManager.h"
#include "WorldPackets.h"
#include "MessageType/Game.h"
#include <ctime>

CharacterComponent::CharacterComponent(Entity* parent, Character* character, const SystemAddress& systemAddress) : Component(parent) {
Expand All @@ -47,6 +48,45 @@ CharacterComponent::CharacterComponent(Entity* parent, Character* character, con
m_CountryCode = 0;
m_LastUpdateTimestamp = std::time(nullptr);
m_SystemAddress = systemAddress;

RegisterMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, this, &CharacterComponent::OnRequestServerObjectInfo);
}

bool CharacterComponent::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) {
auto& request = static_cast<GameMessages::RequestServerObjectInfo&>(msg);
AMFArrayValue response;

response.Insert("visible", true);
response.Insert("objectID", std::to_string(request.targetForReport));
response.Insert("serverInfo", true);

auto& data = *response.InsertArray("data");
auto& cmptType = data.PushDebug("Character");

cmptType.PushDebug<AMFIntValue>("Component ID") = GeneralUtils::ToUnderlying(ComponentType);
cmptType.PushDebug<AMFIntValue>("Character's account ID") = m_Character->GetParentUser()->GetAccountID();
cmptType.PushDebug<AMFBoolValue>("Last log out time") = m_Character->GetLastLogin();
cmptType.PushDebug<AMFDoubleValue>("Seconds played this session") = 0;
cmptType.PushDebug<AMFBoolValue>("Editor enabled") = false;
cmptType.PushDebug<AMFDoubleValue>("Total number of seconds played") = m_TotalTimePlayed;
cmptType.PushDebug<AMFStringValue>("Total currency") = std::to_string(m_Character->GetCoins());
cmptType.PushDebug<AMFStringValue>("Currency able to be picked up") = std::to_string(m_DroppedCoins);
cmptType.PushDebug<AMFStringValue>("Tooltip flags value") = "0";
// visited locations
cmptType.PushDebug<AMFBoolValue>("is a GM") = m_GMLevel > eGameMasterLevel::CIVILIAN;
cmptType.PushDebug<AMFBoolValue>("Has PVP flag turned on") = m_PvpEnabled;
cmptType.PushDebug<AMFIntValue>("GM Level") = GeneralUtils::ToUnderlying(m_GMLevel);
cmptType.PushDebug<AMFIntValue>("Editor level") = GeneralUtils::ToUnderlying(m_EditorLevel);
cmptType.PushDebug<AMFStringValue>("Guild ID") = "0";
cmptType.PushDebug<AMFStringValue>("Guild Name") = "";
cmptType.PushDebug<AMFDoubleValue>("Reputation") = m_Reputation;
cmptType.PushDebug<AMFIntValue>("Current Activity Type") = GeneralUtils::ToUnderlying(m_CurrentActivity);
cmptType.PushDebug<AMFDoubleValue>("Property Clone ID") = m_Character->GetPropertyCloneID();

GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, m_Parent->GetSystemAddress());

LOG("Handled!");
return true;
}

bool CharacterComponent::LandingAnimDisabled(int zoneID) {
Expand Down Expand Up @@ -81,6 +121,8 @@ CharacterComponent::~CharacterComponent() {
void CharacterComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {

if (bIsInitialUpdate) {
if (!m_Character || !m_Character->GetParentUser()) return;

outBitStream.Write(m_ClaimCodes[0] != 0);
if (m_ClaimCodes[0] != 0) outBitStream.Write(m_ClaimCodes[0]);
outBitStream.Write(m_ClaimCodes[1] != 0);
Expand All @@ -100,7 +142,7 @@ void CharacterComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInit
outBitStream.Write(m_Character->GetEyebrows());
outBitStream.Write(m_Character->GetEyes());
outBitStream.Write(m_Character->GetMouth());
outBitStream.Write<uint64_t>(0); //AccountID, trying out if 0 works.
outBitStream.Write<uint64_t>(m_Character->GetParentUser()->GetAccountID());
outBitStream.Write(m_Character->GetLastLogin()); //Last login
outBitStream.Write<uint64_t>(0); //"prop mod last display time"
outBitStream.Write<uint64_t>(m_Uscore); //u-score
Expand Down
2 changes: 2 additions & 0 deletions dGame/dComponents/CharacterComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ class CharacterComponent final : public Component {
Character* m_Character;
private:

bool OnRequestServerObjectInfo(GameMessages::GameMsg& msg);

/**
* The map of active venture vision effects
*/
Expand Down
8 changes: 8 additions & 0 deletions dGame/dComponents/Component.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ namespace RakNet {
class BitStream;
}

namespace GameMessages {
struct GameMsg;
}

class Entity;

/**
Expand Down Expand Up @@ -52,6 +56,10 @@ class Component {

protected:

void RegisterMsg(const MessageType::Game msgId, auto* self, const auto handler) {
m_Parent->RegisterMsg(msgId, std::bind(handler, self, std::placeholders::_1));
}

/**
* The entity that owns this component
*/
Expand Down
39 changes: 31 additions & 8 deletions dGame/dGameMessages/GameMessageHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,19 @@
#include "ePlayerFlag.h"
#include "dConfig.h"
#include "GhostComponent.h"
#include "eGameMasterLevel.h"
#include "StringifiedEnum.h"

namespace {
using enum MessageType::Game;
using namespace GameMessages;
using MessageCreator = std::function<std::unique_ptr<GameMessages::GameMsg>()>;
std::map<MessageType::Game, MessageCreator> g_MessageHandlers = {
{ REQUEST_SERVER_OBJECT_INFO, []() { return std::make_unique<RequestServerObjectInfo>(); } },
{ SHOOTING_GALLERY_FIRE, []() { return std::make_unique<ShootingGalleryFire>(); } },
};
};

void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const SystemAddress& sysAddr, LWOOBJID objectID, MessageType::Game messageID) {

CBITSTREAM;
Expand All @@ -55,6 +66,24 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System

if (messageID != MessageType::Game::READY_FOR_UPDATES) LOG_DEBUG("Received GM with ID and name: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());

auto handler = g_MessageHandlers.find(messageID);
if (handler != g_MessageHandlers.end()) {
auto msg = handler->second();

// Verify that the system address user is able to use this message.
if (msg->requiredGmLevel > eGameMasterLevel::CIVILIAN) {
auto* usingEntity = Game::entityManager->GetEntity(usr->GetLoggedInChar());
if (!usingEntity || usingEntity->GetGMLevel() < msg->requiredGmLevel) {
LOG("User %s (%llu) does not have the required GM level to execute this command.", usingEntity->GetCharacter()->GetName().c_str(), usingEntity->GetObjectID());
return;
}
}

msg->Deserialize(inStream);
msg->Handle(*entity, sysAddr);
return;
}

switch (messageID) {

case MessageType::Game::UN_USE_BBB_MODEL: {
Expand Down Expand Up @@ -104,13 +133,13 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
break;
}

// Currently not actually used for our implementation, however its used right now to get around invisible inventory items in the client.
// Currently not actually used for our implementation, however its used right now to get around invisible inventory items in the client.
case MessageType::Game::SELECT_SKILL: {
auto var = entity->GetVar<bool>(u"dlu_first_time_load");
if (var) {
entity->SetVar<bool>(u"dlu_first_time_load", false);
InventoryComponent* inventoryComponent = entity->GetComponent<InventoryComponent>();

if (inventoryComponent) inventoryComponent->FixInvisibleItems();
}
break;
Expand Down Expand Up @@ -704,12 +733,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
case MessageType::Game::UPDATE_INVENTORY_GROUP_CONTENTS:
GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr);
break;
case MessageType::Game::SHOOTING_GALLERY_FIRE: {
GameMessages::ShootingGalleryFire fire{};
fire.Deserialize(inStream);
fire.Handle(*entity, sysAddr);
break;
}

default:
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
Expand Down
12 changes: 12 additions & 0 deletions dGame/dGameMessages/GameMessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6431,4 +6431,16 @@ namespace GameMessages {
void ShootingGalleryFire::Handle(Entity& entity, const SystemAddress& sysAddr) {
entity.OnShootingGalleryFire(*this);
}

bool RequestServerObjectInfo::Deserialize(RakNet::BitStream& bitStream) {
if (!bitStream.Read(bVerbose)) return false;
if (!bitStream.Read(clientId)) return false;
if (!bitStream.Read(targetForReport)) return false;
return true;
}

void RequestServerObjectInfo::Handle(Entity& entity, const SystemAddress& sysAddr) {
auto* handlingEntity = Game::entityManager->GetEntity(targetForReport);
if (handlingEntity) handlingEntity->HandleMsg(*this);
}
}
15 changes: 14 additions & 1 deletion dGame/dGameMessages/GameMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "eLootSourceType.h"
#include "Brick.h"
#include "MessageType/Game.h"
#include "eGameMasterLevel.h"

class AMFBaseValue;
class Entity;
Expand Down Expand Up @@ -50,14 +51,16 @@ enum class eCameraTargetCyclingMode : int32_t {

namespace GameMessages {
struct GameMsg {
GameMsg(MessageType::Game gmId) : msgId{ gmId } {}
GameMsg(MessageType::Game gmId, eGameMasterLevel lvl) : msgId{ gmId }, requiredGmLevel{ lvl } {}
GameMsg(MessageType::Game gmId) : GameMsg(gmId, eGameMasterLevel::CIVILIAN) {}
virtual ~GameMsg() = default;
void Send(const SystemAddress& sysAddr) const;
virtual void Serialize(RakNet::BitStream& bitStream) const {}
virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; }
virtual void Handle(Entity& entity, const SystemAddress& sysAddr) {};
MessageType::Game msgId;
LWOOBJID target{ LWOOBJID_EMPTY };
eGameMasterLevel requiredGmLevel;
};

class PropertyDataMessage;
Expand Down Expand Up @@ -769,6 +772,16 @@ namespace GameMessages {
struct PlayerResurrectionFinished : public GameMsg {
PlayerResurrectionFinished() : GameMsg(MessageType::Game::PLAYER_RESURRECTION_FINISHED) {}
};

struct RequestServerObjectInfo : public GameMsg {
bool bVerbose{};
LWOOBJID clientId{};
LWOOBJID targetForReport{};

RequestServerObjectInfo() : GameMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, eGameMasterLevel::DEVELOPER) {}
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
};
};

#endif // GAMEMESSAGES_H
2 changes: 1 addition & 1 deletion tests/dCommonTests/Amf3Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ TEST(dCommonTests, AMF3InsertionAssociativeTest) {
array.Insert<int32_t>("Integer", 42U);
array.Insert("Double", 42.0);
array.InsertArray("Array");
array.Insert<std::vector<uint32_t>>("Undefined", {});
array.Insert<std::vector<uint32_t>>("Undefined", std::vector<uint32_t>{});
array.Insert("Null", nullptr);

ASSERT_EQ(array.Get<const char*>("CString")->GetValueType(), eAmf::String);
Expand Down

0 comments on commit e4c2eec

Please sign in to comment.