From dae1925d1a097b7d623ddf4ca2b8a283197c9927 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sat, 26 Sep 2026 19:06:00 -0500 Subject: [PATCH] refactor: effects, audio, animation and UI text game messages as structs Converts PlayAnimation, PlayNDAudioEmitter, PlayEmbeddedEffectOnAllClientsNearObject, PlayFXEffect, StopFXEffect, BroadcastTextToChatbox, Play2DAmbientSound, Stop2DAmbientSound, UIMessageServerToSingleClient, UIMessageServerToAllClients, StartCelebrationEffect, DisplayMessageBox, DisplayChatBubble, ChangeIdleFlags, SetNameBillboardState, ShowBillboardInteractIcon, PlayCinematic, EndCinematic, SlashCommandTextFeedback, PlayEmote and SetEmoteLockState (21 old Send functions, 23 with overloads) and the received MessageBoxRespond, ChoiceBoxRespond, CinematicUpdate and PlayEmote to NetGameMsgs in EffectsMessages.{h,cpp}. The high traffic messages get a constructor for their required fields. UI messages own their AMF arguments. Every caller is switched, the received messages are registered in GameMessageHandler's map, and the old functions and switch cases are deleted. Handlers are copied verbatim. No wire change and no change in recipients: functions that always broadcast whatever address they were given are sent with Send(UNASSIGNED_SYSTEM_ADDRESS), functions that only did SEND_PACKET use SendToClient. Quirks are kept and documented on the structs (PlayAnimation's UTF-8 sized name, the always written null terminator in BroadcastTextToChatbox, StartCelebrationEffect always writing celebrationID, SetNameBillboardState having no payload). Verified byte for byte against a frozen verbatim copy of the old functions over an input grid, to one client and broadcast; received messages compared with the old handlers' read sequences and every truncated payload rejected; hand computed golden bytes; round trips; a deliberate width mutation made the tests fail. The byte-equality helper gains a Broadcast mode for functions that ignored their address. Co-Authored-By: Claude Opus 5.5 --- dGame/Character.cpp | 20 +- dGame/Entity.cpp | 8 +- dGame/dBehaviors/Behavior.cpp | 13 +- dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp | 13 +- dGame/dComponents/BaseCombatAIComponent.cpp | 5 +- dGame/dComponents/BouncerComponent.cpp | 5 +- dGame/dComponents/BuffComponent.cpp | 8 +- dGame/dComponents/CharacterComponent.cpp | 7 +- dGame/dComponents/DestroyableComponent.cpp | 19 +- dGame/dComponents/PetComponent.cpp | 11 +- .../dComponents/PropertyEntranceComponent.cpp | 7 +- dGame/dComponents/QuickBuildComponent.cpp | 5 +- dGame/dComponents/RailActivatorComponent.cpp | 14 +- dGame/dComponents/RenderComponent.cpp | 17 +- dGame/dComponents/SwitchComponent.cpp | 3 +- dGame/dComponents/TriggerComponent.cpp | 21 +- dGame/dGameMessages/CMakeLists.txt | 1 + dGame/dGameMessages/EffectsMessages.cpp | 489 +++++++++++++ dGame/dGameMessages/EffectsMessages.h | 327 +++++++++ dGame/dGameMessages/GameMessageHandler.cpp | 28 +- dGame/dGameMessages/GameMessages.cpp | 674 +----------------- dGame/dGameMessages/GameMessages.h | 51 -- dGame/dGameMessages/MissionMessages.cpp | 5 +- dGame/dPropertyBehaviors/ControlBehaviors.cpp | 25 +- dGame/dUtilities/DashboardActions.cpp | 9 +- dGame/dUtilities/DashboardNotify.cpp | 6 +- dGame/dUtilities/LiveEvents.cpp | 7 +- dGame/dUtilities/SlashCommandHandler.cpp | 14 +- .../SlashCommands/DEVGMCommands.cpp | 48 +- .../GMGreaterThanZeroCommands.cpp | 7 +- .../SlashCommands/GMZeroCommands.cpp | 25 +- .../DLU/DLUVanityTeleportingObject.cpp | 13 +- .../Enemy/AG/BossSpiderQueenEnemyServer.cpp | 8 +- .../02_server/Enemy/AM/AmDarklingDragon.cpp | 15 +- .../02_server/Enemy/FV/FvMaelstromDragon.cpp | 15 +- .../02_server/Enemy/General/BaseEnemyApe.cpp | 13 +- .../02_server/Map/AG/NpcEpsilonServer.cpp | 6 +- .../02_server/Map/AM/AmShieldGenerator.cpp | 3 +- .../Map/AM/AmShieldGeneratorQuickbuild.cpp | 3 +- dScripts/02_server/Map/AM/AmSkullkinDrill.cpp | 26 +- .../02_server/Map/AM/AmSkullkinDrillStand.cpp | 3 +- .../02_server/Map/FV/ImgBrickConsoleQB.cpp | 21 +- .../Map/FV/Racing/RaceMaelstromGeiser.cpp | 5 +- .../02_server/Map/GF/GfCaptainsCannon.cpp | 15 +- dScripts/02_server/Map/GF/MastTeleport.cpp | 19 +- .../Map/General/BankInteractServer.cpp | 13 +- .../General/BaseInteractDropLootServer.cpp | 3 +- .../02_server/Map/General/ExplodingAsset.cpp | 12 +- .../02_server/Map/General/MailBoxServer.cpp | 13 +- .../02_server/Map/General/PropertyDevice.cpp | 3 +- .../Map/General/StoryBoxInteractServer.cpp | 13 +- .../Map/General/TokenConsoleServer.cpp | 3 +- .../Map/General/WishingWellServer.cpp | 3 +- dScripts/02_server/Map/NS/NsLegoClubDoor.cpp | 13 +- dScripts/02_server/Map/NS/NsLupTeleport.cpp | 7 +- .../02_server/Map/NS/NsTokenConsoleServer.cpp | 3 +- .../02_server/Map/NT/NtAssemblyTubeServer.cpp | 19 +- .../Map/NT/NtBeamImaginationCollectors.cpp | 3 +- .../NT/NtCombatChallengeExplodingDummy.cpp | 8 +- .../Map/NT/NtCombatChallengeServer.cpp | 11 +- .../02_server/Map/NT/NtParadoxPanelServer.cpp | 5 +- .../02_server/Map/NT/NtParadoxTeleServer.cpp | 13 +- .../Map/NT/NtVentureCannonServer.cpp | 33 +- dScripts/02_server/Map/PR/HydrantBroken.cpp | 3 +- .../Property/AG_Small/EnemySpiderSpawner.cpp | 7 +- .../Map/Property/AG_Small/ZoneAgProperty.cpp | 17 +- .../Map/Property/PropertyBankInteract.cpp | 13 +- .../Map/njhub/CatapultBaseServer.cpp | 3 +- dScripts/02_server/Map/njhub/FallingTile.cpp | 5 +- .../Map/njhub/NjGarmadonCelebration.cpp | 6 +- dScripts/02_server/Map/njhub/NjWuNPC.cpp | 3 +- dScripts/02_server/Map/njhub/RainOfArrows.cpp | 3 +- .../boss_instance/NjMonastryBossInstance.cpp | 3 +- dScripts/BaseConsoleTeleportServer.cpp | 13 +- dScripts/BasePropertyServer.cpp | 41 +- dScripts/BaseSurvivalServer.cpp | 3 +- dScripts/BaseWavesServer.cpp | 3 +- dScripts/ChooseYourDestinationNsToNt.cpp | 11 +- dScripts/NtFactionSpyServer.cpp | 10 +- dScripts/SpawnPetBaseServer.cpp | 6 +- dScripts/ai/ACT/ActMine.cpp | 5 +- dScripts/ai/AG/AgBusDoor.cpp | 5 +- dScripts/ai/AG/AgJetEffectServer.cpp | 5 +- dScripts/ai/AG/AgShipPlayerShockServer.cpp | 5 +- dScripts/ai/AG/AgShipShake.cpp | 15 +- dScripts/ai/AG/AgSpiderBossMessage.cpp | 3 +- dScripts/ai/FV/ActNinjaSensei.cpp | 35 +- dScripts/ai/FV/ActParadoxPipeFix.cpp | 17 +- dScripts/ai/FV/FvFacilityBrick.cpp | 43 +- dScripts/ai/FV/FvFacilityPipes.cpp | 7 +- dScripts/ai/GENERAL/ForceFieldEffect.cpp | 3 +- ...nceExitTransferPlayerToLastNonInstance.cpp | 20 +- dScripts/ai/GF/GfOrgan.cpp | 3 +- .../ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp | 18 +- dScripts/ai/NP/NpcNpJetpackGuy.cpp | 3 +- dScripts/ai/NS/NsConcertInstrument.cpp | 12 +- dScripts/ai/NS/NsConcertQuickBuild.cpp | 6 +- dScripts/ai/NS/NsGetFactionMissionServer.cpp | 6 +- dScripts/ai/NS/WH/RockHydrantBroken.cpp | 3 +- dScripts/ai/PROPERTY/AG/AgPropGuard.cpp | 6 +- dScripts/ai/PROPERTY/AgPropguards.cpp | 6 +- dScripts/ai/SPEC/SpecialCoinSpawner.cpp | 3 +- dScripts/ai/SPEC/SpecialPowerupSpawner.cpp | 3 +- dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp | 3 +- dScripts/ai/WILD/LupGenericInteract.cpp | 3 +- dScripts/ai/WILD/WildAmbientCrab.cpp | 11 +- dScripts/ai/WILD/WildAndScared.cpp | 3 +- dScripts/ai/WILD/WildGfGlowbug.cpp | 9 +- dScripts/ai/WILD/WildNinjaBricks.cpp | 7 +- dScripts/ai/WILD/WildNinjaSensei.cpp | 15 +- dScripts/ai/WILD/WildNinjaStudent.cpp | 11 +- dScripts/ai/WILD/WildPants.cpp | 3 +- dWorldServer/WorldServer.cpp | 17 +- .../dGameMessagesTests/CMakeLists.txt | 1 + .../EffectsMessagesTests.cpp | 571 +++++++++++++++ .../dGameMessagesTests/GameMessageTestUtils.h | 12 +- .../Legacy/EffectsMessagesLegacy.h | 607 ++++++++++++++++ 117 files changed, 2832 insertions(+), 1058 deletions(-) create mode 100644 dGame/dGameMessages/EffectsMessages.cpp create mode 100644 dGame/dGameMessages/EffectsMessages.h create mode 100644 tests/dGameTests/dGameMessagesTests/EffectsMessagesTests.cpp create mode 100644 tests/dGameTests/dGameMessagesTests/Legacy/EffectsMessagesLegacy.h diff --git a/dGame/Character.cpp b/dGame/Character.cpp index 763223e59..46f061081 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -10,6 +10,7 @@ #include "Entity.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionMessages.h" #include "MissionComponent.h" #include "dZoneManager.h" @@ -239,7 +240,12 @@ void Character::DoQuickXMLDataParse() { void Character::UnlockEmote(int emoteID) { m_UnlockedEmotes.push_back(emoteID); - GameMessages::SendSetEmoteLockState(Game::entityManager->GetEntity(m_ObjectID), false, emoteID); + auto* const entity = Game::entityManager->GetEntity(m_ObjectID); + GameMessages::SetEmoteLockState lockState; + lockState.target = entity->GetObjectID(); + lockState.bLock = false; + lockState.emoteID = emoteID; + lockState.SendToClient(entity->GetSystemAddress()); } void Character::SetBuildMode(bool buildMode) { @@ -590,7 +596,9 @@ void Character::SetBillboardVisible(bool visible) { if (m_BillboardVisible == visible) return; m_BillboardVisible = visible; - GameMessages::SendSetNamebillboardState(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + GameMessages::SetNameBillboardState billboardState; + billboardState.target = m_OurEntity->GetObjectID(); + billboardState.Send(UNASSIGNED_SYSTEM_ADDRESS); if (!visible) return; @@ -598,8 +606,12 @@ void Character::SetBillboardVisible(bool visible) { // Because that same message does not allow for custom parameters, we need to create the BillboardSubcomponent a different way // This workaround involves sending an unrelated GameMessage that does not apply to player entites, // but forces the client to create the necessary SubComponent that controls the billboard. - GameMessages::SendShowBillboardInteractIcon(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + GameMessages::ShowBillboardInteractIcon interactIcon; + interactIcon.target = m_OurEntity->GetObjectID(); + interactIcon.Send(UNASSIGNED_SYSTEM_ADDRESS); // Now turn off the billboard for the owner. - GameMessages::SendSetNamebillboardState(m_OurEntity->GetSystemAddress(), m_OurEntity->GetObjectID()); + GameMessages::SetNameBillboardState ownerBillboardState; + ownerBillboardState.target = m_OurEntity->GetObjectID(); + ownerBillboardState.Send(m_OurEntity->GetSystemAddress()); } diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 622bbf1cd..c9434cffb 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -12,6 +12,7 @@ #include #include "dServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "Zone.h" @@ -2265,7 +2266,12 @@ bool Entity::MsgRequestServerObjectInfo(GameMessages::RequestServerObjectInfoEve HandleMsg(info); auto* client = Game::entityManager->GetEntity(requestInfo.clientId); - if (client) GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, client->GetSystemAddress()); + if (client) { + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleObjectDebugger"; + uiMessage.args = std::move(response); + uiMessage.SendToClient(client->GetSystemAddress()); + } return true; } diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 7cefd4dd7..9ad9d8a53 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -25,6 +25,7 @@ #include "ChainBehavior.h" #include "ChargeUpBehavior.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "HealBehavior.h" #include "ImaginationBehavior.h" #include "KnockbackBehavior.h" @@ -326,7 +327,9 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID const auto effectId = this->m_effectId; if (effectId == 0) { - GameMessages::SendPlayFXEffect(targetEntity, -1, type, "", secondary, 1, 1, true); + GameMessages::PlayFXEffect fx(targetEntity->GetObjectID(), -1, type, ""); + fx.secondary = secondary; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); return; } @@ -343,7 +346,9 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID if (itr != m_effectNames.end()) { if (renderComponent == nullptr) { - GameMessages::SendPlayFXEffect(targetEntity, effectId, type, itr->second, secondary, 1, 1, true); + GameMessages::PlayFXEffect fx(targetEntity->GetObjectID(), effectId, type, itr->second); + fx.secondary = secondary; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); return; } @@ -392,7 +397,9 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID m_effectNames.insert_or_assign(typeString, name); if (renderComponent == nullptr) { - GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true); + GameMessages::PlayFXEffect fx(targetEntity->GetObjectID(), effectId, type, name); + fx.secondary = secondary; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); return; } diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp index b7c6b80a2..8d7ed89ec 100644 --- a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp @@ -2,12 +2,17 @@ #include "ChangeIdleFlagsBehavior.h" #include "BehaviorContext.h" #include "BehaviorBranchContext.h" +#include "EffectsMessages.h" void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; if (!target) return; - GameMessages::SendChangeIdleFlags(target, m_FlagsOn, m_FlagsOff, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = target; + idleFlags.flagsOn = m_FlagsOn; + idleFlags.flagsOff = m_FlagsOff; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); if (branch.duration > 0.0f) { context->RegisterTimerBehavior(this, branch); @@ -24,7 +29,11 @@ void ChangeIdleFlagsBehavior::End(BehaviorContext* context, BehaviorBranchContex const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; if (!target) return; // flip on and off to end behavior - GameMessages::SendChangeIdleFlags(target, m_FlagsOff, m_FlagsOn, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = target; + idleFlags.flagsOn = m_FlagsOff; + idleFlags.flagsOff = m_FlagsOn; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); } void ChangeIdleFlagsBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index 09335459c..5bc74f6e9 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -8,6 +8,7 @@ #include "dpWorld.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "dServer.h" #include "Game.h" @@ -163,7 +164,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { m_TetherTime -= deltaTime; m_ForcedTetherTime -= deltaTime; if (m_ForcedTetherTime >= 0) return; - GameMessages::SendStopFXEffect(m_Parent, true, "tether"); + GameMessages::StopFXEffect(m_Parent->GetObjectID(), true, "tether").Send(UNASSIGNED_SYSTEM_ADDRESS); m_TetherEffectActive = false; } @@ -836,7 +837,7 @@ void BaseCombatAIComponent::TetherLogic() { Game::entityManager->SerializeEntity(m_Parent); } - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 6270, u"tether", "tether"); + GameMessages::PlayFXEffect(m_Parent->GetObjectID(), 6270, u"tether", "tether").Send(UNASSIGNED_SYSTEM_ADDRESS); m_TetherEffectActive = true; } diff --git a/dGame/dComponents/BouncerComponent.cpp b/dGame/dComponents/BouncerComponent.cpp index dc1d50f22..c58fba088 100644 --- a/dGame/dComponents/BouncerComponent.cpp +++ b/dGame/dComponents/BouncerComponent.cpp @@ -7,6 +7,7 @@ #include "Game.h" #include "Logger.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "BitStream.h" #include "eTriggerEventType.h" #include "Amf3.h" @@ -67,10 +68,10 @@ void BouncerComponent::SetPetBouncerEnabled(bool value) { if (value) { m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent); - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch").Send(UNASSIGNED_SYSTEM_ADDRESS); } else { m_Parent->TriggerEvent(eTriggerEventType::PET_OFF_SWITCH, m_Parent); - GameMessages::SendStopFXEffect(m_Parent, true, "PetOnSwitch"); + GameMessages::StopFXEffect(m_Parent->GetObjectID(), true, "PetOnSwitch").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index 8d699b548..95a9c4508 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -6,6 +6,7 @@ #include "Game.h" #include "Logger.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "SkillComponent.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" @@ -123,7 +124,10 @@ void BuffComponent::ApplyBuffFx(uint32_t buffId, const BuffParameter& buff) { fxToPlay += std::to_string(buffId); LOG_DEBUG("Playing %s %i", fxToPlay.c_str(), buff.effectId); - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), buff.effectId, u"cast", fxToPlay, LWOOBJID_EMPTY, 1.07f, 1.0f, false); + GameMessages::PlayFXEffect fx(m_Parent->GetObjectID(), buff.effectId, u"cast", fxToPlay); + fx.priority = 1.07f; + fx.serialize = false; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); } void BuffComponent::RemoveBuffFx(uint32_t buffId, const BuffParameter& buff) { @@ -134,7 +138,7 @@ void BuffComponent::RemoveBuffFx(uint32_t buffId, const BuffParameter& buff) { fxToPlay += std::to_string(buffId); LOG_DEBUG("Stopping %s", fxToPlay.c_str()); - GameMessages::SendStopFXEffect(m_Parent, false, fxToPlay); + GameMessages::StopFXEffect(m_Parent->GetObjectID(), false, fxToPlay).Send(UNASSIGNED_SYSTEM_ADDRESS); } void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity, diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 1ee3ca961..a47c0e6c5 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -12,6 +12,7 @@ #include "EntityManager.h" #include "HavokVehiclePhysicsComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Item.h" #include "Amf3.h" #include "eGameMasterLevel.h" @@ -844,7 +845,11 @@ void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventu if (!m_Parent) return; AMFArrayValue arrayToSend; arrayToSend.Insert(ventureVisionType, showFaction); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", arrayToSend); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = m_Parent->GetObjectID(); + uiMessage.strMessageName = "SetFactionVisibility"; + uiMessage.args = std::move(arrayToSend); + uiMessage.SendToClient(m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS); } void CharacterComponent::AwardClaimCodes() { diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 44f8bb41a..297dd574a 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -11,6 +11,7 @@ #include "Amf3.h" #include "AmfSerialize.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "User.h" #include "CDClientManager.h" #include "CDDestructibleComponentTable.h" @@ -272,7 +273,11 @@ void DestroyableComponent::SetMaxHealth(float value, bool playAnim) { args.Insert("amount", std::to_string(difference)); args.Insert("type", "health"); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, characterComponent->GetSystemAddress(), "MaxPlayerBarUpdate", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = m_Parent->GetObjectID(); + uiMessage.strMessageName = "MaxPlayerBarUpdate"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(characterComponent->GetSystemAddress()); } Game::entityManager->SerializeEntity(m_Parent); @@ -314,7 +319,11 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) { args.Insert("amount", std::to_string(value)); args.Insert("type", "armor"); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, characterComponent->GetSystemAddress(), "MaxPlayerBarUpdate", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = m_Parent->GetObjectID(); + uiMessage.strMessageName = "MaxPlayerBarUpdate"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(characterComponent->GetSystemAddress()); } Game::entityManager->SerializeEntity(m_Parent); @@ -355,7 +364,11 @@ void DestroyableComponent::SetMaxImagination(float value, bool playAnim) { args.Insert("amount", std::to_string(difference)); args.Insert("type", "imagination"); - GameMessages::SendUIMessageServerToSingleClient(m_Parent, characterComponent->GetSystemAddress(), "MaxPlayerBarUpdate", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = m_Parent->GetObjectID(); + uiMessage.strMessageName = "MaxPlayerBarUpdate"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(characterComponent->GetSystemAddress()); } Game::entityManager->SerializeEntity(m_Parent); } diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index c2e36929e..2181361c2 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -2,6 +2,7 @@ #include "DashboardNotify.h" #include "GameMessages.h" #include "PetMessages.h" +#include "EffectsMessages.h" #include "BrickDatabase.h" #include "CDClientDatabase.h" #include "CDTamingBuildPuzzleTable.h" @@ -469,7 +470,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { const auto* const entry = CDClientManager::GetTable()->GetByLOT(m_Parent->GetLOT()); if (!entry) return; - GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(tamer->GetObjectID(), -1, u"petceleb", "").Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(tamer, u"rebuild-celebrate"); EntityInfo info{}; @@ -1036,7 +1037,7 @@ void PetComponent::AddDrainImaginationTimer(bool fromTaming) { } void PetComponent::Deactivate() { - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "").Send(UNASSIGNED_SYSTEM_ADDRESS); activePets.erase(m_Owner); @@ -1105,7 +1106,11 @@ void PetComponent::Command(const NiPoint3& position, const LWOOBJID source, cons if (commandType == 1) { // Emotes - GameMessages::SendPlayEmote(m_Parent->GetObjectID(), typeId, owner->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayEmote playEmote; + playEmote.target = m_Parent->GetObjectID(); + playEmote.emoteID = typeId; + playEmote.targetID = owner->GetObjectID(); + playEmote.Send(UNASSIGNED_SYSTEM_ADDRESS); GameMessages::EmotePlayed msg; msg.target = owner->GetObjectID(); msg.emoteID = typeId; diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index b4a02ac4a..5548b89c6 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -5,6 +5,7 @@ #include "Character.h" #include "Database.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "PropertyManagementComponent.h" #include "PropertyMessages.h" #include "RocketLaunchpadControlComponent.h" @@ -42,7 +43,11 @@ void PropertyEntranceComponent::OnUse(Entity* entity) { args.Insert("state", "property_menu"); - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(entity->GetSystemAddress()); } void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) { diff --git a/dGame/dComponents/QuickBuildComponent.cpp b/dGame/dComponents/QuickBuildComponent.cpp index 8fda9fe7d..11737c82a 100644 --- a/dGame/dComponents/QuickBuildComponent.cpp +++ b/dGame/dComponents/QuickBuildComponent.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "Game.h" #include "Logger.h" @@ -425,7 +426,9 @@ void QuickBuildComponent::CompleteQuickBuild(Entity* const user) { Game::entityManager->SerializeEntity(user); GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::COMPLETED, user->GetObjectID()); - GameMessages::SendPlayFXEffect(m_Parent, 507, u"create", "BrickFadeUpVisCompleteEffect", LWOOBJID_EMPTY, 0.4f, 1.0f, true); + GameMessages::PlayFXEffect fx(m_Parent->GetObjectID(), 507, u"create", "BrickFadeUpVisCompleteEffect"); + fx.priority = 0.4f; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendEnableQuickBuild(m_Parent, false, false, true, eQuickBuildFailReason::NOT_GIVEN, m_ResetTime, user->GetObjectID()); GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); diff --git a/dGame/dComponents/RailActivatorComponent.cpp b/dGame/dComponents/RailActivatorComponent.cpp index 8ef050753..ce54ce057 100644 --- a/dGame/dComponents/RailActivatorComponent.cpp +++ b/dGame/dComponents/RailActivatorComponent.cpp @@ -4,6 +4,7 @@ #include "CDRailActivatorComponent.h" #include "Entity.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "QuickBuildComponent.h" #include "Game.h" #include "Logger.h" @@ -55,8 +56,7 @@ void RailActivatorComponent::OnUse(Entity* originator) { // Start the initial effects if (!m_StartEffect.second.empty()) { - GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_StartEffect.first, m_StartEffect.second, - std::to_string(m_StartEffect.first)); + GameMessages::PlayFXEffect(originator->GetObjectID(), m_StartEffect.first, m_StartEffect.second, std::to_string(m_StartEffect.first)).Send(UNASSIGNED_SYSTEM_ADDRESS); } float animationLength = 0.5f; @@ -90,13 +90,12 @@ void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { if (std::find(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), originator->GetObjectID()) != m_EntitiesOnRail.end()) { // Stop the initial effects if (!m_StartEffect.second.empty()) { - GameMessages::SendStopFXEffect(originator, false, std::to_string(m_StartEffect.first)); + GameMessages::StopFXEffect(originator->GetObjectID(), false, std::to_string(m_StartEffect.first)).Send(UNASSIGNED_SYSTEM_ADDRESS); } // Start the looping effects if (!m_LoopEffect.second.empty()) { - GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_LoopEffect.first, m_LoopEffect.second, - std::to_string(m_LoopEffect.first)); + GameMessages::PlayFXEffect(originator->GetObjectID(), m_LoopEffect.first, m_LoopEffect.second, std::to_string(m_LoopEffect.first)).Send(UNASSIGNED_SYSTEM_ADDRESS); } if (!m_LoopAnimation.empty()) { @@ -125,13 +124,12 @@ void RailActivatorComponent::OnCancelRailMovement(Entity* originator) { if (std::find(m_EntitiesOnRail.begin(), m_EntitiesOnRail.end(), originator->GetObjectID()) != m_EntitiesOnRail.end()) { // Stop the looping effects if (!m_LoopEffect.second.empty()) { - GameMessages::SendStopFXEffect(originator, false, std::to_string(m_LoopEffect.first)); + GameMessages::StopFXEffect(originator->GetObjectID(), false, std::to_string(m_LoopEffect.first)).Send(UNASSIGNED_SYSTEM_ADDRESS); } // Start the end effects if (!m_StopEffect.second.empty()) { - GameMessages::SendPlayFXEffect(originator->GetObjectID(), m_StopEffect.first, m_StopEffect.second, - std::to_string(m_StopEffect.first)); + GameMessages::PlayFXEffect(originator->GetObjectID(), m_StopEffect.first, m_StopEffect.second, std::to_string(m_StopEffect.first)).Send(UNASSIGNED_SYSTEM_ADDRESS); } if (!m_StopAnimation.empty()) { diff --git a/dGame/dComponents/RenderComponent.cpp b/dGame/dComponents/RenderComponent.cpp index f30648cc9..74f7c4fa9 100644 --- a/dGame/dComponents/RenderComponent.cpp +++ b/dGame/dComponents/RenderComponent.cpp @@ -10,6 +10,7 @@ #include "CDClientManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Game.h" #include "Logger.h" #include "CDAnimationsTable.h" @@ -96,7 +97,12 @@ void RenderComponent::Update(const float deltaTime) { void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& effectType, const std::string& name, const LWOOBJID secondary, const float priority, const float scale, const bool serialize) { RemoveEffect(name); - GameMessages::SendPlayFXEffect(m_Parent, effectId, effectType, name, secondary, priority, scale, serialize); + GameMessages::PlayFXEffect fx(m_Parent->GetObjectID(), effectId, effectType, name); + fx.secondary = secondary; + fx.priority = priority; + fx.scale = scale; + fx.serialize = serialize; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); auto& effect = AddEffect(effectId, name, effectType, priority); @@ -135,7 +141,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e } void RenderComponent::StopEffect(const std::string& name, const bool killImmediate) { - GameMessages::SendStopFXEffect(m_Parent, killImmediate, name); + GameMessages::StopFXEffect(m_Parent->GetObjectID(), killImmediate, name).Send(UNASSIGNED_SYSTEM_ADDRESS); RemoveEffect(name); } @@ -175,7 +181,12 @@ float RenderComponent::DoAnimation(Entity* self, const std::string& animation, b returnlength = animationGroup->animation_length; } } - if (sendAnimation) GameMessages::SendPlayAnimation(self, GeneralUtils::ASCIIToUTF16(animation), priority, scale); + if (sendAnimation) { + GameMessages::PlayAnimation playAnimation(self->GetObjectID(), GeneralUtils::ASCIIToUTF16(animation)); + playAnimation.fPriority = priority; + playAnimation.fScale = scale; + playAnimation.Send(UNASSIGNED_SYSTEM_ADDRESS); + } if (returnlength == 0.0f) LOG("WARNING: Unable to find animation %s for lot %i in any group.", animation.c_str(), self->GetLOT()); return returnlength; } diff --git a/dGame/dComponents/SwitchComponent.cpp b/dGame/dComponents/SwitchComponent.cpp index 6406690a3..07f989877 100644 --- a/dGame/dComponents/SwitchComponent.cpp +++ b/dGame/dComponents/SwitchComponent.cpp @@ -3,6 +3,7 @@ #include "eTriggerEventType.h" #include "RenderComponent.h" #include "DestroyableComponent.h" +#include "EffectsMessages.h" std::vector SwitchComponent::petSwitches; @@ -78,7 +79,7 @@ void SwitchComponent::EntityEnter(Entity* entity) { m_Timer = m_ResetTime; if (m_PetBouncer != nullptr) { - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 2602, u"pettriggeractive", "BounceEffect", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(m_Parent->GetObjectID(), 2602, u"pettriggeractive", "BounceEffect").Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(m_Parent, u"engaged"); m_PetBouncer->SetPetBouncerEnabled(true); } else { diff --git a/dGame/dComponents/TriggerComponent.cpp b/dGame/dComponents/TriggerComponent.cpp index 3c2489aa7..46037f6ac 100644 --- a/dGame/dComponents/TriggerComponent.cpp +++ b/dGame/dComponents/TriggerComponent.cpp @@ -18,6 +18,7 @@ #include "MovementAIComponent.h" #include +#include "EffectsMessages.h" TriggerComponent::TriggerComponent(Entity* parent, const int32_t componentID, const std::string triggerInfo) : Component(parent, componentID) { m_Parent = parent; @@ -124,7 +125,7 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity HandlePlayEffect(targetEntity, argArray); break; case eTriggerCommandType::STOP_EFFECT: - GameMessages::SendStopFXEffect(targetEntity, true, command->args); + GameMessages::StopFXEffect(targetEntity->GetObjectID(), true, command->args).Send(UNASSIGNED_SYSTEM_ADDRESS); break; case eTriggerCommandType::CAST_SKILL: HandleCastSkill(targetEntity, command->args); @@ -327,7 +328,19 @@ void TriggerComponent::HandlePlayCinematic(Entity* targetEntity, std::vectorGetObjectID(), GeneralUtils::UTF8ToUTF16(argArray.at(0)), targetEntity->GetSystemAddress(), true, true, false, false, wait, hidePlayer, leadIn, leaveLocked, unlock); + GameMessages::PlayCinematic cinematic; + cinematic.target = targetEntity->GetObjectID(); + cinematic.pathName = GeneralUtils::UTF8ToUTF16(argArray.at(0)); + cinematic.allowGhostUpdates = true; + cinematic.bCloseMultiInteract = true; + cinematic.bSendServerNotify = false; + cinematic.bUseControlledObjectForAudioListener = false; + cinematic.endBehavior = wait; + cinematic.hidePlayerDuringCine = hidePlayer; + cinematic.leadIn = leadIn; + cinematic.leavePlayerLockedWhenFinished = leaveLocked; + cinematic.lockPlayer = unlock; + cinematic.Send(targetEntity->GetSystemAddress()); } void TriggerComponent::HandleToggleBBB(Entity* targetEntity, std::string args) { @@ -366,7 +379,9 @@ void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector(argArray.at(3)).value_or(priority); } - GameMessages::SendPlayFXEffect(targetEntity, effectID.value(), effectType, argArray.at(0), LWOOBJID_EMPTY, priority); + GameMessages::PlayFXEffect fx(targetEntity->GetObjectID(), effectID.value(), effectType, argArray.at(0)); + fx.priority = priority; + fx.Send(UNASSIGNED_SYSTEM_ADDRESS); } void TriggerComponent::HandleCastSkill(Entity* targetEntity, std::string args) { diff --git a/dGame/dGameMessages/CMakeLists.txt b/dGame/dGameMessages/CMakeLists.txt index 1e7e49c1c..0d728669b 100644 --- a/dGame/dGameMessages/CMakeLists.txt +++ b/dGame/dGameMessages/CMakeLists.txt @@ -3,6 +3,7 @@ set(DGAME_DGAMEMESSAGES_SOURCES "BuildingMessages.cpp" "GameMessageDecoder.cpp" "GameMessageHandler.cpp" + "EffectsMessages.cpp" "GameMessages.cpp" "MissionMessages.cpp" "PetMessages.cpp" diff --git a/dGame/dGameMessages/EffectsMessages.cpp b/dGame/dGameMessages/EffectsMessages.cpp new file mode 100644 index 000000000..5fada082c --- /dev/null +++ b/dGame/dGameMessages/EffectsMessages.cpp @@ -0,0 +1,489 @@ +#include "EffectsMessages.h" + +#include "AMFDeserialize.h" +#include "AmfSerialize.h" +#include "BitStreamUtils.h" +#include "CDClientManager.h" +#include "CDEmoteTable.h" +#include "Character.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" +#include "Entity.h" +#include "EntityManager.h" +#include "Game.h" +#include "GeneralUtils.h" +#include "Logger.h" +#include "MissionComponent.h" +#include "NiPoint3.h" +#include "RacingControlComponent.h" +#include "ScriptedActivityComponent.h" +#include "User.h" +#include "UserManager.h" + +#include + +namespace { + // Reads an AMF3 array written with Write. Fails on anything that is not an array. + bool ReadAmfArray(RakNet::BitStream& bitStream, AMFArrayValue& args) { + try { + AMFDeserialize reader; + auto value = reader.Read(bitStream); + if (!value || value->GetValueType() != eAmf::Array) return false; + args = std::move(*static_cast(value.get())); + return true; + } catch (const std::exception&) { + return false; + } + } +} + +namespace GameMessages { + void PlayAnimation::Serialize(RakNet::BitStream& bitStream) const { + const auto animationIDLength = static_cast(GeneralUtils::UTF16ToWTF8(animationID).size()); + bitStream.Write(animationIDLength); + bitStream.Write(LUWString(animationID, animationIDLength)); + bitStream.Write(bExpectAnimToExist); + bitStream.Write(bPlayImmediate); + bitStream.Write(bTriggerOnCompleteMsg); + BitStreamUtils::WriteOptional(bitStream, fPriority, 0.0f); + BitStreamUtils::WriteOptional(bitStream, fScale, 1.0f); + } + + bool PlayAnimation::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, animationID)); + VALIDATE_READ(bitStream.Read(bExpectAnimToExist)); + VALIDATE_READ(bitStream.Read(bPlayImmediate)); + VALIDATE_READ(bitStream.Read(bTriggerOnCompleteMsg)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, fPriority, 0.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, fScale, 1.0f)); + return true; + } + + void PlayNDAudioEmitter::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, NDAudioCallbackMessageData, 0); + BitStreamUtils::WriteOptional(bitStream, NDAudioEmitterID, 0); + BitStreamUtils::WriteLengthPrefixed(bitStream, NDAudioEventGUID); + BitStreamUtils::WriteLengthPrefixed(bitStream, NDAudioMetaEventName); + bitStream.Write(result); + BitStreamUtils::WriteOptional(bitStream, targetObjectIDForNDAudioCallbackMessages, LWOOBJID_EMPTY); + } + + bool PlayNDAudioEmitter::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, NDAudioCallbackMessageData, 0)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, NDAudioEmitterID, 0)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, NDAudioEventGUID)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, NDAudioMetaEventName)); + VALIDATE_READ(bitStream.Read(result)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, targetObjectIDForNDAudioCallbackMessages, LWOOBJID_EMPTY)); + return true; + } + + void PlayEmbeddedEffectOnAllClientsNearObject::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, effectName); + bitStream.Write(fromObjectID); + bitStream.Write(radius); + } + + bool PlayEmbeddedEffectOnAllClientsNearObject::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, effectName)); + VALIDATE_READ(bitStream.Read(fromObjectID)); + VALIDATE_READ(bitStream.Read(radius)); + return true; + } + + void PlayFXEffect::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, effectID, -1); + BitStreamUtils::WriteLengthPrefixed(bitStream, effectType); + BitStreamUtils::WriteOptional(bitStream, scale, 1.0f); + BitStreamUtils::WriteLengthPrefixed(bitStream, name); + BitStreamUtils::WriteOptional(bitStream, priority, 1.0f); + BitStreamUtils::WriteOptional(bitStream, secondary, LWOOBJID_EMPTY); + bitStream.Write(serialize); + } + + bool PlayFXEffect::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, effectID, -1)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, effectType)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, scale, 1.0f)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, name)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, priority, 1.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, secondary, LWOOBJID_EMPTY)); + VALIDATE_READ(bitStream.Read(serialize)); + return true; + } + + void StopFXEffect::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(killImmediate); + BitStreamUtils::WriteLengthPrefixed(bitStream, name); + } + + bool StopFXEffect::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(killImmediate)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, name)); + return true; + } + + void BroadcastTextToChatbox::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, attrs); + bitStream.Write(0x00); // null terminator, always written + BitStreamUtils::WriteLengthPrefixed(bitStream, wsText); + } + + bool BroadcastTextToChatbox::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, attrs)); + uint16_t nullTerminator{}; + VALIDATE_READ(bitStream.Read(nullTerminator)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, wsText)); + return true; + } + + void Play2DAmbientSound::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, audioGUID); + bitStream.Write(result); + } + + bool Play2DAmbientSound::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, audioGUID)); + VALIDATE_READ(bitStream.Read(result)); + return true; + } + + void Stop2DAmbientSound::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(force); + BitStreamUtils::WriteLengthPrefixed(bitStream, audioGUID); + bitStream.Write(result); + } + + bool Stop2DAmbientSound::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(force)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, audioGUID)); + VALIDATE_READ(bitStream.Read(result)); + return true; + } + + void UIMessageServerToSingleClient::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(const_cast(args)); + BitStreamUtils::WriteLengthPrefixed(bitStream, strMessageName); + } + + bool UIMessageServerToSingleClient::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(ReadAmfArray(bitStream, args)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, strMessageName)); + return true; + } + + void UIMessageServerToAllClients::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(const_cast(args)); + BitStreamUtils::WriteLengthPrefixed(bitStream, strMessageName); + } + + bool UIMessageServerToAllClients::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(ReadAmfArray(bitStream, args)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, strMessageName)); + return true; + } + + void StartCelebrationEffect::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, animation); + BitStreamUtils::WriteOptional(bitStream, backgroundObject, 11164); + BitStreamUtils::WriteOptional(bitStream, cameraPathLOT, 12458); + BitStreamUtils::WriteOptional(bitStream, celeLeadIn, 1.0f); + BitStreamUtils::WriteOptional(bitStream, celeLeadOut, 0.8f); + bitStream.Write1(); // DLU always sends celebrationID + bitStream.Write(celebrationID); + bitStream.Write(duration); + bitStream.Write(iconID); + BitStreamUtils::WriteLengthPrefixed(bitStream, mainText); + BitStreamUtils::WriteLengthPrefixed(bitStream, mixerProgram); + BitStreamUtils::WriteLengthPrefixed(bitStream, musicCue); + BitStreamUtils::WriteLengthPrefixed(bitStream, pathNodeName); + BitStreamUtils::WriteLengthPrefixed(bitStream, soundGUID); + BitStreamUtils::WriteLengthPrefixed(bitStream, subText); + } + + bool StartCelebrationEffect::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, animation)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, backgroundObject, 11164)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, cameraPathLOT, 12458)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, celeLeadIn, 1.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, celeLeadOut, 0.8f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, celebrationID, -1)); + VALIDATE_READ(bitStream.Read(duration)); + VALIDATE_READ(bitStream.Read(iconID)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, mainText)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, mixerProgram)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, musicCue)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathNodeName)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, soundGUID)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, subText)); + return true; + } + + void DisplayMessageBox::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bShow); + bitStream.Write(callbackClient); + BitStreamUtils::WriteLengthPrefixed(bitStream, identifier); + bitStream.Write(imageID); + BitStreamUtils::WriteLengthPrefixed(bitStream, text); + BitStreamUtils::WriteLengthPrefixed(bitStream, userData); + } + + bool DisplayMessageBox::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bShow)); + VALIDATE_READ(bitStream.Read(callbackClient)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, identifier)); + VALIDATE_READ(bitStream.Read(imageID)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, text)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, userData)); + return true; + } + + void MessageBoxRespond::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(iButton); + BitStreamUtils::WriteLengthPrefixed(bitStream, identifier); + BitStreamUtils::WriteLengthPrefixed(bitStream, userData); + } + + bool MessageBoxRespond::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(iButton)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, identifier)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, userData)); + return true; + } + + void MessageBoxRespond::Handle(Entity& entityRef, const SystemAddress& sysAddr) { + Entity* entity = &entityRef; + LOG("Button: %d; LOT: %u identifier: %s; userData: %s", iButton, entity->GetLOT(), GeneralUtils::UTF16ToWTF8(identifier).c_str(), GeneralUtils::UTF16ToWTF8(userData).c_str()); + + auto* user = UserManager::Instance()->GetUser(sysAddr); + + if (user == nullptr) { + return; + } + + auto* userEntity = user->GetLastUsedChar()->GetEntity(); + + if (userEntity == nullptr) { + return; + } + + entity->OnMessageBoxResponse(userEntity, iButton, identifier, userData); + + auto* scriptedActivityComponent = entity->GetComponent(); + + if (scriptedActivityComponent != nullptr) { + scriptedActivityComponent->HandleMessageBoxResponse(userEntity, GeneralUtils::UTF16ToWTF8(identifier)); + } + + auto* racingControlComponent = entity->GetComponent(); + + if (racingControlComponent != nullptr) { + racingControlComponent->HandleMessageBoxResponse(userEntity, iButton, GeneralUtils::UTF16ToWTF8(identifier)); + } + + for (auto* shootingGallery : Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY)) { + shootingGallery->OnMessageBoxResponse(userEntity, iButton, identifier, userData); + } + } + + void ChoiceBoxRespond::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, buttonIdentifier); + bitStream.Write(iButton); + BitStreamUtils::WriteLengthPrefixed(bitStream, identifier); + } + + bool ChoiceBoxRespond::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, buttonIdentifier)); + VALIDATE_READ(bitStream.Read(iButton)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, identifier)); + return true; + } + + void ChoiceBoxRespond::Handle(Entity& entityRef, const SystemAddress& sysAddr) { + Entity* entity = &entityRef; + LOG("Button: %d; LOT: %u buttonIdentifier: %s; userData: %s", iButton, entity->GetLOT(), GeneralUtils::UTF16ToWTF8(buttonIdentifier).c_str(), GeneralUtils::UTF16ToWTF8(identifier).c_str()); + + auto* user = UserManager::Instance()->GetUser(sysAddr); + + if (user == nullptr) { + return; + } + + auto* userEntity = user->GetLastUsedChar()->GetEntity(); + + if (userEntity == nullptr) { + return; + } + + entity->OnChoiceBoxResponse(userEntity, iButton, buttonIdentifier, identifier); + } + + void DisplayChatBubble::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, wsText); + } + + bool DisplayChatBubble::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, wsText)); + return true; + } + + void ChangeIdleFlags::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, flagsOff, eAnimationFlags::IDLE_NONE); + BitStreamUtils::WriteOptional(bitStream, flagsOn, eAnimationFlags::IDLE_NONE); + } + + bool ChangeIdleFlags::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, flagsOff, eAnimationFlags::IDLE_NONE)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, flagsOn, eAnimationFlags::IDLE_NONE)); + return true; + } + + void PlayCinematic::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(allowGhostUpdates); + bitStream.Write(bCloseMultiInteract); + bitStream.Write(bSendServerNotify); + bitStream.Write(bUseControlledObjectForAudioListener); + BitStreamUtils::WriteOptional(bitStream, endBehavior, eEndBehavior::RETURN); + bitStream.Write(hidePlayerDuringCine); + BitStreamUtils::WriteOptional(bitStream, leadIn, -1.0f); + bitStream.Write(leavePlayerLockedWhenFinished); + bitStream.Write(lockPlayer); + BitStreamUtils::WriteLengthPrefixed(bitStream, pathName); + bitStream.Write(result); + bitStream.Write(skipIfSamePath); + bitStream.Write(startTimeAdvance); + } + + bool PlayCinematic::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(allowGhostUpdates)); + VALIDATE_READ(bitStream.Read(bCloseMultiInteract)); + VALIDATE_READ(bitStream.Read(bSendServerNotify)); + VALIDATE_READ(bitStream.Read(bUseControlledObjectForAudioListener)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, endBehavior, eEndBehavior::RETURN)); + VALIDATE_READ(bitStream.Read(hidePlayerDuringCine)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, leadIn, -1.0f)); + VALIDATE_READ(bitStream.Read(leavePlayerLockedWhenFinished)); + VALIDATE_READ(bitStream.Read(lockPlayer)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathName)); + VALIDATE_READ(bitStream.Read(result)); + VALIDATE_READ(bitStream.Read(skipIfSamePath)); + VALIDATE_READ(bitStream.Read(startTimeAdvance)); + return true; + } + + void EndCinematic::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, leadOut, -1.0f); + bitStream.Write(leavePlayerLocked); + BitStreamUtils::WriteLengthPrefixed(bitStream, pathName); + } + + bool EndCinematic::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, leadOut, -1.0f)); + VALIDATE_READ(bitStream.Read(leavePlayerLocked)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathName)); + return true; + } + + void CinematicUpdate::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, event, eCinematicEvent::STARTED); + BitStreamUtils::WriteOptional(bitStream, overallTime, -1.0f); + BitStreamUtils::WriteLengthPrefixed(bitStream, pathName); + BitStreamUtils::WriteOptional(bitStream, pathTime, -1.0f); + BitStreamUtils::WriteOptional(bitStream, waypoint, -1); + } + + bool CinematicUpdate::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, event, eCinematicEvent::STARTED)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, overallTime, -1.0f)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathName)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, pathTime, -1.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, waypoint, -1)); + return true; + } + + void CinematicUpdate::Handle(Entity& entity, const SystemAddress& sysAddr) { + std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); + for (Entity* scriptEntity : scriptedActs) { + scriptEntity->OnCinematicUpdate(scriptEntity, &entity, event, pathName, pathTime, overallTime, waypoint); + } + } + + void SlashCommandTextFeedback::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, text); + } + + bool SlashCommandTextFeedback::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, text)); + return true; + } + + void PlayEmote::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(emoteID); + bitStream.Write(targetID); + } + + bool PlayEmote::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(emoteID)); + VALIDATE_READ(bitStream.Read(targetID)); + return true; + } + + void PlayEmote::Handle(Entity& entityRef, const SystemAddress& sysAddr) { + Entity* entity = &entityRef; + LOG_DEBUG("Emote (%i) (%llu)", emoteID, targetID); + + //TODO: If targetID != 0, and we have one of the "perform emote" missions, complete them. + + if (emoteID == 0) return; + std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote + + CDEmoteTableTable* emotes = CDClientManager::GetTable(); + if (emotes) { + CDEmoteTable* emote = emotes->GetEmote(emoteID); + if (emote) sAnimationName = emote->animationName; + } + + GameMessages::EmotePlayed msg; + msg.target = entity->GetObjectID(); + msg.emoteID = emoteID; + msg.targetID = targetID; // The emote’s target entity or 0 if none + msg.Send(UNASSIGNED_SYSTEM_ADDRESS); // Broadcast to all clients + + MissionComponent* missionComponent = entity->GetComponent(); + if (!missionComponent) return; + + if (targetID != LWOOBJID_EMPTY) { + auto* targetEntity = Game::entityManager->GetEntity(targetID); + + LOG_DEBUG("Emote target found (%d)", targetEntity != nullptr); + + if (targetEntity != nullptr) { + targetEntity->OnEmoteReceived(emoteID, entity); + missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, targetID); + } + } else { + LOG_DEBUG("Target ID is empty, using backup"); + const auto scriptedEntities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); + + const auto& referencePoint = entity->GetPosition(); + + for (auto* scripted : scriptedEntities) { + if (Vector3::DistanceSquared(scripted->GetPosition(), referencePoint) > 5.0f * 5.0f) continue; + + scripted->OnEmoteReceived(emoteID, entity); + missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID()); + } + } + } + + void SetEmoteLockState::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bLock); + bitStream.Write(emoteID); + } + + bool SetEmoteLockState::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bLock)); + VALIDATE_READ(bitStream.Read(emoteID)); + return true; + } +} diff --git a/dGame/dGameMessages/EffectsMessages.h b/dGame/dGameMessages/EffectsMessages.h new file mode 100644 index 000000000..518603524 --- /dev/null +++ b/dGame/dGameMessages/EffectsMessages.h @@ -0,0 +1,327 @@ +#ifndef EFFECTSMESSAGES_H +#define EFFECTSMESSAGES_H + +#include "GameMessages.h" +#include "Amf3.h" +#include "eAnimationFlags.h" +#include "eCinematicEvent.h" +#include "eEndBehavior.h" + +#include + +// Game messages for effects, audio, animations, emotes, cinematics and UI text (message boxes, chat bubbles, +// billboards, UI messages, slash command feedback). +// Field names follow the client (legouniverse.exe 1.10.64); fields are listed in wire order. +namespace GameMessages { + // Server -> client, broadcast. + struct PlayAnimation : public NetGameMsg { + PlayAnimation() : NetGameMsg(MessageType::Game::PLAY_ANIMATION) {} + PlayAnimation(const LWOOBJID _target, const std::u16string& _animationID) : PlayAnimation() { + target = _target; + animationID = _animationID; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + // Written as a u32 length followed by that many UTF-16 characters, where the length is the size of the + // name converted to UTF-8 (so a non-ASCII name is padded with null characters). This is what DLU has + // always sent. + std::u16string animationID{}; + bool bExpectAnimToExist{ true }; + bool bPlayImmediate{}; + bool bTriggerOnCompleteMsg{}; + float fPriority{ 0.0f }; // optional + float fScale{ 1.0f }; // optional + }; + + // Server -> client, broadcast. + struct PlayNDAudioEmitter : public NetGameMsg { + PlayNDAudioEmitter() : NetGameMsg(MessageType::Game::PLAY_ND_AUDIO_EMITTER) {} + PlayNDAudioEmitter(const LWOOBJID _target, const std::string& _NDAudioEventGUID) : PlayNDAudioEmitter() { + target = _target; + NDAudioEventGUID = _NDAudioEventGUID; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + LWOOBJID NDAudioCallbackMessageData{}; // optional + uint32_t NDAudioEmitterID{}; // optional + std::string NDAudioEventGUID{}; + std::string NDAudioMetaEventName{}; + bool result{}; + LWOOBJID targetObjectIDForNDAudioCallbackMessages{ LWOOBJID_EMPTY }; // optional + }; + + // Server -> client, broadcast. + struct PlayEmbeddedEffectOnAllClientsNearObject : public NetGameMsg { + PlayEmbeddedEffectOnAllClientsNearObject() : NetGameMsg(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string effectName{}; + LWOOBJID fromObjectID{}; + float radius{}; + }; + + // Server -> client, broadcast. + struct PlayFXEffect : public NetGameMsg { + PlayFXEffect() : NetGameMsg(MessageType::Game::PLAY_FX_EFFECT) {} + PlayFXEffect(const LWOOBJID _target, const int32_t _effectID, const std::u16string& _effectType, const std::string& _name) : PlayFXEffect() { + target = _target; + effectID = _effectID; + effectType = _effectType; + name = _name; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int32_t effectID{ -1 }; // optional + std::u16string effectType{}; + float scale{ 1.0f }; // optional + std::string name{}; + float priority{ 1.0f }; // optional + LWOOBJID secondary{ LWOOBJID_EMPTY }; // optional + bool serialize{ true }; + }; + + // Server -> client, broadcast. + struct StopFXEffect : public NetGameMsg { + StopFXEffect() : NetGameMsg(MessageType::Game::STOP_FX_EFFECT) {} + StopFXEffect(const LWOOBJID _target, const bool _killImmediate, const std::string& _name) : StopFXEffect() { + target = _target; + killImmediate = _killImmediate; + name = _name; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool killImmediate{}; + std::string name{}; + }; + + // Server -> client, broadcast. + struct BroadcastTextToChatbox : public NetGameMsg { + BroadcastTextToChatbox() : NetGameMsg(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + // Name value text: u32 length, the characters, then a null character that DLU always writes (even when empty). + std::u16string attrs{}; + std::u16string wsText{}; + }; + + // Server -> client. + struct Play2DAmbientSound : public NetGameMsg { + Play2DAmbientSound() : NetGameMsg(MessageType::Game::PLAY2_D_AMBIENT_SOUND) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::string audioGUID{}; + bool result{}; + }; + + // Server -> client. + struct Stop2DAmbientSound : public NetGameMsg { + Stop2DAmbientSound() : NetGameMsg(MessageType::Game::STOP2_D_AMBIENT_SOUND) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool force{}; + std::string audioGUID{}; + bool result{}; + }; + + // Server -> client. + struct UIMessageServerToSingleClient : public NetGameMsg { + UIMessageServerToSingleClient() : NetGameMsg(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + AMFArrayValue args{}; + std::string strMessageName{}; + }; + + // Server -> client. Broadcast, or sent to one client (DLU uses it to reach a client that may not have an + // entity yet; the target is then LWOOBJID_EMPTY). + struct UIMessageServerToAllClients : public NetGameMsg { + UIMessageServerToAllClients() : NetGameMsg(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + AMFArrayValue args{}; + std::string strMessageName{}; + }; + + // Server -> client. + struct StartCelebrationEffect : public NetGameMsg { + StartCelebrationEffect() : NetGameMsg(MessageType::Game::START_CELEBRATION_EFFECT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string animation{}; + LOT backgroundObject{ 11164 }; // optional + LOT cameraPathLOT{ 12458 }; // optional + float celeLeadIn{ 1.0f }; // optional + float celeLeadOut{ 0.8f }; // optional + int32_t celebrationID{ -1 }; // optional; DLU always writes it, even when it has the default value + float duration{}; + uint32_t iconID{}; + std::u16string mainText{}; + std::string mixerProgram{}; + std::string musicCue{}; + std::string pathNodeName{}; + std::string soundGUID{}; + std::u16string subText{}; + }; + + // Server -> client. + struct DisplayMessageBox : public NetGameMsg { + DisplayMessageBox() : NetGameMsg(MessageType::Game::DISPLAY_MESSAGE_BOX) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bShow{}; + LWOOBJID callbackClient{}; + std::u16string identifier{}; + int32_t imageID{}; + std::u16string text{}; + std::u16string userData{}; + }; + + // Client -> server. Sent to the callbackClient of a DisplayMessageBox when the player presses a button. + struct MessageBoxRespond : public NetGameMsg { + MessageBoxRespond() : NetGameMsg(MessageType::Game::MESSAGE_BOX_RESPOND) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + int32_t iButton{}; + std::u16string identifier{}; + std::u16string userData{}; + }; + + // Client -> server. + struct ChoiceBoxRespond : public NetGameMsg { + ChoiceBoxRespond() : NetGameMsg(MessageType::Game::CHOICE_BOX_RESPOND) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + std::u16string buttonIdentifier{}; + int32_t iButton{}; + std::u16string identifier{}; + }; + + // Server -> client. + struct DisplayChatBubble : public NetGameMsg { + DisplayChatBubble() : NetGameMsg(MessageType::Game::DISPLAY_CHAT_BUBBLE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string wsText{}; + }; + + // Server -> client, broadcast. + struct ChangeIdleFlags : public NetGameMsg { + ChangeIdleFlags() : NetGameMsg(MessageType::Game::CHANGE_IDLE_FLAGS) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + eAnimationFlags flagsOff{ eAnimationFlags::IDLE_NONE }; // optional + eAnimationFlags flagsOn{ eAnimationFlags::IDLE_NONE }; // optional + }; + + // Server -> client. The client's message has two bools (overrideDefault, state), but the client never reads + // them, so DLU sends no payload; the message only turns the name billboard off. + struct SetNameBillboardState : public NetGameMsg { + SetNameBillboardState() : NetGameMsg(MessageType::Game::SET_NAME_BILLBOARD_STATE) {} + }; + + // Server -> client. No payload. + struct ShowBillboardInteractIcon : public NetGameMsg { + ShowBillboardInteractIcon() : NetGameMsg(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON) {} + }; + + // Server -> client. + struct PlayCinematic : public NetGameMsg { + PlayCinematic() : NetGameMsg(MessageType::Game::PLAY_CINEMATIC) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool allowGhostUpdates{ true }; + bool bCloseMultiInteract{ true }; + bool bSendServerNotify{}; + bool bUseControlledObjectForAudioListener{}; + eEndBehavior endBehavior{ eEndBehavior::RETURN }; // optional + bool hidePlayerDuringCine{}; + float leadIn{ -1.0f }; // optional + bool leavePlayerLockedWhenFinished{}; + bool lockPlayer{ true }; + std::u16string pathName{}; + bool result{}; + bool skipIfSamePath{}; + float startTimeAdvance{}; + }; + + // Server -> client. + struct EndCinematic : public NetGameMsg { + EndCinematic() : NetGameMsg(MessageType::Game::END_CINEMATIC) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + float leadOut{ -1.0f }; // optional + bool leavePlayerLocked{}; + std::u16string pathName{}; + }; + + // Client -> server. + struct CinematicUpdate : public NetGameMsg { + CinematicUpdate() : NetGameMsg(MessageType::Game::CINEMATIC_UPDATE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + eCinematicEvent event{ eCinematicEvent::STARTED }; // optional + float overallTime{ -1.0f }; // optional + std::u16string pathName{}; + float pathTime{ -1.0f }; // optional + int32_t waypoint{ -1 }; // optional + }; + + // Server -> client. + struct SlashCommandTextFeedback : public NetGameMsg { + SlashCommandTextFeedback() : NetGameMsg(MessageType::Game::SLASH_COMMAND_TEXT_FEEDBACK) {} + SlashCommandTextFeedback(const LWOOBJID _target, const std::u16string& _text) : SlashCommandTextFeedback() { + target = _target; + text = _text; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string text{}; + }; + + // Both directions: the client asks to play an emote (handled here), and the server tells clients an object + // plays one. + struct PlayEmote : public NetGameMsg { + PlayEmote() : NetGameMsg(MessageType::Game::PLAY_EMOTE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + int32_t emoteID{}; + LWOOBJID targetID{}; + }; + + // Server -> client. + struct SetEmoteLockState : public NetGameMsg { + SetEmoteLockState() : NetGameMsg(MessageType::Game::SET_EMOTE_LOCK_STATE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bLock{}; + int32_t emoteID{}; + }; +}; + +#endif // EFFECTSMESSAGES_H diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 3ea3c64e2..3fe8a82d3 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -35,6 +35,7 @@ #include "BuildingMessages.h" #include "RacingMessages.h" #include "MissionMessages.h" +#include "EffectsMessages.h" #include "PetMessages.h" #include "PropertyMessages.h" #include "eMissionTaskType.h" @@ -76,6 +77,12 @@ namespace { { SET_FLAG, []() { return std::make_unique(); } }, { HAS_BEEN_COLLECTED, []() { return std::make_unique(); } }, + // Effects, emotes, cinematics, UI + { PLAY_EMOTE, []() { return std::make_unique(); } }, + { MESSAGE_BOX_RESPOND, []() { return std::make_unique(); } }, + { CHOICE_BOX_RESPOND, []() { return std::make_unique(); } }, + { CINEMATIC_UPDATE, []() { return std::make_unique(); } }, + // Pets { PET_TAMING_TRY_BUILD, []() { return std::make_unique(); } }, { NOTIFY_TAMING_BUILD_SUCCESS, []() { return std::make_unique(); } }, @@ -166,11 +173,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System switch (messageID) { - case MessageType::Game::PLAY_EMOTE: { - GameMessages::HandlePlayEmote(inStream, entity); - break; - } - case MessageType::Game::MOVE_ITEM_IN_INVENTORY: { GameMessages::HandleMoveItemInInventory(inStream, entity); break; @@ -287,7 +289,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System || !entity->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return; entity->AddCallbackTimer(0.5f, [entity, sysAddr]() { if (!entity) return; - GameMessages::SendEndCinematic(entity->GetObjectID(), u"", sysAddr); + GameMessages::EndCinematic endCinematic; + endCinematic.target = entity->GetObjectID(); + endCinematic.Send(sysAddr); }); break; } @@ -520,14 +524,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System GameMessages::HandleClientTradeUpdate(inStream, entity, sysAddr); break; - case MessageType::Game::MESSAGE_BOX_RESPOND: - GameMessages::HandleMessageBoxResponse(inStream, entity, sysAddr); - break; - - case MessageType::Game::CHOICE_BOX_RESPOND: - GameMessages::HandleChoiceBoxRespond(inStream, entity, sysAddr); - break; - // Racing: most racing messages are registered in g_MessageHandlers case MessageType::Game::ACKNOWLEDGE_POSSESSION: GameMessages::HandleAcknowledgePossession(inStream, entity, sysAddr); @@ -575,10 +571,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System GameMessages::HandlePlayerRailArrivedNotification(inStream, entity, sysAddr); break; - case MessageType::Game::CINEMATIC_UPDATE: - GameMessages::HandleCinematicUpdate(inStream, entity, sysAddr); - break; - case MessageType::Game::MODIFY_PLAYER_ZONE_STATISTIC: GameMessages::HandleModifyPlayerZoneStatistic(inStream, entity); break; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 90feea390..8b930a1a1 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -1,4 +1,5 @@ #include "GameMessages.h" +#include "EffectsMessages.h" #include "DashboardNotify.h" #include "PlayerReports.h" #include "EconomyLedger.h" @@ -162,43 +163,6 @@ void GameMessages::SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, c SEND_PACKET; } -void GameMessages::SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority, float fScale) { - if (!entity) { - LOG("Trying to play animation, but entity var is nullptr!"); - return; - } - - //Stolen from the old DLU codebase as the new one's autogenerated code doesn't work properly for animationIDs longer than 6 characters. - CBITSTREAM; - CMSGHEADER; - std::string sAnimationID = GeneralUtils::UTF16ToWTF8(animationName); - - uint32_t animationIDLength = sAnimationID.size(); - bool bExpectAnimToExist = true; - bool bPlayImmediate = false; - bool bTriggerOnCompleteMsg = false; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLAY_ANIMATION); - - bitStream.Write(animationIDLength); - bitStream.Write(LUWString(animationName, animationIDLength)); - - bitStream.Write(bExpectAnimToExist); - - bitStream.Write(bPlayImmediate); - - bitStream.Write(bTriggerOnCompleteMsg); - - bitStream.Write(fPriority != 0.0f); - if (fPriority != 0.0f) bitStream.Write(fPriority); - - bitStream.Write(fScale != 1.0f); - if (fScale != 1.0f) bitStream.Write(fScale); - - SEND_PACKET_BROADCAST; -} - void GameMessages::SendPlayerReady(Entity* entity, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -283,28 +247,6 @@ void GameMessages::SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, cons SEND_PACKET; } -void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLAY_ND_AUDIO_EMITTER); - bitStream.Write0(); // callback message data {lwoobjid} - bitStream.Write0(); // audio emitterid {uint32_t} - - uint32_t length = audioGUID.size(); - bitStream.Write(length); - for (uint32_t k = 0; k < length; k++) { - bitStream.Write(audioGUID[k]); - } - - bitStream.Write(0); // size of NDAudioMetaEventName (then print the string like the guid) - bitStream.Write0(); // result {bool} - bitStream.Write0(); // m_TargetObjectIDForNDAudioCallbackMessages {lwoobjid} - - SEND_PACKET_BROADCAST; -} - void GameMessages::SendStartPathing(Entity* entity) { CBITSTREAM; CMSGHEADER; @@ -491,153 +433,6 @@ void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysA SEND_PACKET; } -void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFBaseValue& args) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT); - - bitStream.Write(args); - uint32_t strMessageNameLength = message.size(); - bitStream.Write(strMessageNameLength); - - for (uint32_t k = 0; k < strMessageNameLength; k++) { - bitStream.Write(message[k]); - } - - SEND_PACKET; -} - -void GameMessages::SendUIMessageServerToSingleClient(const std::string& message, AMFBaseValue& args, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - LWOOBJID empty = 0; - bitStream.Write(empty); - bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); // This is intentional to allow the server to send a ui message to a client via their system address. - - bitStream.Write(args); - uint32_t strMessageNameLength = message.size(); - bitStream.Write(strMessageNameLength); - - for (uint32_t k = 0; k < strMessageNameLength; k++) { - bitStream.Write(message[k]); - } - - SEND_PACKET; -} - -void GameMessages::SendUIMessageServerToAllClients(const std::string& message, AMFBaseValue& args) { - CBITSTREAM; - CMSGHEADER; - - LWOOBJID empty = 0; - bitStream.Write(empty); - bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); - - bitStream.Write(args); - uint32_t strMessageNameLength = message.size(); - bitStream.Write(strMessageNameLength); - - for (uint32_t k = 0; k < strMessageNameLength; k++) { - bitStream.Write(message[k]); - } - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT); - - bitStream.Write(effectName.length()); - for (uint32_t k = 0; k < effectName.length(); k++) { - bitStream.Write(effectName[k]); - } - bitStream.Write(fromObjectID); - bitStream.Write(radius); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) { - SendPlayFXEffect(entity->GetObjectID(), effectID, effectType, name, secondary, priority, scale, serialize); -} - -void GameMessages::SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity); - bitStream.Write(MessageType::Game::PLAY_FX_EFFECT); - - bitStream.Write(effectID != -1); - if (effectID != -1) bitStream.Write(effectID); - - bitStream.Write(effectType.size()); - for (const auto& k : effectType) { - bitStream.Write(k); - } - - bitStream.Write(scale != 1.0f); - if (scale != 1.0f) bitStream.Write(scale); - - bitStream.Write(name.size()); - for (const auto& k : name) { - bitStream.Write(k); - } - - bitStream.Write(priority != 1.0); - if (priority != 1.0) bitStream.Write(priority); - - bitStream.Write(secondary != LWOOBJID_EMPTY); - if (secondary != LWOOBJID_EMPTY) bitStream.Write(secondary); - - bitStream.Write(serialize); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendStopFXEffect(Entity* entity, bool killImmediate, std::string name) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::STOP_FX_EFFECT); - - bitStream.Write(killImmediate); - bitStream.Write(name.size()); - bitStream.Write(name.c_str(), name.size()); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendBroadcastTextToChatbox(Entity* entity, const SystemAddress& sysAddr, const std::u16string& attrs, const std::u16string& wsText) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX); - - bitStream.Write(attrs.size()); - for (uint32_t i = 0; i < attrs.size(); ++i) { - bitStream.Write(attrs[i]); - } - bitStream.Write(0x00); // Null Terminator - - uint32_t wsTextLength = wsText.size(); - bitStream.Write(wsTextLength); - for (uint32_t k = 0; k < wsTextLength; k++) { - bitStream.Write(wsText[k]); - } - - SEND_PACKET_BROADCAST; -} - void GameMessages::SendSetCurrency(Entity* entity, int64_t currency, int lootType, const LWOOBJID& sourceID, const LOT& sourceLOT, int sourceTradeID, bool overrideCurrent, eLootSourceType sourceType) { CBITSTREAM; CMSGHEADER; @@ -792,19 +587,6 @@ void GameMessages::SendSetInventorySize(Entity* entity, int invType, int size) { SEND_PACKET; } -void GameMessages::SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SET_EMOTE_LOCK_STATE); - bitStream.Write(bLock); - bitStream.Write(emoteID); - - SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - void GameMessages::SendSetJetPackMode(Entity* entity, bool use, bool bypassChecks, bool doHover, int effectID, float airspeed, float maxAirspeed, float verticalVelocity, int warningEffectID) { /* historical jamesster jetpack values if (bIsJamessterPhysics) { @@ -880,47 +662,6 @@ void GameMessages::SendResurrect(Entity* entity) { SEND_PACKET_BROADCAST; } -void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::STOP2_D_AMBIENT_SOUND); - - uint32_t audioGUIDSize = audioGUID.size(); - - bitStream.Write(force); - bitStream.Write(audioGUIDSize); - - for (uint32_t k = 0; k < audioGUIDSize; k++) { - bitStream.Write(audioGUID[k]); - } - - bitStream.Write(result); - - SystemAddress sysAddr = entity->GetSystemAddress(); - - SEND_PACKET; -} - -void GameMessages::SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLAY2_D_AMBIENT_SOUND); - uint32_t audioGUIDSize = audioGUID.size(); - - bitStream.Write(audioGUIDSize); - for (uint32_t k = 0; k < audioGUIDSize; k++) { - bitStream.Write(audioGUID[k]); - } - bitStream.Write(result); - - SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data) { CBITSTREAM; CMSGHEADER; @@ -1424,33 +1165,6 @@ void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream& inStream, entity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); } -void GameMessages::SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::START_CELEBRATION_EFFECT); - - bitStream.Write(0); //animation - bitStream.Write0(); //No custom bg obj - bitStream.Write0(); //custom path - bitStream.Write0(); //leadin - bitStream.Write0(); //leadout - bitStream.Write1(); - bitStream.Write(celebrationID); - bitStream.Write(0.0f); //duration - bitStream.Write(0); //icon - bitStream.Write(0); //text - bitStream.Write(0); //mixer - bitStream.Write(0); //cue - bitStream.Write(0); //pathnodename - bitStream.Write(0); //soundguid - bitStream.Write(0); //subtext - - SEND_PACKET; -} - - void GameMessages::SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, uint32_t pathStart, const SystemAddress& sysAddr, int32_t railActivatorComponentID, LWOOBJID railActivatorObjectID) { @@ -1696,114 +1410,6 @@ void GameMessages::HandleSetConsumableItem(RakNet::BitStream& inStream, Entity* inventory->SetConsumable(lot); } -void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, - bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, - eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, - bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::PLAY_CINEMATIC); - - bitStream.Write(allowGhostUpdates); - bitStream.Write(bCloseMultiInteract); - bitStream.Write(bSendServerNotify); - bitStream.Write(bUseControlledObjectForAudioListener); - - bitStream.Write(endBehavior != eEndBehavior::RETURN); - if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior); - - bitStream.Write(hidePlayerDuringCine); - - bitStream.Write(leadIn != -1); - if (leadIn != -1) bitStream.Write(leadIn); - - bitStream.Write(leavePlayerLockedWhenFinished); - bitStream.Write(lockPlayer); - - bitStream.Write(pathName.size()); - for (char16_t c : pathName) { - bitStream.Write(c); - } - - bitStream.Write(result); - - bitStream.Write(skipIfSamePath); - - bitStream.Write(startTimeAdvance); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendEndCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, - float leadOut, bool leavePlayerLocked) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::END_CINEMATIC); - - bitStream.Write(leadOut != -1); - if (leadOut != -1) bitStream.Write(leadOut); - - bitStream.Write(leavePlayerLocked); - - bitStream.Write(pathName.size()); - for (uint32_t i = 0; i < pathName.size(); i++) { - bitStream.Write(pathName[i]); - } - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::HandleCinematicUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - eCinematicEvent event; - if (!inStream.ReadBit()) { - event = eCinematicEvent::STARTED; - } else { - inStream.Read(event); - } - - float_t overallTime; - if (!inStream.ReadBit()) { - overallTime = -1.0f; - } else { - inStream.Read(overallTime); - } - - uint32_t pathNameLength; - inStream.Read(pathNameLength); - - std::u16string pathName; - for (size_t i = 0; i < pathNameLength; i++) { - char16_t character; - inStream.Read(character); - pathName.push_back(character); - } - - float_t pathTime; - if (!inStream.ReadBit()) { - pathTime = -1.0f; - } else { - inStream.Read(pathTime); - } - - int32_t waypoint; - if (!inStream.ReadBit()) { - waypoint = -1; - } else { - inStream.Read(waypoint); - } - - std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); - for (Entity* scriptEntity : scriptedActs) { - scriptEntity->OnCinematicUpdate(scriptEntity, entity, event, pathName, pathTime, overallTime, waypoint); - } -} - void GameMessages::SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator, bool bCantAttack, bool bCantEquip, bool bCantInteract, bool bCantJump, bool bCantMove, bool bCantTurn, @@ -2296,20 +1902,6 @@ void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive SEND_PACKET; } -void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::PLAY_EMOTE); - - bitStream.Write(emoteID); - bitStream.Write(target); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - void GameMessages::SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId) { CBITSTREAM; CMSGHEADER; @@ -2325,106 +1917,6 @@ void GameMessages::SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeI SEND_PACKET_BROADCAST; } -void GameMessages::HandleMessageBoxResponse(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - int32_t iButton; - uint32_t identifierLength; - std::u16string identifier; - uint32_t userDataLength; - std::u16string userData; - - inStream.Read(iButton); - - inStream.Read(identifierLength); - if (identifierLength > MAX_MESSAGE_LENGTH) return; - for (size_t i = 0; i < identifierLength; i++) { - char16_t character; - inStream.Read(character); - identifier.push_back(character); - } - - inStream.Read(userDataLength); - if (userDataLength > MAX_MESSAGE_LENGTH) return; - for (size_t i = 0; i < userDataLength; i++) { - char16_t character; - inStream.Read(character); - userData.push_back(character); - } - - LOG("Button: %d; LOT: %u identifier: %s; userData: %s", iButton, entity->GetLOT(), GeneralUtils::UTF16ToWTF8(identifier).c_str(), GeneralUtils::UTF16ToWTF8(userData).c_str()); - - auto* user = UserManager::Instance()->GetUser(sysAddr); - - if (user == nullptr) { - return; - } - - auto* userEntity = user->GetLastUsedChar()->GetEntity(); - - if (userEntity == nullptr) { - return; - } - - entity->OnMessageBoxResponse(userEntity, iButton, identifier, userData); - - auto* scriptedActivityComponent = entity->GetComponent(); - - if (scriptedActivityComponent != nullptr) { - scriptedActivityComponent->HandleMessageBoxResponse(userEntity, GeneralUtils::UTF16ToWTF8(identifier)); - } - - auto* racingControlComponent = entity->GetComponent(); - - if (racingControlComponent != nullptr) { - racingControlComponent->HandleMessageBoxResponse(userEntity, iButton, GeneralUtils::UTF16ToWTF8(identifier)); - } - - for (auto* shootingGallery : Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY)) { - shootingGallery->OnMessageBoxResponse(userEntity, iButton, identifier, userData); - } -} - -void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - int32_t iButton; - uint32_t buttonIdentifierLength; - std::u16string buttonIdentifier; - uint32_t identifierLength; - std::u16string identifier; - - inStream.Read(buttonIdentifierLength); - if (buttonIdentifierLength > MAX_MESSAGE_LENGTH) return; - for (size_t i = 0; i < buttonIdentifierLength; i++) { - char16_t character; - inStream.Read(character); - buttonIdentifier.push_back(character); - } - - inStream.Read(iButton); - - inStream.Read(identifierLength); - if (identifierLength > MAX_MESSAGE_LENGTH) return; - for (size_t i = 0; i < identifierLength; i++) { - char16_t character; - inStream.Read(character); - identifier.push_back(character); - } - - LOG("Button: %d; LOT: %u buttonIdentifier: %s; userData: %s", iButton, entity->GetLOT(), GeneralUtils::UTF16ToWTF8(buttonIdentifier).c_str(), GeneralUtils::UTF16ToWTF8(identifier).c_str()); - - auto* user = UserManager::Instance()->GetUser(sysAddr); - - if (user == nullptr) { - return; - } - - auto* userEntity = user->GetLastUsedChar()->GetEntity(); - - if (userEntity == nullptr) { - return; - } - - entity->OnChoiceBoxResponse(userEntity, iButton, buttonIdentifier, identifier); -} - void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) { CBITSTREAM; CMSGHEADER; @@ -2458,68 +1950,6 @@ void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeS SEND_PACKET; } -void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::DISPLAY_MESSAGE_BOX); - - bitStream.Write(bShow); - bitStream.Write(callbackClient); - - bitStream.Write(identifier.size()); - for (const auto character : identifier) { - bitStream.Write(character); - } - - bitStream.Write(imageID); - - bitStream.Write(text.size()); - for (const auto character : text) { - bitStream.Write(character); - } - - bitStream.Write(userData.size()); - for (const auto character : userData) { - bitStream.Write(character); - } - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr) { - // MessageType::Game::DISPLAY_CHAT_BUBBLE - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::DISPLAY_CHAT_BUBBLE); - - bitStream.Write(text.size()); - for (const auto character : text) { - bitStream.Write(character); - } - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - - -void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::CHANGE_IDLE_FLAGS); - bitStream.Write(flagsOff != eAnimationFlags::IDLE_NONE); - if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); - bitStream.Write(flagsOn != eAnimationFlags::IDLE_NONE); - if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn); - - SEND_PACKET_BROADCAST; -} // Mounts void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) { @@ -3143,59 +2573,6 @@ void GameMessages::HandleQuickBuildCancel(RakNet::BitStream& inStream, Entity* e quickBuildComponent->CancelQuickBuild(Game::entityManager->GetEntity(userID), eQuickBuildFailReason::CANCELED_EARLY); } -void GameMessages::HandlePlayEmote(RakNet::BitStream& inStream, Entity* entity) { - int32_t emoteID; - LWOOBJID targetID; - - inStream.Read(emoteID); - inStream.Read(targetID); - - LOG_DEBUG("Emote (%i) (%llu)", emoteID, targetID); - - //TODO: If targetID != 0, and we have one of the "perform emote" missions, complete them. - - if (emoteID == 0) return; - std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote - - CDEmoteTableTable* emotes = CDClientManager::GetTable(); - if (emotes) { - CDEmoteTable* emote = emotes->GetEmote(emoteID); - if (emote) sAnimationName = emote->animationName; - } - - GameMessages::EmotePlayed msg; - msg.target = entity->GetObjectID(); - msg.emoteID = emoteID; - msg.targetID = targetID; // The emote’s target entity or 0 if none - msg.Send(UNASSIGNED_SYSTEM_ADDRESS); // Broadcast to all clients - - MissionComponent* missionComponent = entity->GetComponent(); - if (!missionComponent) return; - - if (targetID != LWOOBJID_EMPTY) { - auto* targetEntity = Game::entityManager->GetEntity(targetID); - - LOG_DEBUG("Emote target found (%d)", targetEntity != nullptr); - - if (targetEntity != nullptr) { - targetEntity->OnEmoteReceived(emoteID, entity); - missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, targetID); - } - } else { - LOG_DEBUG("Target ID is empty, using backup"); - const auto scriptedEntities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); - - const auto& referencePoint = entity->GetPosition(); - - for (auto* scripted : scriptedEntities) { - if (Vector3::DistanceSquared(scripted->GetPosition(), referencePoint) > 5.0f * 5.0f) continue; - - scripted->OnEmoteReceived(emoteID, entity); - missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID()); - } - } -} - void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& inStream, Entity* entity) { auto* levelComp = entity->GetComponent(); if (!levelComp) return; @@ -3218,7 +2595,7 @@ void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& } //Play the level up effect: - GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(entity->GetObjectID(), 7074, u"create", "7074").Send(UNASSIGNED_SYSTEM_ADDRESS); //Send a notification in chat: std::stringstream wss; @@ -3232,7 +2609,11 @@ void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& std::u16string attrs = GeneralUtils::UTF8ToUTF16(wss.str()); std::u16string wsText = u"UI_LEVEL_PROGRESSION_LEVELUP_MESSAGE"; - GameMessages::SendBroadcastTextToChatbox(entity, UNASSIGNED_SYSTEM_ADDRESS, attrs, wsText); + GameMessages::BroadcastTextToChatbox chatboxText; + chatboxText.target = entity->GetObjectID(); + chatboxText.attrs = attrs; + chatboxText.wsText = wsText; + chatboxText.Send(UNASSIGNED_SYSTEM_ADDRESS); } void GameMessages::HandlePickupCurrency(RakNet::BitStream& inStream, Entity* entity) { @@ -3809,35 +3190,6 @@ void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream& inStream, Entit entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target); }; -void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::SET_NAME_BILLBOARD_STATE); - - // Technically these bits would be written, however the client does not - // contain a deserialize method to actually deserialize, so we are leaving it out. - // As such this GM only turns the billboard off. - - // bitStream.Write(overrideDefault); - // bitStream.Write(state); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST - else SEND_PACKET -} - -void GameMessages::SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST - else SEND_PACKET -} - void GameMessages::HandleAddDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t count = 1; bool hasCount = false; @@ -3937,18 +3289,6 @@ void GameMessages::HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Ent characterComponent->SetCurrentInteracting(LWOOBJID_EMPTY); } -void GameMessages::SendSlashCommandFeedbackText(Entity* entity, std::u16string text) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SLASH_COMMAND_TEXT_FEEDBACK); - bitStream.Write(text.size()); - bitStream.Write(text); - auto sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - void GameMessages::HandleUpdateInventoryGroup(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { std::string action; std::u16string groupName; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 22d52fb95..798909a29 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -127,7 +127,6 @@ namespace GameMessages { 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); - void SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority = 0.0f, float fScale = 1.0f); void SendPlayerReady(Entity* entity, const SystemAddress& sysAddr); void SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptRespawn, const SystemAddress& systemAddress); void SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer); @@ -135,8 +134,6 @@ namespace GameMessages { void SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, bool bAllowCyclingWhileDeadOnly = true, eCyclingMode cyclingMode = eCyclingMode::ALLOW_CYCLE_TEAMMATES); - void SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID); - void SendStartPathing(Entity* entity); // special is for the FV tree platform, feature is complete if we just do that so meh @@ -153,17 +150,7 @@ namespace GameMessages { void SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectWorldState state, const SystemAddress& sysAddr); void SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType); - void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFBaseValue& args); - // Specify sysAddr if you need to send a flash message to a client who you dont know the objectID of. - void SendUIMessageServerToSingleClient(const std::string& message, AMFBaseValue& args, const SystemAddress& sysAddr); - void SendUIMessageServerToAllClients(const std::string& message, AMFBaseValue& args); - - void SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius); - void SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority = 1, float scale = 1, bool serialize = true); - void SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary = LWOOBJID_EMPTY, float priority = 1, float scale = 1, bool serialize = true); - void SendStopFXEffect(Entity* entity, bool killImmediate, std::string name); - void SendBroadcastTextToChatbox(Entity* entity, const SystemAddress& sysAddr, const std::u16string& attrs, const std::u16string& wsText); void SendSetCurrency(Entity* entity, int64_t currency, int lootType, const LWOOBJID& sourceID, const LOT& sourceLOT, int sourceTradeID, bool overrideCurrent, eLootSourceType sourceType); void SendQuickBuildNotifyState(Entity* entity, eQuickBuildState prevState, eQuickBuildState state, const LWOOBJID& playerID); @@ -178,11 +165,8 @@ namespace GameMessages { void SendSetGravityScale(const LWOOBJID& target, const float effectScale, const SystemAddress& sysAddr); - void SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID); void SendSetJetPackMode(Entity* entity, bool use, bool bypassChecks = false, bool doHover = false, int effectID = -1, float airspeed = 10, float maxAirspeed = 15, float verticalVelocity = 1, int warningEffectID = -1); void SendResurrect(Entity* entity); - void SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result = false); - void SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result = false); void SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data); void SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme); @@ -203,8 +187,6 @@ namespace GameMessages { void SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response); void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type); - void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID); - // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.SetResurrectRestoreValues.html void SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore); @@ -260,15 +242,6 @@ namespace GameMessages { void HandleSetConsumableItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, - bool allowGhostUpdates = true, bool bCloseMultiInteract = true, bool bSendServerNotify = false, bool bUseControlledObjectForAudioListener = false, - eEndBehavior endBehavior = eEndBehavior::RETURN, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, - bool lockPlayer = true, bool result = false, bool skipIfSamePath = false, float startTimeAdvance = 0); - - void SendEndCinematic(LWOOBJID objectID, std::u16string pathName, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, - float leadOut = -1.0f, bool leavePlayerLocked = false); - void HandleCinematicUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator = LWOOBJID_EMPTY, bool bCantAttack = false, bool bCantEquip = false, bool bCantInteract = false, bool bCantJump = false, bool bCantMove = false, bool bCantTurn = false, @@ -343,30 +316,11 @@ namespace GameMessages { //Pets: void SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, eUnequippableActiveType iType, LWOOBJID itemID, const SystemAddress& sysAddr); - void SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr); - - void HandleMessageBoxResponse(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - void HandleChoiceBoxRespond(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap = false, bool isZoneStart = false, LWOOBJID sender = LWOOBJID_EMPTY); //UI: void SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeSlotsNeeded, eInventoryType inventoryType, const SystemAddress& sysAddr); - void SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr); - - void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr); - - /** - * @brief - * - * @param objectId ID of the entity to set idle flags - * @param FlagsOn Flag to turn on - * @param FlagsOff Flag to turn off - */ - void SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr); - // Mounts /** * @brief Set the Inventory LWOOBJID of the mount @@ -445,8 +399,6 @@ namespace GameMessages { void HandleToggleGhostReferenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSetGhostReferencePosition(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId); - void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId); void HandleBuyFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSellToVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleBuybackFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); @@ -456,7 +408,6 @@ namespace GameMessages { void HandleFireEventServerSide(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleRequestPlatformResync(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleQuickBuildCancel(RakNet::BitStream& inStream, Entity* entity); - void HandlePlayEmote(RakNet::BitStream& inStream, Entity* entity); void HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& inStream, Entity* entity); void HandlePickupCurrency(RakNet::BitStream& inStream, Entity* entity); void HandleRequestDie(RakNet::BitStream& inStream, Entity* entity); @@ -501,8 +452,6 @@ namespace GameMessages { void HandleConfirmDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity); void HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity); - void SendSlashCommandFeedbackText(Entity* entity, std::u16string text); - void HandleUpdateInventoryGroup(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleUpdateInventoryGroupContents(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID); diff --git a/dGame/dGameMessages/MissionMessages.cpp b/dGame/dGameMessages/MissionMessages.cpp index 410c2d2f5..f4cf041b0 100644 --- a/dGame/dGameMessages/MissionMessages.cpp +++ b/dGame/dGameMessages/MissionMessages.cpp @@ -15,6 +15,7 @@ #include "Mission.h" #include "MissionComponent.h" #include "MissionOfferComponent.h" +#include "EffectsMessages.h" namespace GameMessages { void OfferMission::Serialize(RakNet::BitStream& bitStream) const { @@ -150,7 +151,9 @@ namespace GameMessages { || !player->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return; player->AddCallbackTimer(0.5f, [player]() { if (!player) return; - GameMessages::SendEndCinematic(player->GetObjectID(), u"", player->GetSystemAddress()); + GameMessages::EndCinematic endCinematic; + endCinematic.target = player->GetObjectID(); + endCinematic.Send(player->GetSystemAddress()); }); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.cpp b/dGame/dPropertyBehaviors/ControlBehaviors.cpp index 0b180979d..d7c00b934 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviors.cpp @@ -4,6 +4,7 @@ #include "Entity.h" #include "Game.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ModelComponent.h" #include "ObjectIDManager.h" #include "Logger.h" @@ -46,7 +47,11 @@ void ControlBehaviors::RequestUpdatedID(ControlBehaviorContext& context) { args.Insert("behaviorID", std::to_string(persistentIdBig)); args.Insert("objectID", std::to_string(context.modelComponent->GetParent()->GetObjectID())); - GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorID", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = context.modelOwner->GetObjectID(); + uiMessage.strMessageName = "UpdateBehaviorID"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(context.modelOwner->GetSystemAddress()); context.modelComponent->UpdatePendingBehaviorId(persistentIdBig, oldBehaviorID); ControlBehaviors::Instance().SendBehaviorListToClient(context); @@ -58,7 +63,11 @@ void ControlBehaviors::SendBehaviorListToClient(const ControlBehaviorContext& co AMFArrayValue behaviorsToSerialize; context.modelComponent->SendBehaviorListToClient(behaviorsToSerialize); - GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorList", behaviorsToSerialize); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = context.modelOwner->GetObjectID(); + uiMessage.strMessageName = "UpdateBehaviorList"; + uiMessage.args = std::move(behaviorsToSerialize); + uiMessage.SendToClient(context.modelOwner->GetSystemAddress()); } // TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet @@ -69,7 +78,11 @@ void ControlBehaviors::SendBehaviorBlocksToClient(ControlBehaviorContext& contex context.modelComponent->VerifyBehaviors(); AMFArrayValue behavior; context.modelComponent->SendBehaviorBlocksToClient(behaviorMsg.GetBehaviorId(), behavior); - GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorBlocks", behavior); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = context.modelOwner->GetObjectID(); + uiMessage.strMessageName = "UpdateBehaviorBlocks"; + uiMessage.args = std::move(behavior); + uiMessage.SendToClient(context.modelOwner->GetSystemAddress()); } void ControlBehaviors::UpdateAction(const AMFArrayValue& arguments) { @@ -156,7 +169,11 @@ void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayV if (!isRemove) { AMFArrayValue args; args.Insert("BehaviorID", std::to_string(msg.GetBehaviorId())); - GameMessages::SendUIMessageServerToSingleClient(modelOwner, characterComponent->GetSystemAddress(), "BehaviorRemoved", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = modelOwner->GetObjectID(); + uiMessage.strMessageName = "BehaviorRemoved"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(characterComponent->GetSystemAddress()); } SendBehaviorListToClient(context); diff --git a/dGame/dUtilities/DashboardActions.cpp b/dGame/dUtilities/DashboardActions.cpp index 3dbb05969..8e66532a1 100644 --- a/dGame/dUtilities/DashboardActions.cpp +++ b/dGame/dUtilities/DashboardActions.cpp @@ -11,6 +11,7 @@ #include "CharacterComponent.h" #include "ChatPackets.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "PlayerManager.h" #include "User.h" #include "UserManager.h" @@ -70,7 +71,7 @@ namespace { GameMessages::ToggleGMInvisEvent msg; msg.Send(entity->GetObjectID()); } - GameMessages::SendSlashCommandFeedbackText(entity, u"Your game master level has been changed."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Your game master level has been changed.").SendToClient(entity->GetSystemAddress()); LOG("Dashboard lowered GM level of %s to %i", user->GetUsername().c_str(), static_cast(info->maxGmLevel)); } return static_cast(users.size()); @@ -96,7 +97,11 @@ namespace { AMFArrayValue args; args.Insert("title", std::string("Warning from a moderator")); args.Insert("message", text); - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "ToggleAnnounce", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = player->GetObjectID(); + uiMessage.strMessageName = "ToggleAnnounce"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(player->GetSystemAddress()); ChatPackets::SendSystemMessage(player->GetSystemAddress(), u"Warning from a moderator: " + GeneralUtils::UTF8ToUTF16(text)); affected++; } diff --git a/dGame/dUtilities/DashboardNotify.cpp b/dGame/dUtilities/DashboardNotify.cpp index 408e17f68..19475c295 100644 --- a/dGame/dUtilities/DashboardNotify.cpp +++ b/dGame/dUtilities/DashboardNotify.cpp @@ -16,6 +16,7 @@ #include "Character.h" #include "dZoneManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ChatPackets.h" #include "Amf3.h" #include "GeneralUtils.h" @@ -87,7 +88,10 @@ namespace DashboardNotify { AMFArrayValue args; args.Insert("title", title); args.Insert("message", message); - GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleAnnounce"; + uiMessage.args = std::move(args); + uiMessage.Send(UNASSIGNED_SYSTEM_ADDRESS); // Also in chat, for anyone who closes the popup without reading it const auto text = GeneralUtils::UTF8ToUTF16(ChatLine(title, message)); for (const auto* player : PlayerManager::GetAllPlayers()) { diff --git a/dGame/dUtilities/LiveEvents.cpp b/dGame/dUtilities/LiveEvents.cpp index 0a75d6b3d..0f9b047bd 100644 --- a/dGame/dUtilities/LiveEvents.cpp +++ b/dGame/dUtilities/LiveEvents.cpp @@ -27,6 +27,7 @@ #include "InventoryComponent.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ChatPackets.h" #include "DashboardNotify.h" #include "CDClientManager.h" @@ -218,7 +219,7 @@ namespace { const auto itemCount = std::clamp(event.config.value("itemCount", 1u), 1, 999); if (auto* inventory = player->GetComponent(); inventory && item > 0) inventory->AddItem(item, itemCount, eLootSourceType::ACTIVITY); if (const auto effect = event.config.value("foundEffectId", 0); effect > 0) { - GameMessages::SendPlayFXEffect(player->GetObjectID(), effect, GeneralUtils::UTF8ToUTF16(event.config.value("foundEffectType", std::string{})), "live_event_found"); + GameMessages::PlayFXEffect(player->GetObjectID(), effect, GeneralUtils::UTF8ToUTF16(event.config.value("foundEffectType", std::string{})), "live_event_found").Send(UNASSIGNED_SYSTEM_ADDRESS); } const auto left = std::ranges::count_if(event.treasures, [](const Treasure& t) { return !t.gone; }); TellAll(PlayerName(player) + " found a treasure! " + (left == 0 ? "That was the last one." : std::to_string(left) + " left to find.")); @@ -353,7 +354,7 @@ namespace { if (effect <= 0) return; const auto name = "live_event_" + std::to_string(event.row.id); for (auto* player : PlayerManager::GetAllPlayers()) { - if (player) GameMessages::SendPlayFXEffect(player->GetObjectID(), effect, type, name); + if (player) GameMessages::PlayFXEffect(player->GetObjectID(), effect, type, name).Send(UNASSIGNED_SYSTEM_ADDRESS); } event.bursts++; event.dirty = true; @@ -458,7 +459,7 @@ namespace { event.alive.clear(); if (event.type == eEventType::CELEBRATION) { const auto name = "live_event_" + std::to_string(event.row.id); - for (auto* player : PlayerManager::GetAllPlayers()) if (player) GameMessages::SendStopFXEffect(player, true, name); + for (auto* player : PlayerManager::GetAllPlayers()) if (player) GameMessages::StopFXEffect(player->GetObjectID(), true, name).Send(UNASSIGNED_SYSTEM_ADDRESS); } FlushScores(event); WriteStatus(event, true); diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 14b13761f..58859a592 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -31,6 +31,7 @@ #include "PlayerManager.h" #include "User.h" #include "eObjectBits.h" +#include "EffectsMessages.h" namespace { // Each command once, by the first alias it got @@ -259,7 +260,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity* } if (!error.empty()) { - GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(error)); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), GeneralUtils::ASCIIToUTF16(error)).SendToClient(entity->GetSystemAddress()); } } @@ -290,7 +291,7 @@ void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const st if (page < 1 || page > totalPages) { feedback << "Invalid page number. Total pages: " << totalPages; - GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedback.str())); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), GeneralUtils::ASCIIToUTF16(feedback.str())).SendToClient(entity->GetSystemAddress()); return; } @@ -305,7 +306,7 @@ void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const st const auto feedbackStr = feedback.str(); if (!feedbackStr.empty()) { - GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr)); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), GeneralUtils::ASCIIToUTF16(feedbackStr)).SendToClient(entity->GetSystemAddress()); } return; } @@ -328,7 +329,7 @@ void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const st const auto feedbackStr = feedback.str(); if (!feedbackStr.empty()) { - GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr)); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), GeneralUtils::ASCIIToUTF16(feedbackStr)).SendToClient(entity->GetSystemAddress()); } } @@ -338,7 +339,10 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std:: args.Insert("title", title); args.Insert("message", message); - GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleAnnounce"; + uiMessage.args = std::move(args); + uiMessage.Send(UNASSIGNED_SYSTEM_ADDRESS); //Notify chat about it ChatPackets::Announcement announcement; diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp index 8d325953b..5a1b67049 100644 --- a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -57,6 +57,7 @@ #include "ePlayerFlag.h" #include "StringifiedEnum.h" #include "BinaryPathFinder.h" +#include "EffectsMessages.h" namespace DEVGMCommands { void SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -64,7 +65,7 @@ namespace DEVGMCommands { const auto level_intermed = GeneralUtils::TryParse(args); if (!level_intermed) { - GameMessages::SendSlashCommandFeedbackText(entity, u"Invalid GM level."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Invalid GM level.").SendToClient(entity->GetSystemAddress()); return; } eGameMasterLevel level = static_cast(level_intermed.value()); @@ -106,7 +107,7 @@ namespace DEVGMCommands { 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."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Your game master level has been changed, you may not be able to use all commands.").SendToClient(entity->GetSystemAddress()); } #endif } @@ -118,10 +119,10 @@ namespace DEVGMCommands { auto* character = entity->GetCharacter(); if (character && character->GetBillboardVisible()) { character->SetBillboardVisible(false); - GameMessages::SendSlashCommandFeedbackText(entity, u"Your nameplate has been turned off and is not visible to players currently in this zone."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Your nameplate has been turned off and is not visible to players currently in this zone.").SendToClient(entity->GetSystemAddress()); } else { character->SetBillboardVisible(true); - GameMessages::SendSlashCommandFeedbackText(entity, u"Your nameplate is now on and visible to all players."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Your nameplate is now on and visible to all players.").SendToClient(entity->GetSystemAddress()); } } @@ -132,9 +133,9 @@ namespace DEVGMCommands { bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS); character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current); if (!current) { - GameMessages::SendSlashCommandFeedbackText(entity, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now.").SendToClient(entity->GetSystemAddress()); } else { - GameMessages::SendSlashCommandFeedbackText(entity, u"Cinematics will no longer be skipped."); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Cinematics will no longer be skipped.").SendToClient(entity->GetSystemAddress()); } } @@ -327,7 +328,11 @@ namespace DEVGMCommands { uiState.Insert("state", splitArgs[0]); - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "pushGameState", uiState); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(uiState); + uiMessage.SendToClient(sysAddr); ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); } @@ -340,7 +345,11 @@ namespace DEVGMCommands { amfArgs.Insert("visible", true); - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, splitArgs[0], amfArgs); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = splitArgs[0]; + uiMessage.args = std::move(amfArgs); + uiMessage.SendToClient(sysAddr); ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); } @@ -499,14 +508,14 @@ namespace DEVGMCommands { if (!effectID) return; // FIXME: use fallible ASCIIToUTF16 conversion, because non-ascii isn't valid anyway - GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID.value(), GeneralUtils::ASCIIToUTF16(splitArgs.at(1)), splitArgs.at(2)); + GameMessages::PlayFXEffect(entity->GetObjectID(), effectID.value(), GeneralUtils::ASCIIToUTF16(splitArgs.at(1)), splitArgs.at(2)).Send(UNASSIGNED_SYSTEM_ADDRESS); } void StopEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { const auto splitArgs = GeneralUtils::SplitString(args, ' '); if (splitArgs.empty()) return; - GameMessages::SendStopFXEffect(entity, true, splitArgs[0]); + GameMessages::StopFXEffect(entity->GetObjectID(), true, splitArgs[0]).Send(UNASSIGNED_SYSTEM_ADDRESS); } void SetAnnTitle(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -739,7 +748,10 @@ namespace DEVGMCommands { return; } - GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration.value()); + GameMessages::StartCelebrationEffect celebrationEffect; + celebrationEffect.target = entity->GetObjectID(); + celebrationEffect.celebrationID = celebration.value(); + celebrationEffect.SendToClient(entity->GetSystemAddress()); } void BuffMed(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -807,7 +819,10 @@ namespace DEVGMCommands { for (const auto& [name, lot] : nameToLot) { auto& entry = nameSort.PushDebug(name) = std::to_string(lot); } - GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, sysAddr); + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleObjectDebugger"; + uiMessage.args = std::move(response); + uiMessage.SendToClient(sysAddr); } } @@ -1021,11 +1036,11 @@ namespace DEVGMCommands { } void PlayLvlFx(Entity* entity, const SystemAddress& sysAddr, const std::string args) { - GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(entity->GetObjectID(), 7074, u"create", "7074").Send(UNASSIGNED_SYSTEM_ADDRESS); } void PlayRebuildFx(Entity* entity, const SystemAddress& sysAddr, const std::string args) { - GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(entity->GetObjectID(), 230, u"rebuild", "230").Send(UNASSIGNED_SYSTEM_ADDRESS); } void FreeMoney(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -1354,7 +1369,10 @@ namespace DEVGMCommands { processInfo.PushDebug("Peak RSS") = std::to_string(static_cast(Metrics::GetPeakRSS()) / 1.024e6) + "MB"; processInfo.PushDebug("Current RSS") = std::to_string(static_cast(Metrics::GetCurrentRSS()) / 1.024e6) + "MB"; processInfo.PushDebug("Process ID") = Metrics::GetProcessID(); - GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, sysAddr); + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleObjectDebugger"; + uiMessage.args = std::move(response); + uiMessage.SendToClient(sysAddr); } void ReloadConfig(Entity* entity, const SystemAddress& sysAddr, const std::string args) { diff --git a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp index 9754ade79..e2d47184c 100644 --- a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp @@ -21,6 +21,7 @@ #include "MessageType/Chat.h" #include "eServerDisconnectIdentifiers.h" #include "eObjectBits.h" +#include "EffectsMessages.h" namespace GMGreaterThanZeroCommands { @@ -288,7 +289,7 @@ namespace GMGreaterThanZeroCommands { void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if (args.empty()) { - GameMessages::SendSlashCommandFeedbackText(entity, u"No player Given"); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"No player Given").SendToClient(entity->GetSystemAddress()); return; } @@ -306,10 +307,10 @@ namespace GMGreaterThanZeroCommands { auto player = PlayerManager::GetPlayer(args); if (!player) { - GameMessages::SendSlashCommandFeedbackText(entity, u"Player not found"); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Player not found").SendToClient(entity->GetSystemAddress()); return; } - GameMessages::SendSlashCommandFeedbackText(entity, u"Spectating Player"); + GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Spectating Player").SendToClient(entity->GetSystemAddress()); GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, player->GetObjectID()); } } diff --git a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp index bb5291d3f..92b189960 100644 --- a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp @@ -23,6 +23,7 @@ // Emuns #include "eGameMasterLevel.h" +#include "EffectsMessages.h" namespace GMZeroCommands { void Pvp(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -101,7 +102,11 @@ namespace GMZeroCommands { args.Insert("state", "Story"); - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(entity->GetSystemAddress()); } entity->AddCallbackTimer(0.5f, [customText, entity]() { @@ -112,7 +117,11 @@ namespace GMZeroCommands { LOG("Sending %s", customText.c_str()); - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "ToggleStoryBox"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(entity->GetSystemAddress()); }); } @@ -124,7 +133,11 @@ namespace GMZeroCommands { args.Insert("state", "Story"); - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(entity->GetSystemAddress()); } entity->AddCallbackTimer(0.5f, [customText, entity]() { @@ -135,7 +148,11 @@ namespace GMZeroCommands { LOG("Sending %s", customText.c_str()); - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "ToggleStoryBox"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(entity->GetSystemAddress()); }); } diff --git a/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp b/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp index 0908bbdca..f9f96bf65 100644 --- a/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp +++ b/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp @@ -1,5 +1,6 @@ #include "DLUVanityTeleportingObject.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "dServer.h" #include "VanityUtilities.h" #include "RenderComponent.h" @@ -17,14 +18,14 @@ void DLUVanityTeleportingObject::OnStartup(Entity* self) { void DLUVanityTeleportingObject::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "setupTeleport") { RenderComponent::PlayAnimation(self, u"interact"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); + GameMessages::PlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("teleport", 2.0f); self->AddTimer("stopFX", 2.0f); } else if (timerName == "stopFX") { - GameMessages::SendStopFXEffect(self, true, "teleportBeam"); - GameMessages::SendStopFXEffect(self, true, "teleportRings"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "teleportBeam").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::StopFXEffect(self->GetObjectID(), true, "teleportRings").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "teleport") { std::vector& locations = m_Object->m_Locations[Game::server->GetZoneID()]; @@ -37,8 +38,8 @@ void DLUVanityTeleportingObject::OnTimerDone(Entity* self, std::string timerName self->SetPosition(newLocation.m_Position); self->SetRotation(newLocation.m_Rotation); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); + GameMessages::PlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("stopFX", 2.0f); self->AddTimer("setupTeleport", m_TeleportInterval); } diff --git a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp index 1e772d66e..188098e80 100644 --- a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp +++ b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp @@ -12,6 +12,7 @@ #include "BaseCombatAIComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "SkillComponent.h" #include "eReplicaComponentType.h" #include "RenderComponent.h" @@ -527,7 +528,12 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim } } - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake-bridge", self->GetObjectID(), 100.0f); + GameMessages::PlayEmbeddedEffectOnAllClientsNearObject embeddedEffect; + embeddedEffect.target = self->GetObjectID(); + embeddedEffect.effectName = u"camshake-bridge"; + embeddedEffect.fromObjectID = self->GetObjectID(); + embeddedEffect.radius = 100.0f; + embeddedEffect.Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "AdvanceComplete") { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 11, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp index 5fbbda20b..eb384ec27 100644 --- a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -3,6 +3,7 @@ #include "DestroyableComponent.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "SkillComponent.h" #include "BaseCombatAIComponent.h" #include "EntityInfo.h" @@ -36,7 +37,7 @@ void AmDarklingDragon::OnDie(Entity* self, Entity* killer) { } void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { - GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"gothit", "").Send(UNASSIGNED_SYSTEM_ADDRESS); if (true) { auto weakpoint = self->GetVar(u"weakspot"); @@ -70,7 +71,11 @@ void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t } self->SetVar(u"weakpoint", 2); - GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = self->GetObjectID(); + idleFlags.flagsOn = eAnimationFlags::IDLE_NONE; + idleFlags.flagsOff = eAnimationFlags::IDLE_COMBAT; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); float animationTime = RenderComponent::PlayAnimation(self, u"stunstart", 1.7f); self->AddTimer("timeToStunLoop", 1.0f); @@ -134,7 +139,11 @@ void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { skillComponent->Interrupt(); skillComponent->Reset(); } - GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = self->GetObjectID(); + idleFlags.flagsOn = eAnimationFlags::IDLE_COMBAT; + idleFlags.flagsOff = eAnimationFlags::IDLE_NONE; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"weakspot", -1); GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp index 2ddc63099..88eb57a9c 100644 --- a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -6,6 +6,7 @@ #include "eAnimationFlags.h" #include "EntityInfo.h" #include "RenderComponent.h" +#include "EffectsMessages.h" void FvMaelstromDragon::OnStartup(Entity* self) { self->SetVar(u"weakspot", 0); @@ -49,7 +50,7 @@ void FvMaelstromDragon::OnDie(Entity* self, Entity* killer) { } void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { - GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"gothit", "").Send(UNASSIGNED_SYSTEM_ADDRESS); if (true) { auto weakpoint = self->GetVar(u"weakspot"); @@ -86,7 +87,11 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ self->SetVar(u"weakpoint", 2); - GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = self->GetObjectID(); + idleFlags.flagsOn = eAnimationFlags::IDLE_NONE; + idleFlags.flagsOff = eAnimationFlags::IDLE_COMBAT; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(self, u"stunstart", 1.7f); self->AddTimer("timeToStunLoop", 1.0f); @@ -152,7 +157,11 @@ void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) { skillComponent->Interrupt(); skillComponent->Reset(); } - GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = self->GetObjectID(); + idleFlags.flagsOn = eAnimationFlags::IDLE_COMBAT; + idleFlags.flagsOff = eAnimationFlags::IDLE_NONE; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"weakspot", -1); GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp index 26948c571..8c38cbceb 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -2,6 +2,7 @@ #include "BaseCombatAIComponent.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "EntityInfo.h" #include "SkillComponent.h" @@ -40,7 +41,11 @@ void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) { skillComponent->Reset(); } RenderComponent::PlayAnimation(self, u"disable", 1.7f); - GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = self->GetObjectID(); + idleFlags.flagsOn = eAnimationFlags::IDLE_NONE; + idleFlags.flagsOff = eAnimationFlags::IDLE_COMBAT; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); const auto reviveTime = self->GetVar(u"reviveTime") != 0.0f ? self->GetVar(u"reviveTime") : 12.0f; self->AddTimer("reviveTime", reviveTime); @@ -57,7 +62,11 @@ void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) { destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); } Game::entityManager->SerializeEntity(self); - GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeIdleFlags idleFlags; + idleFlags.target = self->GetObjectID(); + idleFlags.flagsOn = eAnimationFlags::IDLE_COMBAT; + idleFlags.flagsOff = eAnimationFlags::IDLE_NONE; + idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"timesStunned", timesStunned + 1); StunApe(self, false); diff --git a/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp b/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp index a928e9d96..2ccd6738f 100644 --- a/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp +++ b/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp @@ -1,10 +1,14 @@ #include "NpcEpsilonServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" void NpcEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { //If we are completing the Nexus Force join mission, play the celebration for it: if (missionID == 1851) { - GameMessages::SendStartCelebrationEffect(target, target->GetSystemAddress(), 22); + GameMessages::StartCelebrationEffect celebration; + celebration.target = target->GetObjectID(); + celebration.celebrationID = 22; + celebration.SendToClient(target->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp index da0b65d72..55bc315e8 100644 --- a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp +++ b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityInfo.h" #include "MovementAIComponent.h" #include "BaseCombatAIComponent.h" @@ -62,7 +63,7 @@ void AmShieldGenerator::OnTimerDone(Entity* self, std::string timerName) { self->AddTimer("BuffPlayers", 3.0f); } else if (timerName == "PlayFX") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn"); + GameMessages::PlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("PlayFX", 1.5f); } else if (timerName == "RefreshEnemies") { diff --git a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp index 029322959..9fa606dca 100644 --- a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp +++ b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MovementAIComponent.h" #include "BaseCombatAIComponent.h" #include "SkillComponent.h" @@ -82,7 +83,7 @@ void AmShieldGeneratorQuickbuild::OnTimerDone(Entity* self, std::string timerNam self->AddTimer("BuffPlayers", 3.0f); } else if (timerName == "PlayFX") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn"); + GameMessages::PlayFXEffect(self->GetObjectID(), 5351, u"generatorOn", "generatorOn").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("PlayFX", 1.5f); } else if (timerName == "RefreshEnemies") { diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp index 93b876cf8..bf0eb6f7e 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp @@ -1,5 +1,6 @@ #include "AmSkullkinDrill.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MovingPlatformComponent.h" #include "DestroyableComponent.h" #include "ProximityMonitorComponent.h" @@ -12,7 +13,7 @@ void AmSkullkinDrill::OnStartup(Entity* self) { self->SetNetworkVar(u"bIsInUse", false); self->SetVar(u"bActive", true); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"spin", "active"); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"spin", "active").Send(UNASSIGNED_SYSTEM_ADDRESS); auto* movingPlatformComponent = self->GetComponent(); @@ -135,8 +136,8 @@ void AmSkullkinDrill::OnUse(Entity* self, Entity* user) { self->SetNetworkVar(u"bIsInUse", true); - GameMessages::SendPlayFXEffect(user->GetObjectID(), 5499, u"on-anim", "tornado"); - GameMessages::SendPlayFXEffect(user->GetObjectID(), 5502, u"on-anim", "staff"); + GameMessages::PlayFXEffect(user->GetObjectID(), 5499, u"on-anim", "tornado").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(user->GetObjectID(), 5502, u"on-anim", "staff").Send(UNASSIGNED_SYSTEM_ADDRESS); const auto userID = user->GetObjectID(); @@ -174,8 +175,8 @@ void AmSkullkinDrill::OnArrived(Entity* self, uint32_t waypointIndex) { if (waypointIndex == 1) { RenderComponent::PlayAnimation(self, u"no-spin"); - GameMessages::SendStopFXEffect(self, true, "active"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"indicator", "indicator"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "active").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"indicator", "indicator").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"bActive", false); @@ -194,8 +195,8 @@ void AmSkullkinDrill::OnArrived(Entity* self, uint32_t waypointIndex) { return; } else { RenderComponent::PlayAnimation(self, u"idle"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"spin", "active"); - GameMessages::SendStopFXEffect(self, true, "indicator"); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"spin", "active").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::StopFXEffect(self->GetObjectID(), true, "indicator").Send(UNASSIGNED_SYSTEM_ADDRESS); } } @@ -212,7 +213,10 @@ void AmSkullkinDrill::PlayCinematic(Entity* self) { return; } - GameMessages::SendPlayCinematic(player->GetObjectID(), cine, player->GetSystemAddress()); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = cine; + cinematic.Send(player->GetSystemAddress()); } void AmSkullkinDrill::PlayAnim(Entity* self, Entity* player, const std::string& animName) { @@ -259,7 +263,7 @@ void AmSkullkinDrill::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t auto* standObj = GetStandObj(self); if (standObj != nullptr) { - GameMessages::SendPlayFXEffect(standObj->GetObjectID(), 4946, u"explode", "explode"); + GameMessages::PlayFXEffect(standObj->GetObjectID(), 4946, u"explode", "explode").Send(UNASSIGNED_SYSTEM_ADDRESS); } } @@ -320,8 +324,8 @@ void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) { self->SetVar(u"userID", LWOOBJID_EMPTY); - GameMessages::SendStopFXEffect(player, true, "tornado"); - GameMessages::SendStopFXEffect(player, true, "staff"); + GameMessages::StopFXEffect(player->GetObjectID(), true, "tornado").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::StopFXEffect(player->GetObjectID(), true, "staff").Send(UNASSIGNED_SYSTEM_ADDRESS); } } else if (data[0] == "TryUnFreezeAgain") { diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp index 5493dc24d..f1919ac9d 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinDrillStand.cpp @@ -1,5 +1,6 @@ #include "AmSkullkinDrillStand.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "dpEntity.h" #include "Entity.h" #include "RenderComponent.h" @@ -31,7 +32,7 @@ void AmSkullkinDrillStand::OnProximityUpdate(Entity* self, Entity* entering, std GameMessages::SendKnockback(entering->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, newVec); - GameMessages::SendPlayFXEffect(entering->GetObjectID(), 1378, u"create", "pushBack"); + GameMessages::PlayFXEffect(entering->GetObjectID(), 1378, u"create", "pushBack").Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(entering, u"knockback-recovery"); } diff --git a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp index db235f8e3..8c35de312 100644 --- a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp +++ b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp @@ -3,6 +3,7 @@ #include "dZoneManager.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionComponent.h" #include "eMissionState.h" #include "InventoryComponent.h" @@ -62,8 +63,8 @@ void ImgBrickConsoleQB::OnUse(Entity* self, Entity* user) { const auto& facility = Game::entityManager->GetEntitiesInGroup("FacilityPipes"); if (!facility.empty()) { - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeEnergy"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), onFX, u"create", location + "PipeOn"); + GameMessages::StopFXEffect(facility[0]->GetObjectID(), true, location + "PipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(facility[0]->GetObjectID(), onFX, u"create", location + "PipeOn").Send(UNASSIGNED_SYSTEM_ADDRESS); } } @@ -108,8 +109,8 @@ void ImgBrickConsoleQB::SpawnBrick(Entity* self) { void ImgBrickConsoleQB::SmashCanister(Entity* self) { const auto brick = Game::entityManager->GetEntitiesInGroup("Imagination"); if (!brick.empty()) { - GameMessages::SendPlayFXEffect(brick[0]->GetObjectID(), 122, u"create", "bluebrick"); - GameMessages::SendPlayFXEffect(brick[0]->GetObjectID(), 1034, u"cast", "imaginationexplosion"); + GameMessages::PlayFXEffect(brick[0]->GetObjectID(), 122, u"create", "bluebrick").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(brick[0]->GetObjectID(), 1034, u"cast", "imaginationexplosion").Send(UNASSIGNED_SYSTEM_ADDRESS); } const auto canisters = Game::entityManager->GetEntitiesInGroup("Canister"); @@ -138,8 +139,8 @@ void ImgBrickConsoleQB::OnQuickBuildComplete(Entity* self, Entity* target) { const auto& facility = Game::entityManager->GetEntitiesInGroup("FacilityPipes"); if (!facility.empty()) { - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeOff"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), energyFX, u"create", location + "PipeEnergy"); + GameMessages::StopFXEffect(facility[0]->GetObjectID(), true, location + "PipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(facility[0]->GetObjectID(), energyFX, u"create", location + "PipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); } const auto consoles = Game::entityManager->GetEntitiesInGroup("Console"); @@ -182,10 +183,10 @@ void ImgBrickConsoleQB::OnDie(Entity* self, Entity* killer) { const auto& facility = Game::entityManager->GetEntitiesInGroup("FacilityPipes"); if (!facility.empty()) { - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeEnergy"); - GameMessages::SendStopFXEffect(facility[0], true, location + "PipeOn"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), offFX, u"create", location + "PipeOff"); - GameMessages::SendPlayFXEffect(facility[0]->GetObjectID(), 2750, u"create", location + "imagination_canister"); + GameMessages::StopFXEffect(facility[0]->GetObjectID(), true, location + "PipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::StopFXEffect(facility[0]->GetObjectID(), true, location + "PipeOn").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(facility[0]->GetObjectID(), offFX, u"create", location + "PipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(facility[0]->GetObjectID(), 2750, u"create", location + "imagination_canister").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp b/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp index 48d1b2553..2866f7c8e 100644 --- a/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp +++ b/dScripts/02_server/Map/FV/Racing/RaceMaelstromGeiser.cpp @@ -1,5 +1,6 @@ #include "RaceMaelstromGeiser.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "PossessableComponent.h" #include "PossessorComponent.h" #include "EntityManager.h" @@ -68,7 +69,7 @@ void RaceMaelstromGeiser::OnProximityUpdate(Entity* self, Entity* entering, std: void RaceMaelstromGeiser::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "downTime") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 4048, u"rebuild_medium", "geiser", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 4048, u"rebuild_medium", "geiser").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("buildUpTime", 1); } else if (timerName == "buildUpTime") { @@ -76,7 +77,7 @@ void RaceMaelstromGeiser::OnTimerDone(Entity* self, std::string timerName) { self->AddTimer("killTime", 1.5f); } else if (timerName == "killTime") { - GameMessages::SendStopFXEffect(self, true, "geiser"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "geiser").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"AmFiring", false); diff --git a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp index f0f3099b1..759d8817e 100644 --- a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp +++ b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp @@ -1,5 +1,6 @@ #include "GfCaptainsCannon.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "RenderComponent.h" @@ -32,7 +33,7 @@ void GfCaptainsCannon::OnUse(Entity* self, Entity* user) { RenderComponent::PlayAnimation(user, u"cannon-strike-no-equip"); - GameMessages::SendPlayFXEffect(user->GetObjectID(), 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(user->GetObjectID(), 6039, u"hook", "hook").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("FireCannon", 1.667f); } @@ -52,7 +53,10 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "FireCannon") { float cinematicTime = 6.3f; - GameMessages::SendPlayCinematic(playerId, u"Cannon_Cam", player->GetSystemAddress()); + GameMessages::PlayCinematic cinematic; + cinematic.target = playerId; + cinematic.pathName = u"Cannon_Cam"; + cinematic.Send(player->GetSystemAddress()); self->AddTimer("cinematicTimer", cinematicTime); @@ -64,7 +68,10 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { RenderComponent::PlayAnimation(shark, u"cannon"); } - GameMessages::SendPlay2DAmbientSound(player, "{7457d85c-4537-4317-ac9d-2f549219ea87}"); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = "{7457d85c-4537-4317-ac9d-2f549219ea87}"; + ambientSound.SendToClient(player->GetSystemAddress()); } else if (timerName == "cinematicTimer") { GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true @@ -73,7 +80,7 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { self->SetVar(u"bIsInUse", false); self->SetNetworkVar(u"bIsInUse", false); - GameMessages::SendStopFXEffect(player, true, "hook"); + GameMessages::StopFXEffect(player->GetObjectID(), true, "hook").Send(UNASSIGNED_SYSTEM_ADDRESS); auto* missionComponent = player->GetComponent(); diff --git a/dScripts/02_server/Map/GF/MastTeleport.cpp b/dScripts/02_server/Map/GF/MastTeleport.cpp index f2adc80fd..7c1633846 100644 --- a/dScripts/02_server/Map/GF/MastTeleport.cpp +++ b/dScripts/02_server/Map/GF/MastTeleport.cpp @@ -1,6 +1,7 @@ #include "MastTeleport.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Preconditions.h" #include "eEndBehavior.h" #include "DestroyableComponent.h" @@ -49,12 +50,20 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { const auto leanIn = self->GetVar(u"LeanIn"); if (!cinematic.empty()) { - GameMessages::SendPlayCinematic(playerId, GeneralUtils::ASCIIToUTF16(cinematic), player->GetSystemAddress(), - true, true, false, false, eEndBehavior::RETURN, false, leanIn - ); + GameMessages::PlayCinematic playCinematic; + playCinematic.target = playerId; + playCinematic.pathName = GeneralUtils::ASCIIToUTF16(cinematic); + playCinematic.allowGhostUpdates = true; + playCinematic.bCloseMultiInteract = true; + playCinematic.bSendServerNotify = false; + playCinematic.bUseControlledObjectForAudioListener = false; + playCinematic.endBehavior = eEndBehavior::RETURN; + playCinematic.hidePlayerDuringCine = false; + playCinematic.leadIn = leanIn; + playCinematic.Send(player->GetSystemAddress()); } - GameMessages::SendPlayFXEffect(playerId, 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(playerId, 6039, u"hook", "hook").Send(UNASSIGNED_SYSTEM_ADDRESS); float animationTime = 6.25f; animationTime = RenderComponent::PlayAnimation(player, "crow-swing-no-equip", 4.0f); @@ -63,7 +72,7 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { self->AddTimer("PlayerAnimDone", animationTime); } else if (timerName == "PlayerAnimDone") { - GameMessages::SendStopFXEffect(player, true, "hook"); + GameMessages::StopFXEffect(player->GetObjectID(), true, "hook").Send(UNASSIGNED_SYSTEM_ADDRESS); auto forward = QuatUtils::Forward(self->GetRotation()); diff --git a/dScripts/02_server/Map/General/BankInteractServer.cpp b/dScripts/02_server/Map/General/BankInteractServer.cpp index 9b5634917..e87185752 100644 --- a/dScripts/02_server/Map/General/BankInteractServer.cpp +++ b/dScripts/02_server/Map/General/BankInteractServer.cpp @@ -1,5 +1,6 @@ #include "BankInteractServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Entity.h" #include "Amf3.h" @@ -8,7 +9,11 @@ void BankInteractServer::OnUse(Entity* self, Entity* user) { args.Insert("state", "bank"); - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = user->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(user->GetSystemAddress()); } void BankInteractServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, @@ -18,7 +23,11 @@ void BankInteractServer::OnFireEventServerSide(Entity* self, Entity* sender, std args.Insert("visible", false); - GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = sender->GetObjectID(); + uiMessage.strMessageName = "ToggleBank"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(sender->GetSystemAddress()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); } diff --git a/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp b/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp index 6b037ca55..4a327a553 100644 --- a/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp +++ b/dScripts/02_server/Map/General/BaseInteractDropLootServer.cpp @@ -1,6 +1,7 @@ #include "BaseInteractDropLootServer.h" #include "Loot.h" #include "GameMessages.h" +#include "EffectsMessages.h" void BaseInteractDropLootServer::OnUse(Entity* self, Entity* user) { BaseUse(self, user); @@ -17,7 +18,7 @@ void BaseInteractDropLootServer::BaseUse(Entity* self, Entity* user) { auto useSound = self->GetVar(u"sound1"); if (!useSound.empty()) { - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), useSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), useSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } self->SetNetworkVar(u"bInUse", true); diff --git a/dScripts/02_server/Map/General/ExplodingAsset.cpp b/dScripts/02_server/Map/General/ExplodingAsset.cpp index f4902a2ce..b3b1af5ce 100644 --- a/dScripts/02_server/Map/General/ExplodingAsset.cpp +++ b/dScripts/02_server/Map/General/ExplodingAsset.cpp @@ -1,6 +1,7 @@ #include "ExplodingAsset.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionComponent.h" #include "SkillComponent.h" #include "eMissionTaskType.h" @@ -59,7 +60,12 @@ void ExplodingAsset::OnHit(Entity* self, Entity* attacker) { self->SetBoolean(u"bIsHit", true); self->SetOwnerOverride(attacker->GetObjectID()); - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16); + GameMessages::PlayEmbeddedEffectOnAllClientsNearObject embeddedEffect; + embeddedEffect.target = self->GetObjectID(); + embeddedEffect.effectName = u"camshake"; + embeddedEffect.fromObjectID = self->GetObjectID(); + embeddedEffect.radius = 16; + embeddedEffect.Send(UNASSIGNED_SYSTEM_ADDRESS); self->Smash(attacker->GetObjectID()); auto* skillComponent = self->GetComponent(); @@ -92,14 +98,14 @@ void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::stri if (status == "ENTER") { RenderComponent::PlayAnimation(self, u"bounce"); - GameMessages::SendPlayFXEffect(self, -1, u"anim", "bouncin", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"anim", "bouncin").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"playersNearChest", self->GetVar(u"playersNearChest") + 1); } else if (status == "LEAVE") { self->SetVar(u"playersNearChest", self->GetVar(u"playersNearChest") - 1); if (self->GetVar(u"playersNearChest") < 1) { RenderComponent::PlayAnimation(self, u"idle"); - GameMessages::SendStopFXEffect(self, true, "bouncin"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "bouncin").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"playersNearChest", 0); } } diff --git a/dScripts/02_server/Map/General/MailBoxServer.cpp b/dScripts/02_server/Map/General/MailBoxServer.cpp index 53f3b3a26..25eac7663 100644 --- a/dScripts/02_server/Map/General/MailBoxServer.cpp +++ b/dScripts/02_server/Map/General/MailBoxServer.cpp @@ -1,6 +1,7 @@ #include "MailBoxServer.h" #include "Amf3.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Entity.h" void MailBoxServer::OnUse(Entity* self, Entity* user) { @@ -8,13 +9,21 @@ void MailBoxServer::OnUse(Entity* self, Entity* user) { args.Insert("state", "Mail"); - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = user->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(user->GetSystemAddress()); } void MailBoxServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == "toggleMail") { AMFArrayValue args; args.Insert("visible", false); - GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleMail", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = sender->GetObjectID(); + uiMessage.strMessageName = "ToggleMail"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(sender->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/General/PropertyDevice.cpp b/dScripts/02_server/Map/General/PropertyDevice.cpp index df13a3255..bc3c17751 100644 --- a/dScripts/02_server/Map/General/PropertyDevice.cpp +++ b/dScripts/02_server/Map/General/PropertyDevice.cpp @@ -1,5 +1,6 @@ #include "PropertyDevice.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "eMissionState.h" @@ -19,7 +20,7 @@ void PropertyDevice::OnQuickBuildComplete(Entity* self, Entity* target) { auto* missionComponent = target->GetComponent(); if (missionComponent != nullptr) { if (missionComponent->GetMissionState(m_PropertyMissionID) == eMissionState::ACTIVE) { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 641, u"create", "callhome"); + GameMessages::PlayFXEffect(self->GetObjectID(), 641, u"create", "callhome").Send(UNASSIGNED_SYSTEM_ADDRESS); missionComponent->ForceProgress(m_PropertyMissionID, 1793, self->GetLOT()); } } diff --git a/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp index a5ce92cd4..05aadf8f8 100644 --- a/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp +++ b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp @@ -1,6 +1,7 @@ #include "StoryBoxInteractServer.h" #include "Character.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "dServer.h" #include "Amf3.h" #include "Entity.h" @@ -14,7 +15,11 @@ void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { args.Insert("state", "Story"); - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = user->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(user->GetSystemAddress()); } user->AddCallbackTimer(0.1f, [user, customText]() { @@ -23,7 +28,11 @@ void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { args.Insert("visible", true); args.Insert("text", customText); - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "ToggleStoryBox", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = user->GetObjectID(); + uiMessage.strMessageName = "ToggleStoryBox"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(user->GetSystemAddress()); }); return; diff --git a/dScripts/02_server/Map/General/TokenConsoleServer.cpp b/dScripts/02_server/Map/General/TokenConsoleServer.cpp index 68f4130fe..d8d5ba177 100644 --- a/dScripts/02_server/Map/General/TokenConsoleServer.cpp +++ b/dScripts/02_server/Map/General/TokenConsoleServer.cpp @@ -1,6 +1,7 @@ #include "TokenConsoleServer.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Character.h" #include "eReplicaComponentType.h" #include "eTerminateType.h" @@ -18,7 +19,7 @@ void TokenConsoleServer::OnUse(Entity* self, Entity* user) { //play sound if (self->HasVar(u"sound1")) { - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), self->GetVarAsString(u"sound1")); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), self->GetVarAsString(u"sound1")).Send(UNASSIGNED_SYSTEM_ADDRESS); } //figure out which faction the player belongs to: diff --git a/dScripts/02_server/Map/General/WishingWellServer.cpp b/dScripts/02_server/Map/General/WishingWellServer.cpp index 160282d3f..2efa6ee21 100644 --- a/dScripts/02_server/Map/General/WishingWellServer.cpp +++ b/dScripts/02_server/Map/General/WishingWellServer.cpp @@ -1,6 +1,7 @@ #include "WishingWellServer.h" #include "ScriptedActivityComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Loot.h" #include "EntityManager.h" #include "eTerminateType.h" @@ -18,7 +19,7 @@ void WishingWellServer::OnUse(Entity* self, Entity* user) { const auto audio = self->GetVar(u"sound1"); if (!audio.empty()) { - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), audio); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), audio).Send(UNASSIGNED_SYSTEM_ADDRESS); } Loot::DropActivityLoot( diff --git a/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp b/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp index 1cafe67c9..3b532755d 100644 --- a/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp +++ b/dScripts/02_server/Map/NS/NsLegoClubDoor.cpp @@ -1,6 +1,7 @@ #include "NsLegoClubDoor.h" #include "dZoneManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Amf3.h" void NsLegoClubDoor::OnStartup(Entity* self) { @@ -41,7 +42,11 @@ void NsLegoClubDoor::OnUse(Entity* self, Entity* user) { auto* player = user; if (CheckChoice(self, player)) { - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", teleportArgs); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = player->GetObjectID(); + uiMessage.strMessageName = "QueueChoiceBox"; + uiMessage.args = std::move(teleportArgs); + uiMessage.SendToClient(player->GetSystemAddress()); } else if (self->GetVar(u"currentZone") != m_ChoiceZoneID) { AMFArrayValue multiArgs; multiArgs.Insert("state", "Lobby"); @@ -52,7 +57,11 @@ void NsLegoClubDoor::OnUse(Entity* self, Entity* user) { context->Insert("HelpVisible", "show"); context->Insert("type", "Lego_Club_Valid"); - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "pushGameState", multiArgs); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = player->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(multiArgs); + uiMessage.SendToClient(player->GetSystemAddress()); } else { BaseOnUse(self, player); } diff --git a/dScripts/02_server/Map/NS/NsLupTeleport.cpp b/dScripts/02_server/Map/NS/NsLupTeleport.cpp index 6886b4cdc..a07ef8987 100644 --- a/dScripts/02_server/Map/NS/NsLupTeleport.cpp +++ b/dScripts/02_server/Map/NS/NsLupTeleport.cpp @@ -1,6 +1,7 @@ #include "NsLupTeleport.h" #include "dZoneManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Amf3.h" void NsLupTeleport::OnStartup(Entity* self) { @@ -41,7 +42,11 @@ void NsLupTeleport::OnUse(Entity* self, Entity* user) { auto* player = user; if (CheckChoice(self, player)) { - GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = player->GetObjectID(); + uiMessage.strMessageName = "QueueChoiceBox"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(player->GetSystemAddress()); } else { BaseOnUse(self, player); } diff --git a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp index 39bda78bf..df0fe7b68 100644 --- a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp +++ b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp @@ -1,6 +1,7 @@ #include "NsTokenConsoleServer.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Character.h" #include "MissionComponent.h" #include "QuickBuildComponent.h" @@ -39,7 +40,7 @@ void NsTokenConsoleServer::OnUse(Entity* self, Entity* user) { const auto useSound = self->GetVar(u"sound1"); if (!useSound.empty()) { - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), useSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), useSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } // Player must be in faction to interact with this entity. diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp index 6ae4c7679..9d30ccd60 100644 --- a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp @@ -1,5 +1,6 @@ #include "NtAssemblyTubeServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "eMissionTaskType.h" @@ -47,9 +48,19 @@ void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) { if (!teleCinematic.empty()) { const auto teleCinematicUname = teleCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress(), - true, true, true, false, eEndBehavior::RETURN, false, -1, false, true - ); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = teleCinematicUname; + cinematic.allowGhostUpdates = true; + cinematic.bCloseMultiInteract = true; + cinematic.bSendServerNotify = true; + cinematic.bUseControlledObjectForAudioListener = false; + cinematic.endBehavior = eEndBehavior::RETURN; + cinematic.hidePlayerDuringCine = false; + cinematic.leadIn = -1; + cinematic.leavePlayerLockedWhenFinished = false; + cinematic.lockPlayer = true; + cinematic.Send(player->GetSystemAddress()); } RenderComponent::PlayAnimation(player, u"tube-sucker", 4.0f); @@ -104,7 +115,7 @@ void NtAssemblyTubeServer::TeleportPlayer(Entity* self, Entity* player) { const auto useSound = self->GetVar(u"sound1"); if (!useSound.empty()) { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), useSound); + GameMessages::PlayNDAudioEmitter(player->GetObjectID(), useSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp b/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp index b8036c896..b49f07c26 100644 --- a/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp +++ b/dScripts/02_server/Map/NT/NtBeamImaginationCollectors.cpp @@ -1,6 +1,7 @@ #include "NtBeamImaginationCollectors.h" #include "GeneralUtils.h" #include "GameMessages.h" +#include "EffectsMessages.h" void NtBeamImaginationCollectors::OnStartup(Entity* self) { self->AddTimer("PlayFX", GetRandomNum()); @@ -23,7 +24,7 @@ void NtBeamImaginationCollectors::OnTimerDone(Entity* self, std::string timerNam return; } - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, m_FxName, "Beam"); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, m_FxName, "Beam").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("PlayFX", GetRandomNum()); } diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp index c384b26d5..d9201f17a 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "SkillComponent.h" #include "DestroyableComponent.h" +#include "EffectsMessages.h" void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) { const auto challengeObjectID = self->GetVar(u"challengeObjectID"); @@ -36,6 +37,11 @@ void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* at if (skillComponent != nullptr) { skillComponent->CalculateBehavior(1338, 30875, attacker->GetObjectID()); } - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16.0f); + GameMessages::PlayEmbeddedEffectOnAllClientsNearObject embeddedEffect; + embeddedEffect.target = self->GetObjectID(); + embeddedEffect.effectName = u"camshake"; + embeddedEffect.fromObjectID = self->GetObjectID(); + embeddedEffect.radius = 16.0f; + embeddedEffect.Send(UNASSIGNED_SYSTEM_ADDRESS); self->Smash(attacker->GetObjectID()); } diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp index 6e05112c5..51d7ebd8d 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp @@ -1,5 +1,6 @@ #include "NtCombatChallengeServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ActivityMessages.h" #include "EntityManager.h" #include "EntityInfo.h" @@ -33,7 +34,7 @@ void NtCombatChallengeServer::OnHitOrHealResult(Entity* self, Entity* attacker, self->SetVar(u"totalDmg", totalDmg); self->SetNetworkVar(u"totalDmg", totalDmg); - GameMessages::SendPlayNDAudioEmitter(self, attacker->GetSystemAddress(), scoreSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), scoreSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } @@ -55,7 +56,7 @@ void NtCombatChallengeServer::OnMessageBoxResponse(Entity* self, Entity* sender, inventoryComponent->RemoveItem(3039, 1, eInventoryType::ALL); } - GameMessages::SendPlayNDAudioEmitter(self, sender->GetSystemAddress(), startSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), startSound).Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("start_delay", 2.0f); @@ -164,9 +165,9 @@ void NtCombatChallengeServer::OnActivityTimerUpdate(Entity* self, float timeRema self->SetNetworkVar(u"update_time", std::ceil(timeRemaining)); if (timeRemaining <= 3) { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, timerLowSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), timerLowSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } else { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, timerSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), timerSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } } @@ -189,7 +190,7 @@ void NtCombatChallengeServer::OnTimerDone(Entity* self, std::string timerName) { if (gameTick <= 0) { ResetGame(self); - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, stopSound); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), stopSound).Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("reset_tick", 5); } else { diff --git a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp index f182c8a5f..1d81a1192 100644 --- a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp @@ -1,5 +1,6 @@ #include "NtParadoxPanelServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionComponent.h" #include "EntityManager.h" #include "Character.h" @@ -53,7 +54,7 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { GameMessages::SendKnockback(user->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, { dir.x * 15, 5, dir.z * 15 }); - GameMessages::SendPlayFXEffect(self, 6432, u"create", "console_sparks", LWOOBJID_EMPTY, 1.0, 1.0, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 6432, u"create", "console_sparks").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddCallbackTimer(2, [this, self, playerID]() { auto* player = Game::entityManager->GetEntity(playerID); @@ -64,7 +65,7 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"bActive", 0, 0, player->GetObjectID(), "", player->GetSystemAddress()); - GameMessages::SendStopFXEffect(self, true, "console_sparks"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "console_sparks").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"bActive", false); }); diff --git a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp index 67ff4bec7..65670fb28 100644 --- a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp @@ -1,5 +1,6 @@ #include "NtParadoxTeleServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "eMissionTaskType.h" @@ -69,7 +70,10 @@ void NtParadoxTeleServer::TeleportPlayer(Entity* self, Entity* player) { if (!teleCinematic.empty()) { const auto teleCinematicUname = teleCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress()); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = teleCinematicUname; + cinematic.Send(player->GetSystemAddress()); } GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); @@ -93,7 +97,7 @@ void NtParadoxTeleServer::TeleportPlayer(Entity* self, Entity* player) { const auto useSound = self->GetVar(u"sound1"); if (!useSound.empty()) { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), useSound); + GameMessages::PlayNDAudioEmitter(player->GetObjectID(), useSound).Send(UNASSIGNED_SYSTEM_ADDRESS); } } @@ -110,6 +114,9 @@ void NtParadoxTeleServer::UnlockPlayer(Entity* self, Entity* player) { if (!teleCinematic.empty()) { const auto teleCinematicUname = teleCinematic; - GameMessages::SendEndCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress()); + GameMessages::EndCinematic endCinematic; + endCinematic.target = player->GetObjectID(); + endCinematic.pathName = teleCinematicUname; + endCinematic.Send(player->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp index 7e38ac12f..d35950f9d 100644 --- a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp @@ -1,5 +1,6 @@ #include "NtVentureCannonServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "Entity.h" #include "GeneralUtils.h" @@ -35,9 +36,12 @@ void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { RenderComponent::PlayAnimation(player, u"scale-down", 4.0f); const auto enterCinematicUname = enterCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), enterCinematicUname, player->GetSystemAddress()); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = enterCinematicUname; + cinematic.Send(player->GetSystemAddress()); - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), "{e8bf79ce-7453-4a7d-b872-fee65e97ff15}"); + GameMessages::PlayNDAudioEmitter(player->GetObjectID(), "{e8bf79ce-7453-4a7d-b872-fee65e97ff15}").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddCallbackTimer(3, [this, self]() { self->SetNetworkVar(u"bIsInUse", false); @@ -62,9 +66,14 @@ void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) { if (!cannonEffectGroup.empty()) { auto* cannonEffect = cannonEffectGroup[0]; - GameMessages::SendPlayFXEffect(cannonEffect, 6036, u"create", "cannon_blast", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(cannonEffect->GetObjectID(), 6036, u"create", "cannon_blast").Send(UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(cannonEffect, u"camshake-bridge", cannonEffect->GetObjectID(), 100); + GameMessages::PlayEmbeddedEffectOnAllClientsNearObject embeddedEffect; + embeddedEffect.target = cannonEffect->GetObjectID(); + embeddedEffect.effectName = u"camshake-bridge"; + embeddedEffect.fromObjectID = cannonEffect->GetObjectID(); + embeddedEffect.radius = 100; + embeddedEffect.Send(UNASSIGNED_SYSTEM_ADDRESS); } FirePlayer(self, player); @@ -78,9 +87,19 @@ void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) { } const auto exitCinematicUname = exitCinematic; - GameMessages::SendPlayCinematic(player->GetObjectID(), exitCinematicUname, player->GetSystemAddress(), - true, true, true, false, eEndBehavior::RETURN, false, 0, false, false - ); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = exitCinematicUname; + cinematic.allowGhostUpdates = true; + cinematic.bCloseMultiInteract = true; + cinematic.bSendServerNotify = true; + cinematic.bUseControlledObjectForAudioListener = false; + cinematic.endBehavior = eEndBehavior::RETURN; + cinematic.hidePlayerDuringCine = false; + cinematic.leadIn = 0; + cinematic.leavePlayerLockedWhenFinished = false; + cinematic.lockPlayer = false; + cinematic.Send(player->GetSystemAddress()); self->AddCallbackTimer(1.5f, [this, self, playerID]() { auto* player = Game::entityManager->GetEntity(playerID); diff --git a/dScripts/02_server/Map/PR/HydrantBroken.cpp b/dScripts/02_server/Map/PR/HydrantBroken.cpp index c1702cc26..daaee04b7 100644 --- a/dScripts/02_server/Map/PR/HydrantBroken.cpp +++ b/dScripts/02_server/Map/PR/HydrantBroken.cpp @@ -2,6 +2,7 @@ #include "PetMessages.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" void HydrantBroken::OnStartup(Entity* self) { self->AddTimer("playEffect", 1); @@ -39,6 +40,6 @@ void HydrantBroken::OnTimerDone(Entity* self, std::string timerName) { self->Kill(); } else if (timerName == "playEffect") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 384, u"water", "water", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 384, u"water", "water").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp index 2d526a257..4b5e74fe1 100644 --- a/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp @@ -1,5 +1,6 @@ #include "EnemySpiderSpawner.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "EntityInfo.h" #include "DestroyableComponent.h" @@ -12,7 +13,7 @@ void EnemySpiderSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std int32_t param2, int32_t param3) { if (args == "prepEgg") { // Highlight eggs about to hatch with Maelstrom effect - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2856, u"maelstrom", "test", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 2856, u"maelstrom", "test").Send(UNASSIGNED_SYSTEM_ADDRESS); // Make indestructible auto dest = static_cast(self->GetComponent(eReplicaComponentType::DESTROYABLE)); @@ -37,7 +38,7 @@ void EnemySpiderSpawner::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "StartSpawnTime") { SpawnSpiderling(self); } else if (timerName == "SpawnSpiderling") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 644, u"create", "egg_puff_b", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 644, u"create", "egg_puff_b").Send(UNASSIGNED_SYSTEM_ADDRESS); //TODO: set the aggro radius larger @@ -63,6 +64,6 @@ void EnemySpiderSpawner::OnTimerDone(Entity* self, std::string timerName) { //-------------------------------------------------------------- void EnemySpiderSpawner::SpawnSpiderling(Entity* self) { //Initiate the actual spawning - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2260, u"rebuild_medium", "dropdustmedium", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 2260, u"rebuild_medium", "dropdustmedium").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("SpawnSpiderling", spawnTime); } diff --git a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp index 180543650..dc260c7c8 100644 --- a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp @@ -3,6 +3,7 @@ #include "Character.h" #include "Entity.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "dZoneManager.h" #include "RenderComponent.h" #include "MissionComponent.h" @@ -62,7 +63,10 @@ void ZoneAgProperty::OnPlayerLoaded(Entity* self, Entity* player) { } if (Game::zoneManager->GetZone()->GetZoneID().GetMapID() == 1102) { - GameMessages::SendPlay2DAmbientSound(player, GUIDMaelstrom); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = GUIDMaelstrom; + ambientSound.SendToClient(player->GetSystemAddress()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, "", player->GetSystemAddress()); @@ -256,8 +260,15 @@ void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) { DestroySpawner(self->GetVar(SpiderScreamSpawner)); for (auto* player : Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER)) { - GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + GameMessages::Stop2DAmbientSound stopAmbientSound; + stopAmbientSound.target = player->GetObjectID(); + stopAmbientSound.force = true; + stopAmbientSound.audioGUID = GUIDMaelstrom; + stopAmbientSound.SendToClient(player->GetSystemAddress()); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = GUIDPeaceful; + ambientSound.SendToClient(player->GetSystemAddress()); } } else if (timerName == "ShowVendor") { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); diff --git a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp index 50fea9a05..16ee02fd1 100644 --- a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp +++ b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp @@ -1,6 +1,7 @@ #include "PropertyBankInteract.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Amf3.h" #include "Entity.h" @@ -24,7 +25,11 @@ void PropertyBankInteract::OnUse(Entity* self, Entity* user) { args.Insert("state", "bank"); - GameMessages::SendUIMessageServerToSingleClient(user, user->GetSystemAddress(), "pushGameState", args); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = user->GetObjectID(); + uiMessage.strMessageName = "pushGameState"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(user->GetSystemAddress()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); @@ -37,7 +42,11 @@ void PropertyBankInteract::OnFireEventServerSide(Entity* self, Entity* sender, s amfArgs.Insert("visible", false); - GameMessages::SendUIMessageServerToSingleClient(sender, sender->GetSystemAddress(), "ToggleBank", amfArgs); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = sender->GetObjectID(); + uiMessage.strMessageName = "ToggleBank"; + uiMessage.args = std::move(amfArgs); + uiMessage.SendToClient(sender->GetSystemAddress()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); diff --git a/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp b/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp index 45b6f99af..033da0e86 100644 --- a/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp +++ b/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp @@ -1,6 +1,7 @@ #include "CatapultBaseServer.h" #include "PetMessages.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "Entity.h" #include "RenderComponent.h" @@ -28,7 +29,7 @@ void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) { // tell the arm to the play the platform animation, which is just the arm laying there but with bouncer for (auto* obj : arm) { RenderComponent::PlayAnimation(obj, u"idle-platform"); - GameMessages::SendPlayNDAudioEmitter(obj, UNASSIGNED_SYSTEM_ADDRESS, "{8cccf912-69e3-4041-a20b-63e4afafc993}"); + GameMessages::PlayNDAudioEmitter(obj->GetObjectID(), "{8cccf912-69e3-4041-a20b-63e4afafc993}").Send(UNASSIGNED_SYSTEM_ADDRESS); // set the art so we can use it again self->SetVar(u"Arm", obj->GetObjectID()); break; diff --git a/dScripts/02_server/Map/njhub/FallingTile.cpp b/dScripts/02_server/Map/njhub/FallingTile.cpp index 7804c8bcb..fe99e09cf 100644 --- a/dScripts/02_server/Map/njhub/FallingTile.cpp +++ b/dScripts/02_server/Map/njhub/FallingTile.cpp @@ -1,6 +1,7 @@ #include "FallingTile.h" #include "MovingPlatformComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" void FallingTile::OnStartup(Entity* self) { auto* movingPlatfromComponent = self->GetComponent(); @@ -44,12 +45,12 @@ void FallingTile::OnTimerDone(Entity* self, std::string timerName) { movingPlatfromComponent->GotoWaypoint(1); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"down", "down"); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"down", "down").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "flipBack") { self->SetVar(u"AboutToFall", false); movingPlatfromComponent->GotoWaypoint(0); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"up", "up"); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"up", "up").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp b/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp index d3e54be13..a61a7fba0 100644 --- a/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp +++ b/dScripts/02_server/Map/njhub/NjGarmadonCelebration.cpp @@ -1,6 +1,7 @@ #include "NjGarmadonCelebration.h" #include "Character.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ePlayerFlag.h" void NjGarmadonCelebration::OnCollisionPhantom(Entity* self, Entity* target) { @@ -13,6 +14,9 @@ void NjGarmadonCelebration::OnCollisionPhantom(Entity* self, Entity* target) { if (!character->GetPlayerFlag(ePlayerFlag::NJ_GARMADON_CINEMATIC_SEEN)) { character->SetPlayerFlag(ePlayerFlag::NJ_GARMADON_CINEMATIC_SEEN, true); - GameMessages::SendStartCelebrationEffect(target, target->GetSystemAddress(), GarmadonCelebrationID); + GameMessages::StartCelebrationEffect celebration; + celebration.target = target->GetObjectID(); + celebration.celebrationID = GarmadonCelebrationID; + celebration.SendToClient(target->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/njhub/NjWuNPC.cpp b/dScripts/02_server/Map/njhub/NjWuNPC.cpp index 1a5d30fd6..53658aa4a 100644 --- a/dScripts/02_server/Map/njhub/NjWuNPC.cpp +++ b/dScripts/02_server/Map/njhub/NjWuNPC.cpp @@ -3,6 +3,7 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "eMissionState.h" #include "ePlayerFlag.h" @@ -54,7 +55,7 @@ void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, e // Stop the dragon effects for (auto* dragon : Game::entityManager->GetEntitiesInGroup(m_DragonStatueGroup)) { - GameMessages::SendStopFXEffect(dragon, true, "on"); + GameMessages::StopFXEffect(dragon->GetObjectID(), true, "on").Send(UNASSIGNED_SYSTEM_ADDRESS); } }); } diff --git a/dScripts/02_server/Map/njhub/RainOfArrows.cpp b/dScripts/02_server/Map/njhub/RainOfArrows.cpp index 2fc73eb61..65a01b65c 100644 --- a/dScripts/02_server/Map/njhub/RainOfArrows.cpp +++ b/dScripts/02_server/Map/njhub/RainOfArrows.cpp @@ -3,6 +3,7 @@ #include "SkillComponent.h" #include "EntityInfo.h" #include "GameMessages.h" +#include "EffectsMessages.h" void RainOfArrows::OnStartup(Entity* self) { @@ -60,7 +61,7 @@ void RainOfArrows::OnTimerDone(Entity* self, std::string timerName) { self->AddTimer("FireSkill", 0.7f); } else if (timerName == "PlayArrowSound") { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, m_ArrowsGUID); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), m_ArrowsGUID).Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "FireSkill") { if (child != nullptr) { child->Smash(); diff --git a/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp index be47b53b3..9e20078ff 100644 --- a/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp +++ b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "BaseCombatAIComponent.h" #include "BuffComponent.h" #include "SkillComponent.h" @@ -265,7 +266,7 @@ void NjMonastryBossInstance::HandleCounterWeightSpawned(Entity* self, Entity* co } RenderComponent::PlayAnimation(frakjaw, StunnedAnimation); - GameMessages::SendPlayNDAudioEmitter(frakjaw, UNASSIGNED_SYSTEM_ADDRESS, CounterSmashAudio); + GameMessages::PlayNDAudioEmitter(frakjaw->GetObjectID(), CounterSmashAudio).Send(UNASSIGNED_SYSTEM_ADDRESS); // Before wave 4 we should lower frakjaw from the ledge if (self->GetVar(WaveNumberVariable) == 3) { diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index 7392f7590..896cc24a7 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -1,5 +1,6 @@ #include "BaseConsoleTeleportServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "CharacterComponent.h" #include "RenderComponent.h" #include "EntityManager.h" @@ -11,7 +12,15 @@ void BaseConsoleTeleportServer::BaseOnUse(Entity* self, Entity* user) { const auto& teleportLocString = self->GetVar(u"teleportString"); - GameMessages::SendDisplayMessageBox(player->GetObjectID(), true, self->GetObjectID(), u"TransferBox", 0, teleportLocString, u"", player->GetSystemAddress()); + GameMessages::DisplayMessageBox messageBox; + messageBox.target = player->GetObjectID(); + messageBox.bShow = true; + messageBox.callbackClient = self->GetObjectID(); + messageBox.identifier = u"TransferBox"; + messageBox.imageID = 0; + messageBox.text = teleportLocString; + messageBox.userData = u""; + messageBox.Send(player->GetSystemAddress()); } void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { @@ -30,7 +39,7 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s const auto& teleportFXs = self->GetVar>(u"teleportEffectTypes"); for (const auto& type : teleportFXs) { - GameMessages::SendPlayFXEffect(player->GetObjectID(), teleportFXID, type, "FX" + GeneralUtils::UTF16ToWTF8(type)); + GameMessages::PlayFXEffect(player->GetObjectID(), teleportFXID, type, "FX" + GeneralUtils::UTF16ToWTF8(type)).Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/BasePropertyServer.cpp b/dScripts/BasePropertyServer.cpp index 69b839f3c..ddd5bdda2 100644 --- a/dScripts/BasePropertyServer.cpp +++ b/dScripts/BasePropertyServer.cpp @@ -1,5 +1,6 @@ #include "BasePropertyServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "Character.h" @@ -106,8 +107,15 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { } } - GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + GameMessages::Stop2DAmbientSound stopAmbientSound; + stopAmbientSound.target = player->GetObjectID(); + stopAmbientSound.force = true; + stopAmbientSound.audioGUID = GUIDMaelstrom; + stopAmbientSound.SendToClient(player->GetSystemAddress()); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = GUIDPeaceful; + ambientSound.SendToClient(player->GetSystemAddress()); self->AddTimer(TurnSkyOffTimer, 1.5f); @@ -116,7 +124,7 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { self->AddTimer(KillFXObjectTimer, 1.0f); } - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + ambientSound.SendToClient(player->GetSystemAddress()); // activate property safe spawner network ActivateSpawner(self->GetVar(PropObjsSpawner)); @@ -138,10 +146,20 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { if (!flagMsg.flag) { StartMaelstrom(self, player); SpawnSpots(self); - GameMessages::SendPlay2DAmbientSound(player, GUIDMaelstrom); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = GUIDMaelstrom; + ambientSound.SendToClient(player->GetSystemAddress()); } else { - GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + GameMessages::Stop2DAmbientSound stopAmbientSound; + stopAmbientSound.target = player->GetObjectID(); + stopAmbientSound.force = true; + stopAmbientSound.audioGUID = GUIDMaelstrom; + stopAmbientSound.SendToClient(player->GetSystemAddress()); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = GUIDPeaceful; + ambientSound.SendToClient(player->GetSystemAddress()); self->AddTimer(TurnSkyOffTimer, 1.5f); self->AddTimer(KillFXObjectTimer, 1.0f); @@ -385,8 +403,15 @@ void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerNam if (player == nullptr) return; - GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); - GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); + GameMessages::Stop2DAmbientSound stopAmbientSound; + stopAmbientSound.target = player->GetObjectID(); + stopAmbientSound.force = true; + stopAmbientSound.audioGUID = GUIDMaelstrom; + stopAmbientSound.SendToClient(player->GetSystemAddress()); + GameMessages::Play2DAmbientSound ambientSound; + ambientSound.target = player->GetObjectID(); + ambientSound.audioGUID = GUIDPeaceful; + ambientSound.SendToClient(player->GetSystemAddress()); self->AddTimer(ShowVendorTimer, 5.0f); } else if (timerName == KillMarkerTimer) { diff --git a/dScripts/BaseSurvivalServer.cpp b/dScripts/BaseSurvivalServer.cpp index d82c1499d..2a41b6e98 100644 --- a/dScripts/BaseSurvivalServer.cpp +++ b/dScripts/BaseSurvivalServer.cpp @@ -1,5 +1,6 @@ #include "BaseSurvivalServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ActivityMessages.h" #include "DestroyableComponent.h" #include "EntityManager.h" @@ -219,7 +220,7 @@ void BaseSurvivalServer::OnActivityTimerDone(Entity* self, const std::string& na for (const auto& playerID : state.players) { auto* player = Game::entityManager->GetEntity(playerID); if (player != nullptr) { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID); + GameMessages::PlayNDAudioEmitter(player->GetObjectID(), spawnSoundGUID).Send(UNASSIGNED_SYSTEM_ADDRESS); } } } diff --git a/dScripts/BaseWavesServer.cpp b/dScripts/BaseWavesServer.cpp index b92987e86..5c287e1bd 100644 --- a/dScripts/BaseWavesServer.cpp +++ b/dScripts/BaseWavesServer.cpp @@ -1,5 +1,6 @@ #include "BaseWavesServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ActivityMessages.h" #include "DestroyableComponent.h" #include "EntityManager.h" @@ -198,7 +199,7 @@ void BaseWavesServer::OnActivityTimerDone(Entity* self, const std::string& name) for (const auto& playerID : state.players) { auto* player = Game::entityManager->GetEntity(playerID); if (player != nullptr) { - GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID); + GameMessages::PlayNDAudioEmitter(player->GetObjectID(), spawnSoundGUID).Send(UNASSIGNED_SYSTEM_ADDRESS); } } } else if (name == NextWaveTickTimer) { diff --git a/dScripts/ChooseYourDestinationNsToNt.cpp b/dScripts/ChooseYourDestinationNsToNt.cpp index b736883c4..47a70578f 100644 --- a/dScripts/ChooseYourDestinationNsToNt.cpp +++ b/dScripts/ChooseYourDestinationNsToNt.cpp @@ -1,6 +1,7 @@ #include "ChooseYourDestinationNsToNt.h" #include "Character.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "eTerminateType.h" bool ChooseYourDestinationNsToNt::CheckChoice(Entity* self, Entity* player) { @@ -56,7 +57,15 @@ void ChooseYourDestinationNsToNt::BaseChoiceBoxRespond(Entity* self, Entity* sen self->SetVar(u"teleportString", strText); self->SetVar(u"transferZoneID", GeneralUtils::to_u16string(newMap.value())); - GameMessages::SendDisplayMessageBox(sender->GetObjectID(), true, self->GetObjectID(), u"TransferBox", 0, strText, u"", sender->GetSystemAddress()); + GameMessages::DisplayMessageBox messageBox; + messageBox.target = sender->GetObjectID(); + messageBox.bShow = true; + messageBox.callbackClient = self->GetObjectID(); + messageBox.identifier = u"TransferBox"; + messageBox.imageID = 0; + messageBox.text = strText; + messageBox.userData = u""; + messageBox.Send(sender->GetSystemAddress()); } else { GameMessages::SendTerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); } diff --git a/dScripts/NtFactionSpyServer.cpp b/dScripts/NtFactionSpyServer.cpp index 7414bb344..ab2f85a41 100644 --- a/dScripts/NtFactionSpyServer.cpp +++ b/dScripts/NtFactionSpyServer.cpp @@ -3,6 +3,7 @@ #include "ProximityMonitorComponent.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionComponent.h" #include "eMissionState.h" #include "eReplicaComponentType.h" @@ -41,8 +42,13 @@ void NtFactionSpyServer::OnProximityUpdate(Entity* self, Entity* entering, std:: self->SetVar(m_CinematicRootVariable, cinematicSplit.at(0)); } - GameMessages::SendPlayCinematic(entering->GetObjectID(), cinematic, entering->GetSystemAddress(), - true, true, true); + GameMessages::PlayCinematic playCinematic; + playCinematic.target = entering->GetObjectID(); + playCinematic.pathName = cinematic; + playCinematic.allowGhostUpdates = true; + playCinematic.bCloseMultiInteract = true; + playCinematic.bSendServerNotify = true; + playCinematic.Send(entering->GetSystemAddress()); } } } diff --git a/dScripts/SpawnPetBaseServer.cpp b/dScripts/SpawnPetBaseServer.cpp index 04a24ae68..345727e43 100644 --- a/dScripts/SpawnPetBaseServer.cpp +++ b/dScripts/SpawnPetBaseServer.cpp @@ -1,5 +1,6 @@ #include "SpawnPetBaseServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "PetComponent.h" #include "EntityInfo.h" @@ -39,7 +40,10 @@ void SpawnPetBaseServer::OnUse(Entity* self, Entity* user) { auto spawnCinematic = self->GetVar(u"spawnCinematic"); if (!spawnCinematic.empty()) { - GameMessages::SendPlayCinematic(user->GetObjectID(), spawnCinematic, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayCinematic cinematic; + cinematic.target = user->GetObjectID(); + cinematic.pathName = spawnCinematic; + cinematic.Send(UNASSIGNED_SYSTEM_ADDRESS); } GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); diff --git a/dScripts/ai/ACT/ActMine.cpp b/dScripts/ai/ACT/ActMine.cpp index 24863e508..18aa4e25e 100644 --- a/dScripts/ai/ACT/ActMine.cpp +++ b/dScripts/ai/ACT/ActMine.cpp @@ -2,6 +2,7 @@ #include "SkillComponent.h" #include "DestroyableComponent.h" #include "QuickBuildComponent.h" +#include "EffectsMessages.h" void ActMine::OnStartup(Entity* self) { self->SetVar(u"QuickBuildComplete", false); @@ -27,7 +28,7 @@ void ActMine::OnProximityUpdate(Entity* self, Entity* entering, std::string name auto* detroyable = self->GetComponent(); if (!detroyable) return; if (status == "ENTER" && self->GetVar(u"QuickBuildComplete") == true && detroyable->IsEnemy(entering)) { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 242, u"orange", "sirenlight_B"); + GameMessages::PlayFXEffect(self->GetObjectID(), 242, u"orange", "sirenlight_B").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("Tick", TICK_TIME); } } @@ -40,7 +41,7 @@ void ActMine::OnTimerDone(Entity* self, std::string timerName) { skill->CalculateBehavior(SKILL_ID, BEHAVIOR_ID, LWOOBJID_EMPTY); self->AddTimer("BlowedUp", BLOWED_UP_TIME); } else { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 242, u"orange", "sirenlight_B"); + GameMessages::PlayFXEffect(self->GetObjectID(), 242, u"orange", "sirenlight_B").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("Tick", TICK_TIME); self->SetVar(u"NumWarnings", self->GetVar(u"NumWarnings") + 1); } diff --git a/dScripts/ai/AG/AgBusDoor.cpp b/dScripts/ai/AG/AgBusDoor.cpp index a4106aaf5..e74e8af88 100644 --- a/dScripts/ai/AG/AgBusDoor.cpp +++ b/dScripts/ai/AG/AgBusDoor.cpp @@ -1,6 +1,7 @@ #include "AgBusDoor.h" #include "Entity.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ProximityMonitorComponent.h" void AgBusDoor::OnStartup(Entity* self) { @@ -55,11 +56,11 @@ void AgBusDoor::MoveDoor(Entity* self, bool bOpen) { } //This is currently commented out because it might be the reason that people's audio is cutting out. - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, "{9a24f1fa-3177-4745-a2df-fbd996d6e1e3}"); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), "{9a24f1fa-3177-4745-a2df-fbd996d6e1e3}").Send(UNASSIGNED_SYSTEM_ADDRESS); } void AgBusDoor::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "dustTimer") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 642, u"create", "busDust", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 642, u"create", "busDust").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/ai/AG/AgJetEffectServer.cpp b/dScripts/ai/AG/AgJetEffectServer.cpp index 69e94c8f8..0344a2f49 100644 --- a/dScripts/ai/AG/AgJetEffectServer.cpp +++ b/dScripts/ai/AG/AgJetEffectServer.cpp @@ -1,5 +1,6 @@ #include "AgJetEffectServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "SkillComponent.h" #include "eReplicaComponentType.h" @@ -14,7 +15,7 @@ void AgJetEffectServer::OnUse(Entity* self, Entity* user) { auto entities = Game::entityManager->GetEntitiesInGroup("Jet_FX"); if (entities.empty()) return; - GameMessages::SendPlayFXEffect(entities.at(0), 641, u"create", "radarDish", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(entities.at(0)->GetObjectID(), 641, u"create", "radarDish").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("radarDish", 2.0f); self->AddTimer("PlayEffect", 2.5f); self->AddTimer("CineDone", 7.5f + 5.0f); // 7.5f is time the cinematic takes to play @@ -38,7 +39,7 @@ void AgJetEffectServer::OnQuickBuildComplete(Entity* self, Entity* target) { void AgJetEffectServer::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "radarDish") { - GameMessages::SendStopFXEffect(self, true, "radarDish"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "radarDish").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "PlayEffect") { auto entities = Game::entityManager->GetEntitiesInGroup("mortarMain"); if (entities.empty()) return; diff --git a/dScripts/ai/AG/AgShipPlayerShockServer.cpp b/dScripts/ai/AG/AgShipPlayerShockServer.cpp index e14d48ae7..c274a535d 100644 --- a/dScripts/ai/AG/AgShipPlayerShockServer.cpp +++ b/dScripts/ai/AG/AgShipPlayerShockServer.cpp @@ -1,5 +1,6 @@ #include "AgShipPlayerShockServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "RenderComponent.h" #include "Entity.h" #include "eTerminateType.h" @@ -13,11 +14,11 @@ void AgShipPlayerShockServer::OnUse(Entity* self, Entity* user) { RenderComponent::PlayAnimation(user, shockAnim); GameMessages::SendKnockback(user->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, NiPoint3(-20, 10, -20)); - GameMessages::SendPlayFXEffect(self, 1430, u"create", "console_sparks", LWOOBJID_EMPTY, 1.0, 1.0, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 1430, u"create", "console_sparks").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("FXTime", fxTime); } void AgShipPlayerShockServer::OnTimerDone(Entity* self, std::string timerName) { - GameMessages::SendStopFXEffect(self, true, "console_sparks"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "console_sparks").Send(UNASSIGNED_SYSTEM_ADDRESS); active = false; } diff --git a/dScripts/ai/AG/AgShipShake.cpp b/dScripts/ai/AG/AgShipShake.cpp index 7dd2323a7..0df1a9f65 100644 --- a/dScripts/ai/AG/AgShipShake.cpp +++ b/dScripts/ai/AG/AgShipShake.cpp @@ -2,6 +2,7 @@ #include "EntityInfo.h" #include "GeneralUtils.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "RenderComponent.h" #include "Entity.h" @@ -39,18 +40,24 @@ void AgShipShake::OnTimerDone(Entity* self, std::string timerName) { self->AddTimer("ShipShakeIdle", static_cast(time)); - if (ref) - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f); + if (ref) { + GameMessages::PlayEmbeddedEffectOnAllClientsNearObject embeddedEffect; + embeddedEffect.target = ref->GetObjectID(); + embeddedEffect.effectName = FXName; + embeddedEffect.fromObjectID = ref->GetObjectID(); + embeddedEffect.radius = 500.0f; + embeddedEffect.Send(UNASSIGNED_SYSTEM_ADDRESS); + } if (debrisObject) - GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(debrisObject->GetObjectID(), -1, u"DebrisFall", "Debris").Send(UNASSIGNED_SYSTEM_ADDRESS); const auto randomFx = GeneralUtils::GenerateRandomNumber(0, 3); if (shipFxObject) { std::string effectType = "shipboom" + std::to_string(randomFx); - GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + GameMessages::PlayFXEffect(shipFxObject->GetObjectID(), 559, GeneralUtils::ASCIIToUTF16(effectType), "FX").Send(UNASSIGNED_SYSTEM_ADDRESS); } self->AddTimer("ShipShakeExplode", 5.0f); diff --git a/dScripts/ai/AG/AgSpiderBossMessage.cpp b/dScripts/ai/AG/AgSpiderBossMessage.cpp index 495225b7f..a9a7ce0c5 100644 --- a/dScripts/ai/AG/AgSpiderBossMessage.cpp +++ b/dScripts/ai/AG/AgSpiderBossMessage.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "RenderComponent.h" @@ -38,7 +39,7 @@ void AgSpiderBossMessage::OnCollisionPhantom(Entity* self, Entity* target) { // knockback the target auto forward = QuatUtils::Forward(self->GetRotation()); box.boxTarget = target->GetObjectID(); - GameMessages::SendPlayFXEffect(target->GetObjectID(), 1378, u"create", "pushBack"); + GameMessages::PlayFXEffect(target->GetObjectID(), 1378, u"create", "pushBack").Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(target, "knockback-recovery"); forward.y += 15; forward.x *= 100; diff --git a/dScripts/ai/FV/ActNinjaSensei.cpp b/dScripts/ai/FV/ActNinjaSensei.cpp index 6a7dc8938..93c064bd9 100644 --- a/dScripts/ai/FV/ActNinjaSensei.cpp +++ b/dScripts/ai/FV/ActNinjaSensei.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" void ActNinjaSensei::OnStartup(Entity* self) { auto students = Game::entityManager->GetEntitiesInGroup(this->m_StudentGroup); @@ -19,54 +20,54 @@ void ActNinjaSensei::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "crane") { for (auto student : students) { - if (student) GameMessages::SendPlayAnimation(student, u"crane"); + if (student) GameMessages::PlayAnimation(student->GetObjectID(), u"crane").Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendPlayAnimation(self, u"crane"); + GameMessages::PlayAnimation(self->GetObjectID(), u"crane").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("bow", 15.33); } if (timerName == "bow") { - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto student : students) { - if (student) GameMessages::SendPlayAnimation(student, u"bow"); + if (student) GameMessages::PlayAnimation(student->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("tiger", 5); } if (timerName == "tiger") { - GameMessages::SendPlayAnimation(self, u"tiger"); + GameMessages::PlayAnimation(self->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto student : students) { - if (student) GameMessages::SendPlayAnimation(student, u"tiger"); + if (student) GameMessages::PlayAnimation(student->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendPlayAnimation(self, u"tiger"); + GameMessages::PlayAnimation(self->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("bow2", 15.33); } if (timerName == "bow2") { - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto student : students) { - if (student) GameMessages::SendPlayAnimation(student, u"bow"); + if (student) GameMessages::PlayAnimation(student->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("mantis", 5); } if (timerName == "mantis") { - GameMessages::SendPlayAnimation(self, u"mantis"); + GameMessages::PlayAnimation(self->GetObjectID(), u"mantis").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto student : students) { - if (student) GameMessages::SendPlayAnimation(student, u"mantis"); + if (student) GameMessages::PlayAnimation(student->GetObjectID(), u"mantis").Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendPlayAnimation(self, u"mantis"); + GameMessages::PlayAnimation(self->GetObjectID(), u"mantis").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("bow3", 15.3); } if (timerName == "bow3") { - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto student : students) { - if (student) GameMessages::SendPlayAnimation(student, u"bow"); + if (student) GameMessages::PlayAnimation(student->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("repeat", 5); } diff --git a/dScripts/ai/FV/ActParadoxPipeFix.cpp b/dScripts/ai/FV/ActParadoxPipeFix.cpp index 7e6451f96..5632454e2 100644 --- a/dScripts/ai/FV/ActParadoxPipeFix.cpp +++ b/dScripts/ai/FV/ActParadoxPipeFix.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "QuickBuildComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionComponent.h" #include "eEndBehavior.h" @@ -30,7 +31,7 @@ void ActParadoxPipeFix::OnQuickBuildComplete(Entity* self, Entity* target) { const auto refinery = Game::entityManager->GetEntitiesInGroup("Paradox"); if (!refinery.empty()) { - GameMessages::SendPlayFXEffect(refinery[0]->GetObjectID(), 3999, u"create", "pipeFX"); + GameMessages::PlayFXEffect(refinery[0]->GetObjectID(), 3999, u"create", "pipeFX").Send(UNASSIGNED_SYSTEM_ADDRESS); } for (auto* object : groupObjs) { @@ -43,7 +44,17 @@ void ActParadoxPipeFix::OnQuickBuildComplete(Entity* self, Entity* target) { missionComponent->ForceProgressTaskType(769, 1, 1, false); } - GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, eEndBehavior::RETURN, false, 2.0f); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = u"ParadoxPipeFinish"; + cinematic.allowGhostUpdates = true; + cinematic.bCloseMultiInteract = true; + cinematic.bSendServerNotify = false; + cinematic.bUseControlledObjectForAudioListener = false; + cinematic.endBehavior = eEndBehavior::RETURN; + cinematic.hidePlayerDuringCine = false; + cinematic.leadIn = 2.0f; + cinematic.Send(player->GetSystemAddress()); } object->SetVar(u"PlayerID", LWOOBJID_EMPTY); @@ -56,7 +67,7 @@ void ActParadoxPipeFix::OnQuickBuildNotifyState(Entity* self, eQuickBuildState s const auto refinery = Game::entityManager->GetEntitiesInGroup("Paradox"); if (!refinery.empty()) { - GameMessages::SendStopFXEffect(refinery[0], true, "pipeFX"); + GameMessages::StopFXEffect(refinery[0]->GetObjectID(), true, "pipeFX").Send(UNASSIGNED_SYSTEM_ADDRESS); } } } diff --git a/dScripts/ai/FV/FvFacilityBrick.cpp b/dScripts/ai/FV/FvFacilityBrick.cpp index 1402991c4..10815de92 100644 --- a/dScripts/ai/FV/FvFacilityBrick.cpp +++ b/dScripts/ai/FV/FvFacilityBrick.cpp @@ -1,5 +1,6 @@ #include "FvFacilityBrick.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "dZoneManager.h" #include "EntityManager.h" @@ -17,43 +18,43 @@ void FvFacilityBrick::OnNotifyObject(Entity* self, Entity* sender, const std::st auto* const canisterSpawner = canisterObjs.empty() ? nullptr : canisterObjs[0]; if (name == "ConsoleLeftUp") { - GameMessages::SendStopFXEffect(self, true, "LeftPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2775, u"create", "LeftPipeEnergy"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "LeftPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2775, u"create", "LeftPipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (name == "ConsoleLeftDown") { self->SetVar(u"ConsoleLEFTActive", false); - GameMessages::SendStopFXEffect(self, true, "LeftPipeEnergy"); - GameMessages::SendStopFXEffect(self, true, "LeftPipeOn"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "LeftPipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::StopFXEffect(self->GetObjectID(), true, "LeftPipeOn").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (name == "ConsoleLeftActive") { self->SetVar(u"ConsoleLEFTActive", true); - GameMessages::SendStopFXEffect(self, true, "LeftPipeEnergy"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2776, u"create", "LeftPipeOn"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "LeftPipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2776, u"create", "LeftPipeOn").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (name == "ConsoleRightUp") { - GameMessages::SendStopFXEffect(self, true, "RightPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2778, u"create", "RightPipeEnergy"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "RightPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2778, u"create", "RightPipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (name == "ConsoleRightDown") { self->SetVar(u"ConsoleRIGHTActive", false); - GameMessages::SendStopFXEffect(self, true, "RightPipeEnergy"); - GameMessages::SendStopFXEffect(self, true, "RightPipeOn"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "RightPipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::StopFXEffect(self->GetObjectID(), true, "RightPipeOn").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (name == "ConsoleRightActive") { self->SetVar(u"ConsoleRIGHTActive", true); - GameMessages::SendStopFXEffect(self, true, "RightPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2779, u"create", "RightPipeEnergy"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "RightPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2779, u"create", "RightPipeEnergy").Send(UNASSIGNED_SYSTEM_ADDRESS); } if (self->GetVar(u"ConsoleLEFTActive") && self->GetVar(u"ConsoleRIGHTActive")) { auto* object = Game::entityManager->GetEntitiesInGroup("Brick")[0]; if (object != nullptr) { - GameMessages::SendPlayFXEffect(object->GetObjectID(), 122, u"create", "bluebrick"); - GameMessages::SendPlayFXEffect(object->GetObjectID(), 1034, u"cast", "imaginationexplosion"); + GameMessages::PlayFXEffect(object->GetObjectID(), 122, u"create", "bluebrick").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(object->GetObjectID(), 1034, u"cast", "imaginationexplosion").Send(UNASSIGNED_SYSTEM_ADDRESS); } object = Game::entityManager->GetEntitiesInGroup("Canister")[0]; @@ -70,7 +71,7 @@ void FvFacilityBrick::OnNotifyObject(Entity* self, Entity* sender, const std::st auto* object = Game::entityManager->GetEntitiesInGroup("Brick")[0]; if (object != nullptr) { - GameMessages::SendStopFXEffect(object, true, "bluebrick"); + GameMessages::StopFXEffect(object->GetObjectID(), true, "bluebrick").Send(UNASSIGNED_SYSTEM_ADDRESS); } if (bugSpawner) { @@ -101,8 +102,8 @@ void FvFacilityBrick::OnFireEventServerSide(Entity* self, Entity* sender, std::s return; } - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2750, u"create", "imagination_canister"); - GameMessages::SendPlayFXEffect(self->GetObjectID(), 2751, u"create", "canister_light_filler"); + GameMessages::PlayFXEffect(self->GetObjectID(), 2774, u"create", "LeftPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2777, u"create", "RightPipeOff").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2750, u"create", "imagination_canister").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), 2751, u"create", "canister_light_filler").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/FV/FvFacilityPipes.cpp b/dScripts/ai/FV/FvFacilityPipes.cpp index dd35ffe1d..a01c4a8e2 100644 --- a/dScripts/ai/FV/FvFacilityPipes.cpp +++ b/dScripts/ai/FV/FvFacilityPipes.cpp @@ -1,10 +1,11 @@ #include "FvFacilityPipes.h" #include "GameMessages.h" +#include "EffectsMessages.h" void FvFacilityPipes::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == "startFX") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), m_LeftPipeEffectID, m_EffectType, m_LeftPipeEffectName); - GameMessages::SendPlayFXEffect(self->GetObjectID(), m_RightPipeEffectID, m_EffectType, m_RightPipeEffectName); - GameMessages::SendPlayFXEffect(self->GetObjectID(), m_ImaginationCanisterEffectID, m_EffectType, m_ImaginationCanisterEffectName); + GameMessages::PlayFXEffect(self->GetObjectID(), m_LeftPipeEffectID, m_EffectType, m_LeftPipeEffectName).Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), m_RightPipeEffectID, m_EffectType, m_RightPipeEffectName).Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayFXEffect(self->GetObjectID(), m_ImaginationCanisterEffectID, m_EffectType, m_ImaginationCanisterEffectName).Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/ai/GENERAL/ForceFieldEffect.cpp b/dScripts/ai/GENERAL/ForceFieldEffect.cpp index 62d0eeb82..71dd4409c 100644 --- a/dScripts/ai/GENERAL/ForceFieldEffect.cpp +++ b/dScripts/ai/GENERAL/ForceFieldEffect.cpp @@ -2,9 +2,10 @@ #include "Entity.h" #include "GameMessages.h" +#include "EffectsMessages.h" void ForceFieldEffect::OnCollisionPhantom(Entity* self, Entity* target) { if (!target) return; - GameMessages::SendPlayFXEffect(target, 3671, u"cast", "", LWOOBJID_EMPTY); + GameMessages::PlayFXEffect(target->GetObjectID(), 3671, u"cast", "").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp index 667f41bd2..00792dcfd 100644 --- a/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp +++ b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp @@ -1,5 +1,6 @@ #include "InstanceExitTransferPlayerToLastNonInstance.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "CharacterComponent.h" #include "Character.h" #include "dServer.h" @@ -10,16 +11,15 @@ void InstanceExitTransferPlayerToLastNonInstance::OnUse(Entity* self, Entity* us if (transferText.empty()) transferText = u"DRAGON_EXIT_QUESTION"; - GameMessages::SendDisplayMessageBox( - user->GetObjectID(), - true, - self->GetObjectID(), - u"Instance_Exit", - 1, - transferText, - u"", - user->GetSystemAddress() - ); + GameMessages::DisplayMessageBox messageBox; + messageBox.target = user->GetObjectID(); + messageBox.bShow = true; + messageBox.callbackClient = self->GetObjectID(); + messageBox.identifier = u"Instance_Exit"; + messageBox.imageID = 1; + messageBox.text = transferText; + messageBox.userData = u""; + messageBox.Send(user->GetSystemAddress()); } void InstanceExitTransferPlayerToLastNonInstance::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { diff --git a/dScripts/ai/GF/GfOrgan.cpp b/dScripts/ai/GF/GfOrgan.cpp index 3184aa829..007e4c365 100644 --- a/dScripts/ai/GF/GfOrgan.cpp +++ b/dScripts/ai/GF/GfOrgan.cpp @@ -1,5 +1,6 @@ #include "GfOrgan.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Entity.h" #include "RenderComponent.h" @@ -9,7 +10,7 @@ void GfOrgan::OnUse(Entity* self, Entity* user) { return; } - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, "{15d5f8bd-139a-4c31-8904-970c480cd70f}"); + GameMessages::PlayNDAudioEmitter(self->GetObjectID(), "{15d5f8bd-139a-4c31-8904-970c480cd70f}").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetBoolean(u"bIsInUse", true); self->AddTimer("reset", 5.0f); diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index e33b857a9..93a61eb93 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -1,6 +1,7 @@ #include "SGCannon.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "ActivityMessages.h" #include "dZoneManager.h" #include "Character.h" @@ -132,10 +133,15 @@ void SGCannon::OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button if (!player) return; if (identifier == u"Scoreboardinfo") { - GameMessages::SendDisplayMessageBox(player->GetObjectID(), true, - Game::zoneManager->GetZoneControlObject()->GetObjectID(), - u"Shooting_Gallery_Retry", 2, u"Retry?", - u"", player->GetSystemAddress()); + GameMessages::DisplayMessageBox messageBox; + messageBox.target = player->GetObjectID(); + messageBox.bShow = true; + messageBox.callbackClient = Game::zoneManager->GetZoneControlObject()->GetObjectID(); + messageBox.identifier = u"Shooting_Gallery_Retry"; + messageBox.imageID = 2; + messageBox.text = u"Retry?"; + messageBox.userData = u""; + messageBox.Send(player->GetSystemAddress()); } else { if ((button == 1 && (identifier == u"Shooting_Gallery_Retry" || identifier == u"RePlay")) || identifier == u"SG1" || button == 0) { if (IsPlayerInActivity(self, player->GetObjectID())) return; @@ -187,7 +193,7 @@ void SGCannon::SpawnWaveTimerFunc(Entity* self) { const auto* player = Game::entityManager->GetEntity(self->GetVar(PlayerIDVariable)); if (player != nullptr) { - GameMessages::SendPlayFXEffect(player->GetObjectID(), -1, u"SG-start", ""); + GameMessages::PlayFXEffect(player->GetObjectID(), -1, u"SG-start", "").Send(UNASSIGNED_SYSTEM_ADDRESS); GameMessages::StartActivityTime startActivityTime; startActivityTime.target = self->GetObjectID(); @@ -362,7 +368,7 @@ void SGCannon::StartGame(Entity* self) { activityStart.target = self->GetObjectID(); activityStart.Send(player->GetSystemAddress()); - GameMessages::SendPlayFXEffect(self->GetObjectID(), -1, u"start", ""); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"start", "").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetNetworkVar(ClearVariable, true); DoGameStartup(self); diff --git a/dScripts/ai/NP/NpcNpJetpackGuy.cpp b/dScripts/ai/NP/NpcNpJetpackGuy.cpp index 0e772ad1b..582b7c53c 100644 --- a/dScripts/ai/NP/NpcNpJetpackGuy.cpp +++ b/dScripts/ai/NP/NpcNpJetpackGuy.cpp @@ -2,8 +2,9 @@ #include "Entity.h" #include "GameMessages.h" +#include "EffectsMessages.h" void NpcNpJetpackGuy::OnUse(Entity* self, Entity* user) { // No effect ID, the client plays the object's own effect of this type. - GameMessages::SendPlayFXEffect(self, -1, u"launch", "", LWOOBJID_EMPTY); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"launch", "").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/NS/NsConcertInstrument.cpp b/dScripts/ai/NS/NsConcertInstrument.cpp index d1b259183..3f910ef37 100644 --- a/dScripts/ai/NS/NsConcertInstrument.cpp +++ b/dScripts/ai/NS/NsConcertInstrument.cpp @@ -1,5 +1,6 @@ #include "NsConcertInstrument.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "Item.h" #include "DestroyableComponent.h" #include "EntityManager.h" @@ -121,7 +122,10 @@ void NsConcertInstrument::StartPlayingInstrument(Entity* self, Entity* player) { EquipInstruments(self, player); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"startPlaying", 0, 0, player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendPlayCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlayCinematic cinematic; + cinematic.target = player->GetObjectID(); + cinematic.pathName = cinematics.at(instrumentLot); + cinematic.Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddCallbackTimer(1.0f, [player, instrumentLot]() { RenderComponent::PlayAnimation(player, animations.at(instrumentLot), 2.0f); }); @@ -153,7 +157,11 @@ void NsConcertInstrument::StopPlayingInstrument(Entity* self, Entity* player) { missions->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } - GameMessages::SendEndCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS, 1.0f); + GameMessages::EndCinematic endCinematic; + endCinematic.target = player->GetObjectID(); + endCinematic.pathName = cinematics.at(instrumentLot); + endCinematic.leadOut = 1.0f; + endCinematic.Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(player, smashAnimations.at(instrumentLot), 2.0f); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stopCheckingMovement", 0, 0, player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); diff --git a/dScripts/ai/NS/NsConcertQuickBuild.cpp b/dScripts/ai/NS/NsConcertQuickBuild.cpp index 2278eb5c2..3fb1d539b 100644 --- a/dScripts/ai/NS/NsConcertQuickBuild.cpp +++ b/dScripts/ai/NS/NsConcertQuickBuild.cpp @@ -3,6 +3,7 @@ #include "NsConcertChoiceBuildManager.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MovingPlatformComponent.h" #include "MissionComponent.h" @@ -206,8 +207,7 @@ void NsConcertQuickBuild::UpdateEffects(Entity* self) { for (const auto& effectName : setIterator->second.effects) { const auto effectObjects = Game::entityManager->GetEntitiesInGroup(quickBuildFX.at(effectName)); for (auto* effectObject : effectObjects) { - GameMessages::SendPlayFXEffect(effectObject, 0, GeneralUtils::ASCIIToUTF16(effectName), - effectName + "Effect", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(effectObject->GetObjectID(), 0, GeneralUtils::ASCIIToUTF16(effectName), effectName + "Effect").Send(UNASSIGNED_SYSTEM_ADDRESS); } } } @@ -220,7 +220,7 @@ void NsConcertQuickBuild::CancelEffects(Entity* self) { for (const auto& effectName : setIterator->second.effects) { const auto effectObjects = Game::entityManager->GetEntitiesInGroup(quickBuildFX.at(effectName)); for (auto* effectObject : effectObjects) { - GameMessages::SendStopFXEffect(effectObject, true, effectName + "Effect"); + GameMessages::StopFXEffect(effectObject->GetObjectID(), true, effectName + "Effect").Send(UNASSIGNED_SYSTEM_ADDRESS); } } } diff --git a/dScripts/ai/NS/NsGetFactionMissionServer.cpp b/dScripts/ai/NS/NsGetFactionMissionServer.cpp index d395cfd89..cf8655d31 100644 --- a/dScripts/ai/NS/NsGetFactionMissionServer.cpp +++ b/dScripts/ai/NS/NsGetFactionMissionServer.cpp @@ -1,5 +1,6 @@ #include "NsGetFactionMissionServer.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "MissionComponent.h" #include "Character.h" #include "eReplicaComponentType.h" @@ -38,7 +39,10 @@ void NsGetFactionMissionServer::OnRespondToMission(Entity* self, int missionID, factionMissions.push_back(778); if (celebrationID != -1) { - GameMessages::SendStartCelebrationEffect(player, player->GetSystemAddress(), celebrationID); + GameMessages::StartCelebrationEffect celebration; + celebration.target = player->GetObjectID(); + celebration.celebrationID = celebrationID; + celebration.SendToClient(player->GetSystemAddress()); } if (flagID != -1) { diff --git a/dScripts/ai/NS/WH/RockHydrantBroken.cpp b/dScripts/ai/NS/WH/RockHydrantBroken.cpp index bb4484258..887254219 100644 --- a/dScripts/ai/NS/WH/RockHydrantBroken.cpp +++ b/dScripts/ai/NS/WH/RockHydrantBroken.cpp @@ -2,6 +2,7 @@ #include "PetMessages.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EffectsMessages.h" void RockHydrantBroken::OnStartup(Entity* self) { self->AddTimer("playEffect", 1); @@ -40,6 +41,6 @@ void RockHydrantBroken::OnTimerDone(Entity* self, std::string timerName) { self->Kill(); } else if (timerName == "playEffect") { - GameMessages::SendPlayFXEffect(self->GetObjectID(), 4737, u"water", "water", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), 4737, u"water", "water").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp b/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp index 86c2c1599..0542c9492 100644 --- a/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp +++ b/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp @@ -7,6 +7,7 @@ #include "MissionComponent.h" #include "Item.h" #include "eMissionState.h" +#include "EffectsMessages.h" void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* character = target->GetCharacter(); @@ -17,7 +18,10 @@ void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionI if (missionID == 768 && missionState == eMissionState::AVAILABLE) { // Players who have not touched the orb yet get a camera pan showing where it is. if (character && !character->GetPlayerFlag(71)) { - GameMessages::SendPlayCinematic(target->GetObjectID(), u"MissionCam", target->GetSystemAddress()); + GameMessages::PlayCinematic cinematic; + cinematic.target = target->GetObjectID(); + cinematic.pathName = u"MissionCam"; + cinematic.Send(target->GetSystemAddress()); } } else if (missionID == 768 && missionState >= eMissionState::READY_TO_COMPLETE) { //remove the inventory items diff --git a/dScripts/ai/PROPERTY/AgPropguards.cpp b/dScripts/ai/PROPERTY/AgPropguards.cpp index ced7dd688..7d88c3790 100644 --- a/dScripts/ai/PROPERTY/AgPropguards.cpp +++ b/dScripts/ai/PROPERTY/AgPropguards.cpp @@ -1,6 +1,7 @@ #include "AgPropguards.h" #include "Character.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "eMissionState.h" @@ -17,7 +18,10 @@ void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int mission if ((missionState == eMissionState::AVAILABLE || missionState == eMissionState::ACTIVE) && !character->GetPlayerFlag(flag)) { // If the player just started the mission, play a cinematic highlighting the target - GameMessages::SendPlayCinematic(target->GetObjectID(), u"MissionCam", target->GetSystemAddress()); + GameMessages::PlayCinematic cinematic; + cinematic.target = target->GetObjectID(); + cinematic.pathName = u"MissionCam"; + cinematic.Send(target->GetSystemAddress()); } else if (missionState == eMissionState::READY_TO_COMPLETE) { // Makes the guard disappear once the mission has been completed const auto zoneControlID = Game::entityManager->GetZoneControlEntity()->GetObjectID(); diff --git a/dScripts/ai/SPEC/SpecialCoinSpawner.cpp b/dScripts/ai/SPEC/SpecialCoinSpawner.cpp index ff494845e..b0e29eb99 100644 --- a/dScripts/ai/SPEC/SpecialCoinSpawner.cpp +++ b/dScripts/ai/SPEC/SpecialCoinSpawner.cpp @@ -1,5 +1,6 @@ #include "SpecialCoinSpawner.h" #include "CharacterComponent.h" +#include "EffectsMessages.h" void SpecialCoinSpawner::OnStartup(Entity* self) { self->SetProximityRadius(1.5f, "powerupEnter"); @@ -10,7 +11,7 @@ void SpecialCoinSpawner::OnProximityUpdate(Entity* self, Entity* entering, const if (!entering->IsPlayer()) return; auto character = entering->GetCharacter(); if (!character) return; - GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"pickup", "").Send(UNASSIGNED_SYSTEM_ADDRESS); character->SetCoins(character->GetCoins() + this->m_CurrencyDenomination, eLootSourceType::CURRENCY); self->Smash(entering->GetObjectID(), eKillType::SILENT); } diff --git a/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp b/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp index 72565923b..44e71155b 100644 --- a/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp +++ b/dScripts/ai/SPEC/SpecialPowerupSpawner.cpp @@ -1,6 +1,7 @@ #include "SpecialPowerupSpawner.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "SkillComponent.h" #include "EntityManager.h" #include "eReplicaComponentType.h" @@ -15,7 +16,7 @@ void SpecialPowerupSpawner::OnProximityUpdate(Entity* self, Entity* entering, co if (!entering->IsPlayer()) return; if (self->GetVar(u"bIsDead")) return; - GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"pickup", "").Send(UNASSIGNED_SYSTEM_ADDRESS); auto skillComponent = self->GetComponent(); if (!skillComponent) return; diff --git a/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp b/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp index d31098061..6e8045957 100644 --- a/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp +++ b/dScripts/ai/SPEC/SpecialSpeedBuffSpawner.cpp @@ -1,6 +1,7 @@ #include "SpecialSpeedBuffSpawner.h" #include "GameMessages.h" +#include "EffectsMessages.h" #include "SkillComponent.h" #include "EntityManager.h" #include "eReplicaComponentType.h" @@ -15,7 +16,7 @@ void SpecialSpeedBuffSpawner::OnProximityUpdate(Entity* self, Entity* entering, if (!entering->IsPlayer()) return; if (self->GetVar(u"bIsDead")) return; - GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"pickup", "").Send(UNASSIGNED_SYSTEM_ADDRESS); auto skillComponent = entering->GetComponent(); if (!skillComponent) return; diff --git a/dScripts/ai/WILD/LupGenericInteract.cpp b/dScripts/ai/WILD/LupGenericInteract.cpp index 95eb7a96f..db824a3eb 100644 --- a/dScripts/ai/WILD/LupGenericInteract.cpp +++ b/dScripts/ai/WILD/LupGenericInteract.cpp @@ -1,6 +1,7 @@ #include "LupGenericInteract.h" #include "GameMessages.h" +#include "EffectsMessages.h" void LupGenericInteract::OnUse(Entity* self, Entity* user) { - GameMessages::SendPlayAnimation(self, u"interact"); + GameMessages::PlayAnimation(self->GetObjectID(), u"interact").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/WILD/WildAmbientCrab.cpp b/dScripts/ai/WILD/WildAmbientCrab.cpp index 7b5b3d45c..78575bc04 100644 --- a/dScripts/ai/WILD/WildAmbientCrab.cpp +++ b/dScripts/ai/WILD/WildAmbientCrab.cpp @@ -1,27 +1,28 @@ #include "WildAmbientCrab.h" #include "GameMessages.h" +#include "EffectsMessages.h" void WildAmbientCrab::OnStartup(Entity* self){ self->SetVar(u"flipped", true); - GameMessages::SendPlayAnimation(self, u"idle"); + GameMessages::PlayAnimation(self->GetObjectID(), u"idle").Send(UNASSIGNED_SYSTEM_ADDRESS); } void WildAmbientCrab::OnUse(Entity* self, Entity* user) { auto flipped = self->GetVar(u"flipped"); if (flipped) { self->AddTimer("Flipping", 0.6f); - GameMessages::SendPlayAnimation(self, u"flip-over"); + GameMessages::PlayAnimation(self->GetObjectID(), u"flip-over").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"flipped", false); } else if (!flipped) { self->AddTimer("Flipback", 0.8f); - GameMessages::SendPlayAnimation(self, u"flip-back"); + GameMessages::PlayAnimation(self->GetObjectID(), u"flip-back").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"flipped", true); } } void WildAmbientCrab::OnTimerDone(Entity* self, std::string timerName) { - if (timerName == "Flipping") GameMessages::SendPlayAnimation(self, u"over-idle"); - else if (timerName == "Flipback") GameMessages::SendPlayAnimation(self, u"idle"); + if (timerName == "Flipping") GameMessages::PlayAnimation(self->GetObjectID(), u"over-idle").Send(UNASSIGNED_SYSTEM_ADDRESS); + else if (timerName == "Flipback") GameMessages::PlayAnimation(self->GetObjectID(), u"idle").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/WILD/WildAndScared.cpp b/dScripts/ai/WILD/WildAndScared.cpp index d2e89c40d..647f2c820 100644 --- a/dScripts/ai/WILD/WildAndScared.cpp +++ b/dScripts/ai/WILD/WildAndScared.cpp @@ -1,6 +1,7 @@ #include "WildAndScared.h" #include "GameMessages.h" +#include "EffectsMessages.h" void WildAndScared::OnUse(Entity* self, Entity* user) { - GameMessages::SendPlayAnimation(self, u"scared"); + GameMessages::PlayAnimation(self->GetObjectID(), u"scared").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/WILD/WildGfGlowbug.cpp b/dScripts/ai/WILD/WildGfGlowbug.cpp index d834f5b5d..f346d00fe 100644 --- a/dScripts/ai/WILD/WildGfGlowbug.cpp +++ b/dScripts/ai/WILD/WildGfGlowbug.cpp @@ -1,5 +1,6 @@ #include "WildGfGlowbug.h" #include "GameMessages.h" +#include "EffectsMessages.h" void WildGfGlowbug::OnStartup(Entity* self){ self->SetVar(u"switch", false); @@ -9,9 +10,9 @@ void WildGfGlowbug::OnFireEventServerSide(Entity* self, Entity* sender, std::str if (args == "physicsReady") { auto switchState = self->GetVar(u"switch"); if (!switchState) { - GameMessages::SendStopFXEffect(self, true, "glowlight"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "glowlight").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (switchState) { - GameMessages::SendPlayFXEffect(self, -1, u"light", "glowlight", LWOOBJID_EMPTY); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"light", "glowlight").Send(UNASSIGNED_SYSTEM_ADDRESS); } } } @@ -19,10 +20,10 @@ void WildGfGlowbug::OnFireEventServerSide(Entity* self, Entity* sender, std::str void WildGfGlowbug::OnUse(Entity* self, Entity* user) { auto switchState = self->GetVar(u"switch"); if (switchState) { - GameMessages::SendStopFXEffect(self, true, "glowlight"); + GameMessages::StopFXEffect(self->GetObjectID(), true, "glowlight").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"switch", false); } else if (!switchState) { - GameMessages::SendPlayFXEffect(self, -1, u"light", "glowlight", LWOOBJID_EMPTY); + GameMessages::PlayFXEffect(self->GetObjectID(), -1, u"light", "glowlight").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"switch", true); } } diff --git a/dScripts/ai/WILD/WildNinjaBricks.cpp b/dScripts/ai/WILD/WildNinjaBricks.cpp index 4fa65b010..d0f10c053 100644 --- a/dScripts/ai/WILD/WildNinjaBricks.cpp +++ b/dScripts/ai/WILD/WildNinjaBricks.cpp @@ -1,13 +1,14 @@ #include "WildNinjaBricks.h" #include "Entity.h" +#include "EffectsMessages.h" void WildNinjaBricks::OnStartup(Entity* self) { self->AddToGroup("Ninjastuff"); } void WildNinjaBricks::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { - if (name == "Crane") GameMessages::SendPlayAnimation(self, u"crane"); - else if (name == "Tiger") GameMessages::SendPlayAnimation(self, u"tiger"); - else if (name == "Mantis") GameMessages::SendPlayAnimation(self, u"mantis"); + if (name == "Crane") GameMessages::PlayAnimation(self->GetObjectID(), u"crane").Send(UNASSIGNED_SYSTEM_ADDRESS); + else if (name == "Tiger") GameMessages::PlayAnimation(self->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); + else if (name == "Mantis") GameMessages::PlayAnimation(self->GetObjectID(), u"mantis").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/WILD/WildNinjaSensei.cpp b/dScripts/ai/WILD/WildNinjaSensei.cpp index 0941e41c1..7071cd06c 100644 --- a/dScripts/ai/WILD/WildNinjaSensei.cpp +++ b/dScripts/ai/WILD/WildNinjaSensei.cpp @@ -1,8 +1,9 @@ #include "WildNinjaSensei.h" #include "Entity.h" +#include "EffectsMessages.h" void WildNinjaSensei::OnStartup(Entity* self) { - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("CraneStart", 5); } @@ -12,25 +13,25 @@ void WildNinjaSensei::OnTimerDone(Entity* self, std::string timerName) { for (auto ninja : ninjas) ninja->NotifyObject(self, "Crane"); self->AddTimer("Bow", 15.5f); self->AddTimer("TigerStart", 25); - GameMessages::SendPlayAnimation(self, u"crane"); + GameMessages::PlayAnimation(self->GetObjectID(), u"crane").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "TigerStart") { auto ninjas = Game::entityManager->GetEntitiesInGroup("Ninjastuff"); - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto ninja : ninjas) ninja->NotifyObject(self, "Tiger"); self->AddTimer("Bow", 15.5f); self->AddTimer("MantisStart", 25); - GameMessages::SendPlayAnimation(self, u"tiger"); + GameMessages::PlayAnimation(self->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "MantisStart") { auto ninjas = Game::entityManager->GetEntitiesInGroup("Ninjastuff"); - GameMessages::SendPlayAnimation(self, u"tiger"); + GameMessages::PlayAnimation(self->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); for (auto ninja : ninjas) ninja->NotifyObject(self, "Mantis"); self->AddTimer("Bow", 15.5f); self->AddTimer("CraneStart", 25); - GameMessages::SendPlayAnimation(self, u"mantis"); + GameMessages::PlayAnimation(self->GetObjectID(), u"mantis").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "Bow") { auto ninjas = Game::entityManager->GetEntitiesInGroup("Ninjastuff"); for (auto ninja : ninjas) ninja->NotifyObject(self, "Bow"); - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/ai/WILD/WildNinjaStudent.cpp b/dScripts/ai/WILD/WildNinjaStudent.cpp index b7e2f5852..9a8e4d401 100644 --- a/dScripts/ai/WILD/WildNinjaStudent.cpp +++ b/dScripts/ai/WILD/WildNinjaStudent.cpp @@ -1,14 +1,15 @@ #include "WildNinjaStudent.h" #include "GameMessages.h" +#include "EffectsMessages.h" void WildNinjaStudent::OnStartup(Entity* self) { self->AddToGroup("Ninjastuff"); - GameMessages::SendPlayAnimation(self, u"bow"); + GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); } void WildNinjaStudent::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { - if (name == "Crane") GameMessages::SendPlayAnimation(self, u"crane"); - else if (name == "Tiger") GameMessages::SendPlayAnimation(self, u"tiger"); - else if (name == "Mantis") GameMessages::SendPlayAnimation(self, u"mantis"); - else if (name == "Bow") GameMessages::SendPlayAnimation(self, u"bow"); + if (name == "Crane") GameMessages::PlayAnimation(self->GetObjectID(), u"crane").Send(UNASSIGNED_SYSTEM_ADDRESS); + else if (name == "Tiger") GameMessages::PlayAnimation(self->GetObjectID(), u"tiger").Send(UNASSIGNED_SYSTEM_ADDRESS); + else if (name == "Mantis") GameMessages::PlayAnimation(self->GetObjectID(), u"mantis").Send(UNASSIGNED_SYSTEM_ADDRESS); + else if (name == "Bow") GameMessages::PlayAnimation(self->GetObjectID(), u"bow").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/WILD/WildPants.cpp b/dScripts/ai/WILD/WildPants.cpp index 7c5e1cd24..4f141964f 100644 --- a/dScripts/ai/WILD/WildPants.cpp +++ b/dScripts/ai/WILD/WildPants.cpp @@ -1,10 +1,11 @@ #include "WildPants.h" #include "GameMessages.h" +#include "EffectsMessages.h" void WildPants::OnStartup(Entity* self) { self->SetProximityRadius(5, "scardyPants"); } void WildPants::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { - if (status == "ENTER") GameMessages::SendPlayAnimation(self, u"scared"); + if (status == "ENTER") GameMessages::PlayAnimation(self->GetObjectID(), u"scared").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index f03e2dec4..27c7f9367 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -99,6 +99,7 @@ #include "Item.h" #include "eFunnessTypes.h" #include "WorldMigration.h" +#include "EffectsMessages.h" namespace Game { Logger* logger = nullptr; @@ -621,7 +622,10 @@ namespace { args.Insert("title", announcement.title); args.Insert("message", announcement.message); - GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleAnnounce"; + uiMessage.args = std::move(args); + uiMessage.Send(UNASSIGNED_SYSTEM_ADDRESS); }); handlers.On(MessageType::Chat::GM_MUTE, [](const ChatPackets::GMMute& mute, const SystemAddress&) { @@ -1153,7 +1157,10 @@ namespace { args.Insert("title", Game::config->GetValue("cdclient_mismatch_title")); args.Insert("message", Game::config->GetValue("cdclient_mismatch_message")); - GameMessages::SendUIMessageServerToSingleClient("ToggleAnnounce", args, sysAddr); + GameMessages::UIMessageServerToAllClients uiMessage; + uiMessage.strMessageName = "ToggleAnnounce"; + uiMessage.args = std::move(args); + uiMessage.SendToClient(sysAddr); LOG("Account (%s) with GmLevel (%s) does not have a matching FDB, but is a developer and will skip this check." , username.GetAsString().c_str(), StringifiedEnum::ToString(accountInfo->maxGmLevel).data()); } @@ -1555,7 +1562,11 @@ namespace { data.Insert("Description3", Game::config->GetValue("help_3_description")); data.Insert("Description4", Game::config->GetValue("help_4_description")); - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "UIHelpTop5", data); + GameMessages::UIMessageServerToSingleClient uiMessage; + uiMessage.target = entity->GetObjectID(); + uiMessage.strMessageName = "UIHelpTop5"; + uiMessage.args = std::move(data); + uiMessage.SendToClient(sysAddr); } }; diff --git a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt index cf20079c8..a49e21d7a 100644 --- a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt +++ b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt @@ -3,6 +3,7 @@ SET(DGAMEMESSAGES_TESTS "BuildingMessagesTests.cpp" "GameMessageTests.cpp" "GameMsgSplitTests.cpp" + "EffectsMessagesTests.cpp" "MissionMessagesTests.cpp" "PetMessagesTests.cpp" "PropertyMessagesTests.cpp" diff --git a/tests/dGameTests/dGameMessagesTests/EffectsMessagesTests.cpp b/tests/dGameTests/dGameMessagesTests/EffectsMessagesTests.cpp new file mode 100644 index 000000000..6da338f70 --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/EffectsMessagesTests.cpp @@ -0,0 +1,571 @@ +#include "EffectsMessages.h" +#include "GameDependencies.h" +#include "GameMessageTestUtils.h" +#include "Legacy/EffectsMessagesLegacy.h" + +#include +#include +#include + +#include + +using namespace GameMessageTestUtils; + +namespace { + const std::vector g_Ints = { 0, 1, -1, 1727, std::numeric_limits::max(), std::numeric_limits::min() }; + const std::vector g_Floats = { 0.0f, 1.0f, -1.0f, 0.4f, 0.8f, 3.5f }; + const std::vector g_WStrings = { u"", u"a", u"camshake-bridge", u"été ☃", std::u16string(300, u'x') }; + const std::vector g_Strings = { "", "a", "{9a24f1fa-3177-4745-a2df-fbd996d6e1e3}", std::string(300, 'y') }; + const std::vector g_Ids = { LWOOBJID_EMPTY, 0x1000000000000001LL, -1 }; + + PacketBytes Payload(const GameMessages::NetGameMsg& msg) { + RakNet::BitStream bitStream; + msg.Serialize(bitStream); + return FromBitStream(bitStream); + } + + // Serializes msg, then reads it with the legacy read sequence; both must consume exactly the same bits. + template + Result ReadWithLegacy(const GameMessages::NetGameMsg& msg, const std::function& read) { + RakNet::BitStream wire; + msg.Serialize(wire); + RakNet::BitStream legacyStream(wire.GetData(), wire.GetNumberOfBytesUsed(), false); + auto result = read(legacyStream); + EXPECT_EQ(legacyStream.GetReadOffset(), wire.GetNumberOfBitsUsed()); + return result; + } + + // Round trip for messages carrying AMF arrays: the associative part is an unordered map, so a re-serialized + // copy may list the keys in another order. Checks every bit is consumed and returns the copy. + template + T AmfRoundTrip(const T& msg) { + RakNet::BitStream bitStream; + msg.Serialize(bitStream); + T copy; + EXPECT_TRUE(copy.Deserialize(bitStream)); + EXPECT_EQ(bitStream.GetNumberOfUnreadBits(), 0); + RakNet::BitStream again; + copy.Serialize(again); + EXPECT_EQ(again.GetNumberOfBitsUsed(), bitStream.GetNumberOfBitsUsed()); + return copy; + } + + // A few differently shaped AMF argument arrays (built fresh each time: AMFArrayValue is move only). + AMFArrayValue MakeArgs(const int variant) { + AMFArrayValue args; + if (variant == 1) { + args.Insert("visible", true); + args.Insert("text", "hello"); + } else if (variant == 2) { + args.Insert("state", "Lobby"); + args.Insert("amount", -5); + args.Insert("ratio", 0.25); + auto* nested = args.InsertArray("nested"); + nested->Push("one"); + nested->Push(false); + } + return args; + } +} + +class EffectsMessagesTests : public GameDependenciesTest { +protected: + void SetUp() override { SetUpDependencies(); } + void TearDown() override { TearDownDependencies(); } +}; + +TEST_F(EffectsMessagesTests, PlayAnimationMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto& animation : g_WStrings) { + for (const auto priority : g_Floats) { + for (const auto scale : g_Floats) { + GameMessages::PlayAnimation msg(target, animation); + msg.fPriority = priority; + msg.fScale = scale; + ExpectSameAsLegacy([&](const SystemAddress&) { LegacyGameMessages::SendPlayAnimation(&entity, animation, priority, scale); }, msg, SendMode::Broadcast); + if (animation == GeneralUtils::ASCIIToUTF16(GeneralUtils::UTF16ToWTF8(animation))) { + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.animationID, animation); + EXPECT_EQ(copy.fPriority, priority); + EXPECT_EQ(copy.fScale, scale); + } + } + } + } + } +} + +TEST_F(EffectsMessagesTests, PlayNDAudioEmitterMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto& guid : g_Strings) { + const GameMessages::PlayNDAudioEmitter msg(target, guid); + // The legacy function always broadcast, whatever address it was given. + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendPlayNDAudioEmitter(&entity, a, guid); }, msg, SendMode::Broadcast); + EXPECT_EQ(RoundTrip(msg).NDAudioEventGUID, guid); + } + } + GameMessages::PlayNDAudioEmitter full; + full.NDAudioCallbackMessageData = 5; + full.NDAudioEmitterID = 7; + full.NDAudioEventGUID = "guid"; + full.NDAudioMetaEventName = "meta"; + full.result = true; + full.targetObjectIDForNDAudioCallbackMessages = 9; + const auto copy = RoundTrip(full); + EXPECT_EQ(copy.NDAudioCallbackMessageData, 5); + EXPECT_EQ(copy.NDAudioEmitterID, 7); + EXPECT_EQ(copy.NDAudioMetaEventName, "meta"); + EXPECT_EQ(copy.targetObjectIDForNDAudioCallbackMessages, 9); + ExpectTruncatedFails(full); +} + +TEST_F(EffectsMessagesTests, PlayEmbeddedEffectMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto& effectName : g_WStrings) { + for (const auto from : g_Ids) { + for (const auto radius : g_Floats) { + GameMessages::PlayEmbeddedEffectOnAllClientsNearObject msg; + msg.target = target; + msg.effectName = effectName; + msg.fromObjectID = from; + msg.radius = radius; + ExpectSameAsLegacy([&](const SystemAddress&) { LegacyGameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(&entity, effectName, from, radius); }, msg, SendMode::Broadcast); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.effectName, effectName); + EXPECT_EQ(copy.fromObjectID, from); + EXPECT_EQ(copy.radius, radius); + } + } + } + } +} + +TEST_F(EffectsMessagesTests, PlayFXEffectMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto effectID : g_Ints) { + for (const auto& effectType : g_WStrings) { + for (const auto& name : g_Strings) { + for (const auto secondary : g_Ids) { + for (const auto priority : { 1.0f, 0.4f, 1.07f }) { + for (const auto scale : { 1.0f, 2.0f }) { + for (const bool serialize : { false, true }) { + GameMessages::PlayFXEffect msg(target, effectID, effectType, name); + msg.secondary = secondary; + msg.priority = priority; + msg.scale = scale; + msg.serialize = serialize; + ExpectSameAsLegacy([&](const SystemAddress&) { LegacyGameMessages::SendPlayFXEffect(target, effectID, effectType, name, secondary, priority, scale, serialize); }, msg, SendMode::Broadcast); + // The Entity* overload wrote the same thing. + ExpectSameAsLegacy([&](const SystemAddress&) { LegacyGameMessages::SendPlayFXEffect(&entity, effectID, effectType, name, secondary, priority, scale, serialize); }, msg, SendMode::Broadcast); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.effectID, effectID); + EXPECT_EQ(copy.effectType, effectType); + EXPECT_EQ(copy.name, name); + EXPECT_EQ(copy.secondary, secondary); + EXPECT_EQ(copy.priority, priority); + EXPECT_EQ(copy.scale, scale); + EXPECT_EQ(copy.serialize, serialize); + } + } + } + } + } + } + } + } +} + +TEST_F(EffectsMessagesTests, StopFXEffectMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const bool killImmediate : { false, true }) { + for (const auto& name : g_Strings) { + const GameMessages::StopFXEffect msg(target, killImmediate, name); + ExpectSameAsLegacy([&](const SystemAddress&) { LegacyGameMessages::SendStopFXEffect(&entity, killImmediate, name); }, msg, SendMode::Broadcast); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.killImmediate, killImmediate); + EXPECT_EQ(copy.name, name); + } + } + } +} + +TEST_F(EffectsMessagesTests, BroadcastTextToChatboxMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto& attrs : g_WStrings) { + for (const auto& text : g_WStrings) { + GameMessages::BroadcastTextToChatbox msg; + msg.target = target; + msg.attrs = attrs; + msg.wsText = text; + // The legacy function always broadcast. + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendBroadcastTextToChatbox(&entity, a, attrs, text); }, msg, SendMode::Broadcast); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.attrs, attrs); + EXPECT_EQ(copy.wsText, text); + } + } + } +} + +TEST_F(EffectsMessagesTests, AmbientSoundsMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto& guid : g_Strings) { + for (const bool result : { false, true }) { + GameMessages::Play2DAmbientSound play; + play.target = target; + play.audioGUID = guid; + play.result = result; + // Sent to the entity's own address (the test entity has none, so both send nothing to a client). + const auto legacyPlay = Capture([&] { LegacyGameMessages::SendPlay2DAmbientSound(&entity, guid, result); }); + const auto ourPlay = Capture([&] { play.SendToClient(entity.GetSystemAddress()); }); + ASSERT_EQ(legacyPlay.size(), 1); + ASSERT_EQ(ourPlay.size(), 1); + EXPECT_PACKET_EQ(FromCapture(legacyPlay[0]), FromCapture(ourPlay[0])); + EXPECT_EQ(legacyPlay[0].sysAddr, ourPlay[0].sysAddr); + EXPECT_EQ(legacyPlay[0].broadcast, ourPlay[0].broadcast); + const auto playCopy = RoundTrip(play); + EXPECT_EQ(playCopy.audioGUID, guid); + EXPECT_EQ(playCopy.result, result); + + for (const bool force : { false, true }) { + GameMessages::Stop2DAmbientSound stop; + stop.target = target; + stop.force = force; + stop.audioGUID = guid; + stop.result = result; + const auto legacyStop = Capture([&] { LegacyGameMessages::SendStop2DAmbientSound(&entity, force, guid, result); }); + const auto ourStop = Capture([&] { stop.SendToClient(entity.GetSystemAddress()); }); + ASSERT_EQ(legacyStop.size(), 1); + ASSERT_EQ(ourStop.size(), 1); + EXPECT_PACKET_EQ(FromCapture(legacyStop[0]), FromCapture(ourStop[0])); + EXPECT_EQ(legacyStop[0].sysAddr, ourStop[0].sysAddr); + const auto stopCopy = RoundTrip(stop); + EXPECT_EQ(stopCopy.force, force); + EXPECT_EQ(stopCopy.audioGUID, guid); + } + } + } + } +} + +TEST_F(EffectsMessagesTests, UIMessagesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const int variant : { 0, 1, 2 }) { + for (const auto& name : g_Strings) { + GameMessages::UIMessageServerToSingleClient single; + single.target = target; + single.args = MakeArgs(variant); + single.strMessageName = name; + auto legacyArgs = MakeArgs(variant); + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendUIMessageServerToSingleClient(&entity, a, name, legacyArgs); }, single, SendMode::SendToClient); + const auto singleCopy = AmfRoundTrip(single); + EXPECT_EQ(singleCopy.strMessageName, name); + EXPECT_EQ(singleCopy.args.GetAssociative().size(), single.args.GetAssociative().size()); + + // The "single client by address" overload sent UIMessageServerToAllClients with an empty target. + GameMessages::UIMessageServerToAllClients all; + all.args = MakeArgs(variant); + all.strMessageName = name; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendUIMessageServerToSingleClient(name, legacyArgs, a); }, all, SendMode::SendToClient); + // And the broadcast one. + ExpectSameAsLegacy([&](const SystemAddress&) { LegacyGameMessages::SendUIMessageServerToAllClients(name, legacyArgs); }, all, SendMode::Broadcast); + const auto allCopy = AmfRoundTrip(all); + EXPECT_EQ(allCopy.strMessageName, name); + EXPECT_EQ(allCopy.args.GetAssociative().size(), all.args.GetAssociative().size()); + EXPECT_EQ(allCopy.args.GetDense().size(), all.args.GetDense().size()); + } + } + } +} + +TEST_F(EffectsMessagesTests, StartCelebrationEffectMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto celebrationID : g_Ints) { + GameMessages::StartCelebrationEffect msg; + msg.target = target; + msg.celebrationID = celebrationID; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendStartCelebrationEffect(&entity, a, celebrationID); }, msg, SendMode::SendToClient); + EXPECT_EQ(RoundTrip(msg).celebrationID, celebrationID); + } + } + GameMessages::StartCelebrationEffect full; + full.animation = u"anim"; + full.backgroundObject = 1; + full.cameraPathLOT = 2; + full.celeLeadIn = 3.0f; + full.celeLeadOut = 4.0f; + full.celebrationID = 22; + full.duration = 5.0f; + full.iconID = 6; + full.mainText = u"main"; + full.mixerProgram = "mixer"; + full.musicCue = "cue"; + full.pathNodeName = "node"; + full.soundGUID = "sound"; + full.subText = u"sub"; + const auto copy = RoundTrip(full); + EXPECT_EQ(copy.backgroundObject, 1); + EXPECT_EQ(copy.cameraPathLOT, 2); + EXPECT_EQ(copy.celeLeadOut, 4.0f); + EXPECT_EQ(copy.subText, u"sub"); + ExpectTruncatedFails(full); +} + +TEST_F(EffectsMessagesTests, MessageBoxAndChatBubbleMatchLegacy) { + for (const auto target : g_Targets) { + for (const bool show : { false, true }) { + for (const auto callback : g_Ids) { + for (const auto& identifier : g_WStrings) { + for (const auto imageID : g_Ints) { + GameMessages::DisplayMessageBox msg; + msg.target = target; + msg.bShow = show; + msg.callbackClient = callback; + msg.identifier = identifier; + msg.imageID = imageID; + msg.text = identifier + u"!"; + msg.userData = u"data"; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendDisplayMessageBox(target, show, callback, identifier, imageID, identifier + u"!", u"data", a); }, msg); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.bShow, show); + EXPECT_EQ(copy.callbackClient, callback); + EXPECT_EQ(copy.identifier, identifier); + EXPECT_EQ(copy.imageID, imageID); + EXPECT_EQ(copy.text, identifier + u"!"); + EXPECT_EQ(copy.userData, u"data"); + } + } + } + } + for (const auto& text : g_WStrings) { + GameMessages::DisplayChatBubble bubble; + bubble.target = target; + bubble.wsText = text; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendDisplayChatBubble(target, text, a); }, bubble); + EXPECT_EQ(RoundTrip(bubble).wsText, text); + } + } +} + +TEST_F(EffectsMessagesTests, ChangeIdleFlagsMatchesLegacy) { + const auto flags = { eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, static_cast(0xFFFFFFFF) }; + for (const auto target : g_Targets) { + for (const auto on : flags) { + for (const auto off : flags) { + GameMessages::ChangeIdleFlags msg; + msg.target = target; + msg.flagsOn = on; + msg.flagsOff = off; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendChangeIdleFlags(target, on, off, a); }, msg, SendMode::Broadcast); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.flagsOn, on); + EXPECT_EQ(copy.flagsOff, off); + } + } + } +} + +TEST_F(EffectsMessagesTests, BillboardsMatchLegacy) { + for (const auto target : g_Targets) { + GameMessages::SetNameBillboardState state; + state.target = target; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendSetNamebillboardState(a, target); }, state); + GameMessages::ShowBillboardInteractIcon icon; + icon.target = target; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendShowBillboardInteractIcon(a, target); }, icon); + } +} + +TEST_F(EffectsMessagesTests, CinematicsMatchLegacy) { + const auto endBehaviors = { eEndBehavior::RETURN, eEndBehavior::WAIT }; + for (const auto target : g_Targets) { + for (const auto& path : g_WStrings) { + for (const auto leadIn : { -1.0f, 0.0f, 2.0f }) { + for (const auto endBehavior : endBehaviors) { + for (uint32_t bools = 0; bools < (1u << 10); bools += 37) { + const auto bit = [&](int i) { return ((bools >> i) & 1) != 0; }; + GameMessages::PlayCinematic msg; + msg.target = target; + msg.pathName = path; + msg.allowGhostUpdates = bit(0); + msg.bCloseMultiInteract = bit(1); + msg.bSendServerNotify = bit(2); + msg.bUseControlledObjectForAudioListener = bit(3); + msg.endBehavior = endBehavior; + msg.hidePlayerDuringCine = bit(4); + msg.leadIn = leadIn; + msg.leavePlayerLockedWhenFinished = bit(5); + msg.lockPlayer = bit(6); + msg.result = bit(7); + msg.skipIfSamePath = bit(8); + msg.startTimeAdvance = bit(9) ? 1.5f : 0.0f; + ExpectSameAsLegacy([&](const SystemAddress& a) { + LegacyGameMessages::SendPlayCinematic(target, path, a, bit(0), bit(1), bit(2), bit(3), endBehavior, bit(4), leadIn, bit(5), bit(6), bit(7), bit(8), bit(9) ? 1.5f : 0.0f); + }, msg); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.pathName, path); + EXPECT_EQ(copy.endBehavior, endBehavior); + EXPECT_EQ(copy.leadIn, leadIn); + EXPECT_EQ(copy.lockPlayer, bit(6)); + } + } + } + for (const auto leadOut : { -1.0f, 1.0f }) { + for (const bool locked : { false, true }) { + GameMessages::EndCinematic end; + end.target = target; + end.pathName = path; + end.leadOut = leadOut; + end.leavePlayerLocked = locked; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendEndCinematic(target, path, a, leadOut, locked); }, end); + const auto copy = RoundTrip(end); + EXPECT_EQ(copy.leadOut, leadOut); + EXPECT_EQ(copy.leavePlayerLocked, locked); + EXPECT_EQ(copy.pathName, path); + } + } + } + } +} + +TEST_F(EffectsMessagesTests, SlashCommandTextFeedbackMatchesLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto& text : g_WStrings) { + const GameMessages::SlashCommandTextFeedback msg(target, text); + const auto legacy = Capture([&] { LegacyGameMessages::SendSlashCommandFeedbackText(&entity, text); }); + const auto ours = Capture([&] { msg.SendToClient(entity.GetSystemAddress()); }); + ASSERT_EQ(legacy.size(), 1); + ASSERT_EQ(ours.size(), 1); + EXPECT_PACKET_EQ(FromCapture(legacy[0]), FromCapture(ours[0])); + EXPECT_EQ(legacy[0].sysAddr, ours[0].sysAddr); + EXPECT_EQ(RoundTrip(msg).text, text); + } + } +} + +TEST_F(EffectsMessagesTests, EmotesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto emoteID : g_Ints) { + for (const auto emoteTarget : g_Ids) { + GameMessages::PlayEmote msg; + msg.target = target; + msg.emoteID = emoteID; + msg.targetID = emoteTarget; + ExpectSameAsLegacy([&](const SystemAddress& a) { LegacyGameMessages::SendPlayEmote(target, emoteID, emoteTarget, a); }, msg); + const auto legacyRead = ReadWithLegacy(msg, LegacyGameMessages::ReadPlayEmote); + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.emoteID, legacyRead.emoteID); + EXPECT_EQ(copy.targetID, legacyRead.targetID); + ExpectTruncatedFails(msg); + } + for (const bool lock : { false, true }) { + GameMessages::SetEmoteLockState lockState; + lockState.target = target; + lockState.bLock = lock; + lockState.emoteID = emoteID; + const auto legacy = Capture([&] { LegacyGameMessages::SendSetEmoteLockState(&entity, lock, emoteID); }); + const auto ours = Capture([&] { lockState.SendToClient(entity.GetSystemAddress()); }); + ASSERT_EQ(legacy.size(), 1); + ASSERT_EQ(ours.size(), 1); + EXPECT_PACKET_EQ(FromCapture(legacy[0]), FromCapture(ours[0])); + const auto copy = RoundTrip(lockState); + EXPECT_EQ(copy.bLock, lock); + EXPECT_EQ(copy.emoteID, emoteID); + } + } + } +} + +TEST_F(EffectsMessagesTests, InboundReadsLikeLegacy) { + for (const auto button : g_Ints) { + for (const auto& identifier : g_WStrings) { + GameMessages::MessageBoxRespond box; + box.iButton = button; + box.identifier = identifier; + box.userData = u"user"; + const auto legacyBox = ReadWithLegacy(box, LegacyGameMessages::ReadMessageBoxResponse); + const auto boxCopy = RoundTrip(box); + EXPECT_TRUE(legacyBox.ok); + EXPECT_EQ(boxCopy.iButton, legacyBox.iButton); + EXPECT_EQ(boxCopy.identifier, legacyBox.identifier); + EXPECT_EQ(boxCopy.userData, legacyBox.userData); + ExpectTruncatedFails(box); + + GameMessages::ChoiceBoxRespond choice; + choice.buttonIdentifier = u"btn"; + choice.iButton = button; + choice.identifier = identifier; + const auto legacyChoice = ReadWithLegacy(choice, LegacyGameMessages::ReadChoiceBoxRespond); + const auto choiceCopy = RoundTrip(choice); + EXPECT_TRUE(legacyChoice.ok); + EXPECT_EQ(choiceCopy.buttonIdentifier, legacyChoice.buttonIdentifier); + EXPECT_EQ(choiceCopy.iButton, legacyChoice.iButton); + EXPECT_EQ(choiceCopy.identifier, legacyChoice.identifier); + ExpectTruncatedFails(choice); + } + } + + for (const auto event : { eCinematicEvent::STARTED, eCinematicEvent::WAYPOINT, eCinematicEvent::ENDED }) { + for (const auto time : { -1.0f, 0.0f, 2.5f }) { + for (const auto waypoint : { -1, 0, 3 }) { + for (const auto& path : g_WStrings) { + GameMessages::CinematicUpdate update; + update.event = event; + update.overallTime = time; + update.pathName = path; + update.pathTime = time * 2; + update.waypoint = waypoint; + const auto legacy = ReadWithLegacy(update, LegacyGameMessages::ReadCinematicUpdate); + const auto copy = RoundTrip(update); + EXPECT_EQ(copy.event, legacy.event); + EXPECT_EQ(copy.overallTime, legacy.overallTime); + EXPECT_EQ(copy.pathName, legacy.pathName); + EXPECT_EQ(copy.pathTime, legacy.pathTime); + EXPECT_EQ(copy.waypoint, legacy.waypoint); + ExpectTruncatedFails(update); + } + } + } + } + + // A length above MAX_MESSAGE_LENGTH is rejected, as the old handler did. + RakNet::BitStream tooLong; + tooLong.Write(0); + tooLong.Write(MAX_MESSAGE_LENGTH + 1); + GameMessages::MessageBoxRespond box; + EXPECT_FALSE(box.Deserialize(tooLong)); +} + +// Independent of the legacy code: hand computed payloads (RakNet writes MSB first). +TEST_F(EffectsMessagesTests, GoldenBytes) { + // effectID 7 (flag 1), "a" (u32 1, 0x61 0x00), scale default (0), "b" (u32 1, 0x62), priority default (0), + // secondary default (0), serialize true (1). + GameMessages::PlayFXEffect fx(0, 7, u"a", "b"); + EXPECT_PACKET_EQ(FromHex("83 80 00 00 00 80 00 00 30 80 00 40 00 00 18 88", 125), Payload(fx)); + + GameMessages::StopFXEffect stop(0, true, "ab"); + EXPECT_PACKET_EQ(FromHex("81 00 00 00 30 b1 00", 49), Payload(stop)); + + GameMessages::PlayAnimation animation(0, u"ab"); + // u32 2, "a\0b\0", then expect(1) immediate(0) complete(0) priority(0) scale(0) + EXPECT_PACKET_EQ(FromHex("02 00 00 00 61 00 62 00 80", 69), Payload(animation)); + + GameMessages::ChangeIdleFlags idle; + idle.flagsOn = static_cast(1); + // off default (0), on flag (1) then 01 00 00 00 + EXPECT_PACKET_EQ(FromHex("40 40 00 00 00", 34), Payload(idle)); + + GameMessages::EndCinematic end; + EXPECT_PACKET_EQ(FromHex("00 00 00 00 00", 34), Payload(end)); +} diff --git a/tests/dGameTests/dGameMessagesTests/GameMessageTestUtils.h b/tests/dGameTests/dGameMessagesTests/GameMessageTestUtils.h index 9cfccfb57..4a230f532 100644 --- a/tests/dGameTests/dGameMessagesTests/GameMessageTestUtils.h +++ b/tests/dGameTests/dGameMessagesTests/GameMessageTestUtils.h @@ -33,8 +33,10 @@ namespace GameMessageTestUtils { } // How the struct is sent in a comparison: Send (UNASSIGNED broadcasts; legacy functions that did - // "if (UNASSIGNED) SEND_PACKET_BROADCAST; SEND_PACKET;") or SendToClient (legacy functions with only SEND_PACKET). - enum class SendMode { Send, SendToClient }; + // "if (UNASSIGNED) SEND_PACKET_BROADCAST; SEND_PACKET;"), SendToClient (legacy functions with only SEND_PACKET) + // or Broadcast (legacy functions with only SEND_PACKET_BROADCAST, whatever address they were given: the struct is + // sent with Send(UNASSIGNED_SYSTEM_ADDRESS)). + enum class SendMode { Send, SendToClient, Broadcast }; // Sends the same message through the frozen legacy function and through the struct, to one client and to // UNASSIGNED_SYSTEM_ADDRESS, and requires identical bytes and the same effective destination. @@ -43,7 +45,11 @@ namespace GameMessageTestUtils { for (const auto& address : g_Addresses) { SCOPED_TRACE(address == UNASSIGNED_SYSTEM_ADDRESS ? "unassigned address" : "single client"); const auto legacyPackets = Capture([&] { legacySend(address); }); - const auto newPackets = Capture([&] { mode == SendMode::Send ? msg.Send(address) : msg.SendToClient(address); }); + const auto newPackets = Capture([&] { + if (mode == SendMode::Send) msg.Send(address); + else if (mode == SendMode::SendToClient) msg.SendToClient(address); + else msg.Send(UNASSIGNED_SYSTEM_ADDRESS); + }); ASSERT_FALSE(legacyPackets.empty()); ASSERT_EQ(newPackets.size(), 1); diff --git a/tests/dGameTests/dGameMessagesTests/Legacy/EffectsMessagesLegacy.h b/tests/dGameTests/dGameMessagesTests/Legacy/EffectsMessagesLegacy.h new file mode 100644 index 000000000..873c58c28 --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/Legacy/EffectsMessagesLegacy.h @@ -0,0 +1,607 @@ +#ifndef EFFECTSMESSAGESLEGACY_H +#define EFFECTSMESSAGESLEGACY_H + +// FROZEN ORACLE - DO NOT EDIT. +// Verbatim copies of the hand written GameMessages functions that EffectsMessages.h replaced +// (dGame/dGameMessages/GameMessages.cpp, branched from origin/main 129199e4). Only the namespace changed. +// The Read* functions are the read sequences of the replaced GameMessages::Handle* functions. + +#include "Amf3.h" +#include "AmfSerialize.h" +#include "BitStreamUtils.h" +#include "dCommonVars.h" +#include "dServer.h" +#include "eAnimationFlags.h" +#include "eCinematicEvent.h" +#include "eEndBehavior.h" +#include "Entity.h" +#include "Game.h" +#include "GeneralUtils.h" +#include "Logger.h" +#include "MessageType/Client.h" +#include "MessageType/Game.h" +#include "ServiceType.h" + +#include +#include + +namespace LegacyGameMessages { + // Declared in GameMessages.h in the original; the Entity* overload forwards to it. + inline void SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize); + + inline void SendPlayAnimation(Entity* entity, const std::u16string& animationName, float fPriority, float fScale) { + if (!entity) { + LOG("Trying to play animation, but entity var is nullptr!"); + return; + } + + //Stolen from the old DLU codebase as the new one's autogenerated code doesn't work properly for animationIDs longer than 6 characters. + CBITSTREAM; + CMSGHEADER; + std::string sAnimationID = GeneralUtils::UTF16ToWTF8(animationName); + + uint32_t animationIDLength = sAnimationID.size(); + bool bExpectAnimToExist = true; + bool bPlayImmediate = false; + bool bTriggerOnCompleteMsg = false; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLAY_ANIMATION); + + bitStream.Write(animationIDLength); + bitStream.Write(LUWString(animationName, animationIDLength)); + + bitStream.Write(bExpectAnimToExist); + + bitStream.Write(bPlayImmediate); + + bitStream.Write(bTriggerOnCompleteMsg); + + bitStream.Write(fPriority != 0.0f); + if (fPriority != 0.0f) bitStream.Write(fPriority); + + bitStream.Write(fScale != 1.0f); + if (fScale != 1.0f) bitStream.Write(fScale); + + SEND_PACKET_BROADCAST; + } + + inline void SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& sysAddr, std::string audioGUID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLAY_ND_AUDIO_EMITTER); + bitStream.Write0(); // callback message data {lwoobjid} + bitStream.Write0(); // audio emitterid {uint32_t} + + uint32_t length = audioGUID.size(); + bitStream.Write(length); + for (uint32_t k = 0; k < length; k++) { + bitStream.Write(audioGUID[k]); + } + + bitStream.Write(0); // size of NDAudioMetaEventName (then print the string like the guid) + bitStream.Write0(); // result {bool} + bitStream.Write0(); // m_TargetObjectIDForNDAudioCallbackMessages {lwoobjid} + + SEND_PACKET_BROADCAST; + } + + inline void SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT); + + bitStream.Write(effectName.length()); + for (uint32_t k = 0; k < effectName.length(); k++) { + bitStream.Write(effectName[k]); + } + bitStream.Write(fromObjectID); + bitStream.Write(radius); + + SEND_PACKET_BROADCAST; + } + + inline void SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) { + SendPlayFXEffect(entity->GetObjectID(), effectID, effectType, name, secondary, priority, scale, serialize); + } + + inline void SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority, float scale, bool serialize) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity); + bitStream.Write(MessageType::Game::PLAY_FX_EFFECT); + + bitStream.Write(effectID != -1); + if (effectID != -1) bitStream.Write(effectID); + + bitStream.Write(effectType.size()); + for (const auto& k : effectType) { + bitStream.Write(k); + } + + bitStream.Write(scale != 1.0f); + if (scale != 1.0f) bitStream.Write(scale); + + bitStream.Write(name.size()); + for (const auto& k : name) { + bitStream.Write(k); + } + + bitStream.Write(priority != 1.0); + if (priority != 1.0) bitStream.Write(priority); + + bitStream.Write(secondary != LWOOBJID_EMPTY); + if (secondary != LWOOBJID_EMPTY) bitStream.Write(secondary); + + bitStream.Write(serialize); + + SEND_PACKET_BROADCAST; + } + + inline void SendStopFXEffect(Entity* entity, bool killImmediate, std::string name) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::STOP_FX_EFFECT); + + bitStream.Write(killImmediate); + bitStream.Write(name.size()); + bitStream.Write(name.c_str(), name.size()); + + SEND_PACKET_BROADCAST; + } + + inline void SendBroadcastTextToChatbox(Entity* entity, const SystemAddress& sysAddr, const std::u16string& attrs, const std::u16string& wsText) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX); + + bitStream.Write(attrs.size()); + for (uint32_t i = 0; i < attrs.size(); ++i) { + bitStream.Write(attrs[i]); + } + bitStream.Write(0x00); // Null Terminator + + uint32_t wsTextLength = wsText.size(); + bitStream.Write(wsTextLength); + for (uint32_t k = 0; k < wsTextLength; k++) { + bitStream.Write(wsText[k]); + } + + SEND_PACKET_BROADCAST; + } + + inline void SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, bool result) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLAY2_D_AMBIENT_SOUND); + uint32_t audioGUIDSize = audioGUID.size(); + + bitStream.Write(audioGUIDSize); + for (uint32_t k = 0; k < audioGUIDSize; k++) { + bitStream.Write(audioGUID[k]); + } + bitStream.Write(result); + + SystemAddress sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + inline void SendStop2DAmbientSound(Entity* entity, bool force, std::string audioGUID, bool result) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::STOP2_D_AMBIENT_SOUND); + + uint32_t audioGUIDSize = audioGUID.size(); + + bitStream.Write(force); + bitStream.Write(audioGUIDSize); + + for (uint32_t k = 0; k < audioGUIDSize; k++) { + bitStream.Write(audioGUID[k]); + } + + bitStream.Write(result); + + SystemAddress sysAddr = entity->GetSystemAddress(); + + SEND_PACKET; + } + + inline void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFBaseValue& args) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT); + + bitStream.Write(args); + uint32_t strMessageNameLength = message.size(); + bitStream.Write(strMessageNameLength); + + for (uint32_t k = 0; k < strMessageNameLength; k++) { + bitStream.Write(message[k]); + } + + SEND_PACKET; + } + + inline void SendUIMessageServerToSingleClient(const std::string& message, AMFBaseValue& args, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + LWOOBJID empty = 0; + bitStream.Write(empty); + bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); // This is intentional to allow the server to send a ui message to a client via their system address. + + bitStream.Write(args); + uint32_t strMessageNameLength = message.size(); + bitStream.Write(strMessageNameLength); + + for (uint32_t k = 0; k < strMessageNameLength; k++) { + bitStream.Write(message[k]); + } + + SEND_PACKET; + } + + inline void SendUIMessageServerToAllClients(const std::string& message, AMFBaseValue& args) { + CBITSTREAM; + CMSGHEADER; + + LWOOBJID empty = 0; + bitStream.Write(empty); + bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); + + bitStream.Write(args); + uint32_t strMessageNameLength = message.size(); + bitStream.Write(strMessageNameLength); + + for (uint32_t k = 0; k < strMessageNameLength; k++) { + bitStream.Write(message[k]); + } + + SEND_PACKET_BROADCAST; + } + + inline void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::START_CELEBRATION_EFFECT); + + bitStream.Write(0); //animation + bitStream.Write0(); //No custom bg obj + bitStream.Write0(); //custom path + bitStream.Write0(); //leadin + bitStream.Write0(); //leadout + bitStream.Write1(); + bitStream.Write(celebrationID); + bitStream.Write(0.0f); //duration + bitStream.Write(0); //icon + bitStream.Write(0); //text + bitStream.Write(0); //mixer + bitStream.Write(0); //cue + bitStream.Write(0); //pathnodename + bitStream.Write(0); //soundguid + bitStream.Write(0); //subtext + + SEND_PACKET; + } + + inline void SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::DISPLAY_MESSAGE_BOX); + + bitStream.Write(bShow); + bitStream.Write(callbackClient); + + bitStream.Write(identifier.size()); + for (const auto character : identifier) { + bitStream.Write(character); + } + + bitStream.Write(imageID); + + bitStream.Write(text.size()); + for (const auto character : text) { + bitStream.Write(character); + } + + bitStream.Write(userData.size()); + for (const auto character : userData) { + bitStream.Write(character); + } + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr) { + // MessageType::Game::DISPLAY_CHAT_BUBBLE + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::DISPLAY_CHAT_BUBBLE); + + bitStream.Write(text.size()); + for (const auto character : text) { + bitStream.Write(character); + } + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::CHANGE_IDLE_FLAGS); + bitStream.Write(flagsOff != eAnimationFlags::IDLE_NONE); + if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); + bitStream.Write(flagsOn != eAnimationFlags::IDLE_NONE); + if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn); + + SEND_PACKET_BROADCAST; + } + + inline void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::SET_NAME_BILLBOARD_STATE); + + // Technically these bits would be written, however the client does not + // contain a deserialize method to actually deserialize, so we are leaving it out. + // As such this GM only turns the billboard off. + + // bitStream.Write(overrideDefault); + // bitStream.Write(state); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET + } + + inline void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET + } + + inline void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, + bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, + eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, + bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::PLAY_CINEMATIC); + + bitStream.Write(allowGhostUpdates); + bitStream.Write(bCloseMultiInteract); + bitStream.Write(bSendServerNotify); + bitStream.Write(bUseControlledObjectForAudioListener); + + bitStream.Write(endBehavior != eEndBehavior::RETURN); + if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior); + + bitStream.Write(hidePlayerDuringCine); + + bitStream.Write(leadIn != -1); + if (leadIn != -1) bitStream.Write(leadIn); + + bitStream.Write(leavePlayerLockedWhenFinished); + bitStream.Write(lockPlayer); + + bitStream.Write(pathName.size()); + for (char16_t c : pathName) { + bitStream.Write(c); + } + + bitStream.Write(result); + + bitStream.Write(skipIfSamePath); + + bitStream.Write(startTimeAdvance); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendEndCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, + float leadOut, bool leavePlayerLocked) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::END_CINEMATIC); + + bitStream.Write(leadOut != -1); + if (leadOut != -1) bitStream.Write(leadOut); + + bitStream.Write(leavePlayerLocked); + + bitStream.Write(pathName.size()); + for (uint32_t i = 0; i < pathName.size(); i++) { + bitStream.Write(pathName[i]); + } + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendSlashCommandFeedbackText(Entity* entity, std::u16string text) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SLASH_COMMAND_TEXT_FEEDBACK); + bitStream.Write(text.size()); + bitStream.Write(text); + auto sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + inline void SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID target, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::PLAY_EMOTE); + + bitStream.Write(emoteID); + bitStream.Write(target); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SET_EMOTE_LOCK_STATE); + bitStream.Write(bLock); + bitStream.Write(emoteID); + + SystemAddress sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + struct LegacyMessageBoxResponse { bool ok{}; int32_t iButton{}; std::u16string identifier; std::u16string userData; }; + inline LegacyMessageBoxResponse ReadMessageBoxResponse(RakNet::BitStream& inStream) { + int32_t iButton; + uint32_t identifierLength; + std::u16string identifier; + uint32_t userDataLength; + std::u16string userData; + + inStream.Read(iButton); + + inStream.Read(identifierLength); + if (identifierLength > MAX_MESSAGE_LENGTH) return {}; + for (size_t i = 0; i < identifierLength; i++) { + char16_t character; + inStream.Read(character); + identifier.push_back(character); + } + + inStream.Read(userDataLength); + if (userDataLength > MAX_MESSAGE_LENGTH) return {}; + for (size_t i = 0; i < userDataLength; i++) { + char16_t character; + inStream.Read(character); + userData.push_back(character); + } + return { true, iButton, identifier, userData }; + } + + struct LegacyChoiceBoxRespond { bool ok{}; int32_t iButton{}; std::u16string buttonIdentifier; std::u16string identifier; }; + inline LegacyChoiceBoxRespond ReadChoiceBoxRespond(RakNet::BitStream& inStream) { + int32_t iButton; + uint32_t buttonIdentifierLength; + std::u16string buttonIdentifier; + uint32_t identifierLength; + std::u16string identifier; + + inStream.Read(buttonIdentifierLength); + if (buttonIdentifierLength > MAX_MESSAGE_LENGTH) return {}; + for (size_t i = 0; i < buttonIdentifierLength; i++) { + char16_t character; + inStream.Read(character); + buttonIdentifier.push_back(character); + } + + inStream.Read(iButton); + + inStream.Read(identifierLength); + if (identifierLength > MAX_MESSAGE_LENGTH) return {}; + for (size_t i = 0; i < identifierLength; i++) { + char16_t character; + inStream.Read(character); + identifier.push_back(character); + } + return { true, iButton, buttonIdentifier, identifier }; + } + + struct LegacyCinematicUpdate { eCinematicEvent event; float_t overallTime; std::u16string pathName; float_t pathTime; int32_t waypoint; }; + inline LegacyCinematicUpdate ReadCinematicUpdate(RakNet::BitStream& inStream) { + eCinematicEvent event; + if (!inStream.ReadBit()) { + event = eCinematicEvent::STARTED; + } else { + inStream.Read(event); + } + + float_t overallTime; + if (!inStream.ReadBit()) { + overallTime = -1.0f; + } else { + inStream.Read(overallTime); + } + + uint32_t pathNameLength; + inStream.Read(pathNameLength); + + std::u16string pathName; + for (size_t i = 0; i < pathNameLength; i++) { + char16_t character; + inStream.Read(character); + pathName.push_back(character); + } + + float_t pathTime; + if (!inStream.ReadBit()) { + pathTime = -1.0f; + } else { + inStream.Read(pathTime); + } + + int32_t waypoint; + if (!inStream.ReadBit()) { + waypoint = -1; + } else { + inStream.Read(waypoint); + } + return { event, overallTime, pathName, pathTime, waypoint }; + } + + struct LegacyPlayEmote { int32_t emoteID; LWOOBJID targetID; }; + inline LegacyPlayEmote ReadPlayEmote(RakNet::BitStream& inStream) { + int32_t emoteID; + LWOOBJID targetID; + + inStream.Read(emoteID); + inStream.Read(targetID); + return { emoteID, targetID }; + } +} + +#endif // EFFECTSMESSAGESLEGACY_H