From 48510b731523fe8609261dd3175acfcc92d2a6b2 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 29 Jun 2025 00:22:41 -0700 Subject: [PATCH] feat: add messaging system for manager and add example usage to Loot (#1837) tested that loot still drops at the entities position --- dGame/EntityManager.cpp | 11 +++++++++++ dGame/EntityManager.h | 7 +++++++ dGame/dComponents/ActivityComponent.cpp | 2 +- dGame/dComponents/DestroyableComponent.cpp | 8 ++++---- dGame/dComponents/QuickBuildComponent.cpp | 2 +- dGame/dComponents/RacingControlComponent.cpp | 2 +- dGame/dGameMessages/GameMessages.cpp | 4 ++++ dGame/dGameMessages/GameMessages.h | 6 ++++++ dGame/dUtilities/Loot.cpp | 16 +++++++++------- dGame/dUtilities/Loot.h | 8 ++++---- .../Enemy/General/TreasureChestDragonServer.cpp | 4 ++-- dScripts/02_server/Equipment/BootyDigServer.cpp | 2 +- .../Map/General/BaseInteractDropLootServer.cpp | 2 +- dScripts/02_server/Map/General/GrowingFlower.cpp | 2 +- .../02_server/Map/General/WishingWellServer.cpp | 2 +- dScripts/02_server/Map/VE/VeMissionConsole.cpp | 2 +- .../Map/njhub/NjDragonEmblemChestServer.cpp | 2 +- .../General/MinigameTreasureChestServer.cpp | 4 ++-- dScripts/ActivityManager.cpp | 2 +- dScripts/ScriptedPowerupSpawner.cpp | 2 +- dScripts/ai/AG/AgPicnicBlanket.cpp | 2 +- dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp | 2 +- 22 files changed, 62 insertions(+), 32 deletions(-) diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 0d2c840c..3dde2d53 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -605,3 +605,14 @@ void EntityManager::FireEventServerSide(Entity* origin, std::string args) { bool EntityManager::IsExcludedFromGhosting(LOT lot) { return std::find(m_GhostingExcludedLOTs.begin(), m_GhostingExcludedLOTs.end(), lot) != m_GhostingExcludedLOTs.end(); } + +bool EntityManager::SendMessage(GameMessages::GameMsg& msg) const { + bool handled = false; + const auto entityItr = m_Entities.find(msg.target); + if (entityItr != m_Entities.end()) { + auto* const entity = entityItr->second; + if (entity) handled = entity->HandleMsg(msg); + } + + return handled; +} diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index a0c0d186..780a7c2c 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -14,6 +14,10 @@ class Player; class User; enum class eReplicaComponentType : uint32_t; +namespace GameMessages { + struct GameMsg; +} + struct SystemAddress; class EntityManager { @@ -72,6 +76,9 @@ public: const bool GetHardcoreDropinventoryOnDeath() { return m_HardcoreDropinventoryOnDeath; }; const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; + // Messaging + bool SendMessage(GameMessages::GameMsg& msg) const; + private: void SerializeEntities(); void KillEntities(); diff --git a/dGame/dComponents/ActivityComponent.cpp b/dGame/dComponents/ActivityComponent.cpp index cd71c5cb..a3a25082 100644 --- a/dGame/dComponents/ActivityComponent.cpp +++ b/dGame/dComponents/ActivityComponent.cpp @@ -575,7 +575,7 @@ void ActivityInstance::RewardParticipant(Entity* participant) { maxCoins = currencyTable[0].maxvalue; } - Loot::DropLoot(participant, m_Parent, activityRewards[0].LootMatrixIndex, minCoins, maxCoins); + Loot::DropLoot(participant, m_Parent->GetObjectID(), activityRewards[0].LootMatrixIndex, minCoins, maxCoins); } } diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index cc67a9db..29f14d3b 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -755,18 +755,18 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* member = Game::entityManager->GetEntity(specificOwner); - if (member) Loot::DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); + if (member) Loot::DropLoot(member, m_Parent->GetObjectID(), lootMatrixId, GetMinCoins(), GetMaxCoins()); } else { for (const auto memberId : team->members) { // Free for all auto* member = Game::entityManager->GetEntity(memberId); if (member == nullptr) continue; - Loot::DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); + Loot::DropLoot(member, m_Parent->GetObjectID(), lootMatrixId, GetMinCoins(), GetMaxCoins()); } } } else { // drop loot for non team user - Loot::DropLoot(owner, m_Parent, GetLootMatrixID(), GetMinCoins(), GetMaxCoins()); + Loot::DropLoot(owner, m_Parent->GetObjectID(), GetLootMatrixID(), GetMinCoins(), GetMaxCoins()); } } } else { @@ -784,7 +784,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType coinsTotal -= coinsToLose; - Loot::DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose); + Loot::DropLoot(m_Parent, m_Parent->GetObjectID(), -1, coinsToLose, coinsToLose); character->SetCoins(coinsTotal, eLootSourceType::PICKUP); } } diff --git a/dGame/dComponents/QuickBuildComponent.cpp b/dGame/dComponents/QuickBuildComponent.cpp index 7a5cd8a0..f1a54394 100644 --- a/dGame/dComponents/QuickBuildComponent.cpp +++ b/dGame/dComponents/QuickBuildComponent.cpp @@ -459,7 +459,7 @@ void QuickBuildComponent::CompleteQuickBuild(Entity* const user) { auto* missionComponent = builder->GetComponent(); if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId); } - Loot::DropActivityLoot(builder, m_Parent, m_ActivityId, 1); + Loot::DropActivityLoot(builder, m_Parent->GetObjectID(), m_ActivityId, 1); } // Notify scripts diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index 02a7ca0e..0761dc4a 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -393,7 +393,7 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu } const auto score = playersRating * 10 + data->finished; - Loot::GiveActivityLoot(player, m_Parent, m_ActivityID, score); + Loot::GiveActivityLoot(player, m_Parent->GetObjectID(), m_ActivityID, score); // Giving rewards GameMessages::SendNotifyRacingClient( diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index c2f464d1..0d25774f 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -6312,6 +6312,10 @@ void GameMessages::SendUpdateInventoryUi(LWOOBJID objectId, const SystemAddress& } namespace GameMessages { + bool GameMsg::Send() { + return Game::entityManager->SendMessage(*this); + } + void GameMsg::Send(const SystemAddress& sysAddr) const { CBITSTREAM; CMSGHEADER; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 1573a9d8..91f6cd7c 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -54,6 +54,12 @@ namespace GameMessages { GameMsg(MessageType::Game gmId, eGameMasterLevel lvl) : msgId{ gmId }, requiredGmLevel{ lvl } {} GameMsg(MessageType::Game gmId) : GameMsg(gmId, eGameMasterLevel::CIVILIAN) {} virtual ~GameMsg() = default; + + // Sends a message to the entity manager to route to the target + bool Send(); + + // Sends the message to the specified client or + // all clients if UNASSIGNED_SYSTEM_ADDRESS is specified void Send(const SystemAddress& sysAddr) const; virtual void Serialize(RakNet::BitStream& bitStream) const {} virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; } diff --git a/dGame/dUtilities/Loot.cpp b/dGame/dUtilities/Loot.cpp index ac9868ef..853ebd01 100644 --- a/dGame/dUtilities/Loot.cpp +++ b/dGame/dUtilities/Loot.cpp @@ -214,7 +214,7 @@ void Loot::GiveLoot(Entity* player, std::unordered_map& result, eL } } -void Loot::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) { +void Loot::GiveActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating) { CDActivityRewardsTable* activityRewardsTable = CDClientManager::GetTable(); std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); @@ -248,7 +248,7 @@ void Loot::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, character->SetCoins(character->GetCoins() + coins, eLootSourceType::ACTIVITY); } -void Loot::DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) { +void Loot::DropLoot(Entity* player, const LWOOBJID source, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins) { player = player->GetOwner(); // if the owner is overwritten, we collect that here auto* inventoryComponent = player->GetComponent(); @@ -258,10 +258,10 @@ void Loot::DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, std::unordered_map result = RollLootMatrix(player, matrixIndex); - DropLoot(player, killedObject, result, minCoins, maxCoins); + DropLoot(player, source, result, minCoins, maxCoins); } -void Loot::DropLoot(Entity* player, Entity* killedObject, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins) { +void Loot::DropLoot(Entity* player, const LWOOBJID source, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins) { player = player->GetOwner(); // if the owner is overwritten, we collect that here auto* inventoryComponent = player->GetComponent(); @@ -269,9 +269,11 @@ void Loot::DropLoot(Entity* player, Entity* killedObject, std::unordered_mapGetPosition(); + GameMessages::GetPosition posMsg; + posMsg.target = source; + posMsg.Send(); - const auto source = killedObject->GetObjectID(); + const auto spawnPosition = posMsg.pos; for (const auto& pair : result) { for (int i = 0; i < pair.second; ++i) { @@ -284,7 +286,7 @@ void Loot::DropLoot(Entity* player, Entity* killedObject, std::unordered_map(); std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); diff --git a/dGame/dUtilities/Loot.h b/dGame/dUtilities/Loot.h index ac4d5233..c8247b5b 100644 --- a/dGame/dUtilities/Loot.h +++ b/dGame/dUtilities/Loot.h @@ -18,8 +18,8 @@ namespace Loot { void CacheMatrix(const uint32_t matrixIndex); void GiveLoot(Entity* player, uint32_t matrixIndex, eLootSourceType lootSourceType = eLootSourceType::NONE); void GiveLoot(Entity* player, std::unordered_map& result, eLootSourceType lootSourceType = eLootSourceType::NONE); - void GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0); - void DropLoot(Entity* player, Entity* killedObject, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins); - void DropLoot(Entity* player, Entity* killedObject, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins); - void DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating = 0); + void GiveActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating = 0); + void DropLoot(Entity* player, const LWOOBJID source, uint32_t matrixIndex, uint32_t minCoins, uint32_t maxCoins); + void DropLoot(Entity* player, const LWOOBJID source, std::unordered_map& result, uint32_t minCoins, uint32_t maxCoins); + void DropActivityLoot(Entity* player, const LWOOBJID source, uint32_t activityID, int32_t rating = 0); }; diff --git a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp index fd227087..ec6327e0 100644 --- a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp +++ b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp @@ -33,10 +33,10 @@ void TreasureChestDragonServer::OnUse(Entity* self, Entity* user) { if (memberObject == nullptr) continue; - Loot::DropActivityLoot(memberObject, self, scriptedActivityComponent->GetActivityID(), rating); + Loot::DropActivityLoot(memberObject, self->GetObjectID(), scriptedActivityComponent->GetActivityID(), rating); } } else { - Loot::DropActivityLoot(user, self, scriptedActivityComponent->GetActivityID(), rating); + Loot::DropActivityLoot(user, self->GetObjectID(), scriptedActivityComponent->GetActivityID(), rating); } self->Smash(self->GetObjectID()); diff --git a/dScripts/02_server/Equipment/BootyDigServer.cpp b/dScripts/02_server/Equipment/BootyDigServer.cpp index 0461047e..69c957c8 100644 --- a/dScripts/02_server/Equipment/BootyDigServer.cpp +++ b/dScripts/02_server/Equipment/BootyDigServer.cpp @@ -45,7 +45,7 @@ BootyDigServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string if (renderComponent != nullptr) renderComponent->PlayEffect(7730, u"cast", "bootyshine"); - Loot::DropLoot(player, self, 231, 75, 75); + Loot::DropLoot(player, self->GetObjectID(), 231, 75, 75); } } } else if (args == "ChestDead") { diff --git a/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp b/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp index dd25868d..6b037ca5 100644 --- a/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp +++ b/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp @@ -22,7 +22,7 @@ void BaseInteractDropLootServer::BaseUse(Entity* self, Entity* user) { self->SetNetworkVar(u"bInUse", true); - Loot::DropLoot(user, self, lootMatrix, 0, 0); + Loot::DropLoot(user, self->GetObjectID(), lootMatrix, 0, 0); self->AddCallbackTimer(cooldownTime, [this, self]() { self->SetNetworkVar(u"bInUse", false); diff --git a/dScripts/02_server/Map/General/GrowingFlower.cpp b/dScripts/02_server/Map/General/GrowingFlower.cpp index e9891902..04cc11ab 100644 --- a/dScripts/02_server/Map/General/GrowingFlower.cpp +++ b/dScripts/02_server/Map/General/GrowingFlower.cpp @@ -13,7 +13,7 @@ void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::s const auto mission1 = self->GetVar(u"missionID"); const auto mission2 = self->GetVar(u"missionID2"); - Loot::DropActivityLoot(target, self, self->GetLOT(), 0); + Loot::DropActivityLoot(target, self->GetObjectID(), self->GetLOT(), 0); auto* missionComponent = target->GetComponent(); if (missionComponent != nullptr) { diff --git a/dScripts/02_server/Map/General/WishingWellServer.cpp b/dScripts/02_server/Map/General/WishingWellServer.cpp index 86af5a9a..160282d3 100644 --- a/dScripts/02_server/Map/General/WishingWellServer.cpp +++ b/dScripts/02_server/Map/General/WishingWellServer.cpp @@ -23,7 +23,7 @@ void WishingWellServer::OnUse(Entity* self, Entity* user) { Loot::DropActivityLoot( user, - self, + self->GetObjectID(), static_cast(scriptedActivity->GetActivityID()), GeneralUtils::GenerateRandomNumber(1, 1000) ); diff --git a/dScripts/02_server/Map/VE/VeMissionConsole.cpp b/dScripts/02_server/Map/VE/VeMissionConsole.cpp index aa9abb93..011d680d 100644 --- a/dScripts/02_server/Map/VE/VeMissionConsole.cpp +++ b/dScripts/02_server/Map/VE/VeMissionConsole.cpp @@ -6,7 +6,7 @@ #include "eTerminateType.h" void VeMissionConsole::OnUse(Entity* self, Entity* user) { - Loot::DropActivityLoot(user, self, 12551); + Loot::DropActivityLoot(user, self->GetObjectID(), 12551); auto* inventoryComponent = user->GetComponent(); if (inventoryComponent != nullptr) { diff --git a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp index 74e50b1c..80bb792e 100644 --- a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp +++ b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp @@ -14,6 +14,6 @@ void NjDragonEmblemChestServer::OnUse(Entity* self, Entity* user) { auto* destroyable = self->GetComponent(); if (destroyable != nullptr) { - Loot::DropLoot(user, self, destroyable->GetLootMatrixID(), 0, 0); + Loot::DropLoot(user, self->GetObjectID(), destroyable->GetLootMatrixID(), 0, 0); } } diff --git a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp index 2e5645cd..7b0abaa1 100644 --- a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp +++ b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp @@ -27,7 +27,7 @@ void MinigameTreasureChestServer::OnUse(Entity* self, Entity* user) { if (self->GetLOT() == frakjawChestId) activityRating = team->members.size(); - Loot::DropActivityLoot(teamMember, self, sac->GetActivityID(), activityRating); + Loot::DropActivityLoot(teamMember, self->GetObjectID(), sac->GetActivityID(), activityRating); } } } else { @@ -35,7 +35,7 @@ void MinigameTreasureChestServer::OnUse(Entity* self, Entity* user) { if (self->GetLOT() == frakjawChestId) activityRating = 1; - Loot::DropActivityLoot(user, self, sac->GetActivityID(), activityRating); + Loot::DropActivityLoot(user, self->GetObjectID(), sac->GetActivityID(), activityRating); } sac->PlayerRemove(user->GetObjectID()); diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index f173be58..060fda08 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -72,7 +72,7 @@ void ActivityManager::StopActivity(Entity* self, const LWOOBJID playerID, const SetActivityValue(self, playerID, 1, value1); SetActivityValue(self, playerID, 2, value2); - Loot::GiveActivityLoot(player, self, gameID, CalculateActivityRating(self, playerID)); + Loot::GiveActivityLoot(player, self->GetObjectID(), gameID, CalculateActivityRating(self, playerID)); if (sac != nullptr) { sac->PlayerRemove(player->GetObjectID()); diff --git a/dScripts/ScriptedPowerupSpawner.cpp b/dScripts/ScriptedPowerupSpawner.cpp index 0566a1fa..9abb8fd6 100644 --- a/dScripts/ScriptedPowerupSpawner.cpp +++ b/dScripts/ScriptedPowerupSpawner.cpp @@ -29,7 +29,7 @@ void ScriptedPowerupSpawner::OnTimerDone(Entity* self, std::string message) { renderComponent->PlayEffect(0, u"cast", "N_cast"); } - Loot::DropLoot(owner, self, drops, 0, 0); + Loot::DropLoot(owner, self->GetObjectID(), drops, 0, 0); } // Increment the current cycle diff --git a/dScripts/ai/AG/AgPicnicBlanket.cpp b/dScripts/ai/AG/AgPicnicBlanket.cpp index a413fd21..4e0bb44a 100644 --- a/dScripts/ai/AG/AgPicnicBlanket.cpp +++ b/dScripts/ai/AG/AgPicnicBlanket.cpp @@ -11,7 +11,7 @@ void AgPicnicBlanket::OnUse(Entity* self, Entity* user) { self->SetVar(u"active", true); auto lootTable = std::unordered_map{ {935, 3} }; - Loot::DropLoot(user, self, lootTable, 0, 0); + Loot::DropLoot(user, self->GetObjectID(), lootTable, 0, 0); self->AddCallbackTimer(5.0f, [self]() { self->SetVar(u"active", false); diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 71a8b50a..d291be8b 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -572,7 +572,7 @@ void SGCannon::StopGame(Entity* self, bool cancel) { missionComponent->Progress(eMissionTaskType::ACTIVITY, m_CannonLot, 0, "", self->GetVar(TotalScoreVariable)); } - Loot::GiveActivityLoot(player, self, GetGameID(self), self->GetVar(TotalScoreVariable)); + Loot::GiveActivityLoot(player, self->GetObjectID(), GetGameID(self), self->GetVar(TotalScoreVariable)); SaveScore(self, player->GetObjectID(), static_cast(self->GetVar(TotalScoreVariable)), static_cast(self->GetVar(MaxStreakVariable)), percentage);