diff --git a/dGame/Character.cpp b/dGame/Character.cpp index 7d321ecba..8e29d381b 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -12,6 +12,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "MissionMessages.h" +#include "PlayerMessages.h" #include "MissionComponent.h" #include "dZoneManager.h" #include "dServer.h" @@ -597,7 +598,16 @@ void Character::SetCoins(int64_t newCoins, eLootSourceType lootSource) { EconomyLedger::RecordCoins(m_ID, newCoins - m_Coins, lootSource); m_Coins = newCoins; - GameMessages::SendSetCurrency(Game::entityManager->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource); + auto* entity = Game::entityManager->GetEntity(m_ObjectID); + GameMessages::SetCurrency setCurrency; + setCurrency.target = entity->GetObjectID(); + setCurrency.currency = m_Coins; + setCurrency.lootType = 0; + setCurrency.sourceLOT = 0; + setCurrency.sourceID = 0; + setCurrency.sourceTradeID = 0; + setCurrency.sourceType = lootSource; + setCurrency.SendToClient(entity->GetSystemAddress()); } bool Character::HasBeenToWorld(LWOMAPID mapID) const { diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 652e308d0..d4ca9a0df 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -14,6 +14,9 @@ #include "dServer.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" +#include "PlayerMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "Zone.h" @@ -107,6 +110,8 @@ #include "StringifiedEnum.h" #include +#include "InventoryMessages.h" +#include "ActivityMessages.h" Observable Entity::OnPlayerPositionUpdate; @@ -623,7 +628,7 @@ void Entity::Initialize() { // FV tree handler for when built so it sets the state to moving at the correct time if (GetLOT() == 9483) quickBuildComponent->AddQuickBuildCompleteCallback([objectID](Entity* user) { auto* const entity = Game::entityManager->GetEntity(objectID); - if (entity) GameMessages::SendPlatformResync(entity, UNASSIGNED_SYSTEM_ADDRESS, false, 0, 1, 1, eMovementPlatformState::Moving, true); + if (entity) GameMessages::PlatformResync(*entity, false, 0, 1, 1, eMovementPlatformState::Moving, true).Send(UNASSIGNED_SYSTEM_ADDRESS); }); const auto activityID = GetVar(u"activityID"); @@ -942,7 +947,10 @@ void Entity::SetGMLevel(eGameMasterLevel value) { characterComponent->SetGMLevel(value); - GameMessages::SendGMLevelBroadcast(m_ObjectID, value); + GameMessages::SetGMLevel setGMLevel; + setGMLevel.target = m_ObjectID; + setGMLevel.level = value; + setGMLevel.Send(UNASSIGNED_SYSTEM_ADDRESS); // Update the chat server of our GM Level { @@ -1300,7 +1308,7 @@ void Entity::OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent eve } void Entity::NotifyObject(Entity* sender, const std::string& name, int32_t param1, int32_t param2) { - GameMessages::SendNotifyObject(GetObjectID(), sender->GetObjectID(), GeneralUtils::ASCIIToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyObject(GetObjectID(), sender->GetObjectID(), GeneralUtils::ASCIIToUTF16(name)).Send(UNASSIGNED_SYSTEM_ADDRESS); GetScript()->OnNotifyObject(this, sender, name, param1, param2); } @@ -1899,7 +1907,10 @@ std::vector Entity::GetTargetsInPhantom() { } void Entity::SendNetworkVar(const std::string& data, const SystemAddress& sysAddr) { - GameMessages::SendSetNetworkScriptVar(this, sysAddr, data); + GameMessages::ScriptNetworkVarUpdate scriptVar; + scriptVar.target = this->GetObjectID(); + scriptVar.tableOfVars = GeneralUtils::ASCIIToUTF16(data); + scriptVar.Send(sysAddr); } const LDFBaseData* const Entity::GetVarData(const std::u16string& name) const { diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index 12f258da0..202306e26 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -9,6 +9,7 @@ #include "Character.h" #include "Game.h" #include "GameMessages.h" +#include "ActivityMessages.h" #include "Logger.h" #include "dConfig.h" #include "CDClientManager.h" @@ -243,7 +244,10 @@ void Leaderboard::SetupLeaderboard(bool weekly) { void Leaderboard::Send(const LWOOBJID targetID) const { auto* player = Game::entityManager->GetEntity(relatedPlayer); if (player != nullptr) { - GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress()); + GameMessages::SendActivitySummaryLeaderboardData leaderboardData; + leaderboardData.target = targetID; + leaderboardData.leaderboard = this; + leaderboardData.SendToClient(player->GetSystemAddress()); } } diff --git a/dGame/dBehaviors/JetPackBehavior.cpp b/dGame/dBehaviors/JetPackBehavior.cpp index 78f25fcd4..61afc2385 100644 --- a/dGame/dBehaviors/JetPackBehavior.cpp +++ b/dGame/dBehaviors/JetPackBehavior.cpp @@ -2,6 +2,7 @@ #include "BehaviorBranchContext.h" #include "GameMessages.h" +#include "MovementMessages.h" #include "Character.h" @@ -9,7 +10,17 @@ void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_st auto* entity = Game::entityManager->GetEntity(branch.target); if (!entity) return; - GameMessages::SendSetJetPackMode(entity, true, this->m_BypassChecks, this->m_EnableHover, this->m_effectId, this->m_Airspeed, this->m_MaxAirspeed, this->m_VerticalVelocity, this->m_WarningEffectID); + GameMessages::SetJetPackMode jetPackMode; + jetPackMode.target = entity->GetObjectID(); + jetPackMode.bUse = true; + jetPackMode.bBypassChecks = this->m_BypassChecks; + jetPackMode.bDoHover = this->m_EnableHover; + jetPackMode.effectID = this->m_effectId; + jetPackMode.fAirspeed = this->m_Airspeed; + jetPackMode.fMaxAirspeed = this->m_MaxAirspeed; + jetPackMode.fVertVel = this->m_VerticalVelocity; + jetPackMode.iWarningEffectID = this->m_WarningEffectID; + jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); if (entity->IsPlayer()) { auto* character = entity->GetCharacter(); @@ -24,7 +35,10 @@ void JetPackBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext bra auto* entity = Game::entityManager->GetEntity(branch.target); if (!entity) return; - GameMessages::SendSetJetPackMode(entity, false); + GameMessages::SetJetPackMode jetPackMode; + jetPackMode.target = entity->GetObjectID(); + jetPackMode.bUse = false; + jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); if (entity->IsPlayer()) { auto* character = entity->GetCharacter(); diff --git a/dGame/dComponents/ActivityComponent.cpp b/dGame/dComponents/ActivityComponent.cpp index 9a3b45153..a45ee4b8b 100644 --- a/dGame/dComponents/ActivityComponent.cpp +++ b/dGame/dComponents/ActivityComponent.cpp @@ -2,6 +2,7 @@ #include "ChatServerLink.h" #include "ChatPackets.h" #include "GameMessages.h" +#include "ActivityMessages.h" #include "CDClientManager.h" #include "MissionComponent.h" #include "Character.h" @@ -124,8 +125,12 @@ void ActivityComponent::PlayerJoin(Entity* player) { } void ActivityComponent::PlayerJoinLobby(Entity* player) { - if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD)) - GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby + if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD)) { + GameMessages::MatchResponse matchResponse; + matchResponse.target = player->GetObjectID(); + matchResponse.response = 0; + matchResponse.SendToClient(player->GetSystemAddress()); // tell the client they joined a lobby + } LobbyPlayer newLobbyPlayer{}; newLobbyPlayer.entityID = player->GetObjectID(); LWOOBJID playerLobbyID = LWOOBJID_EMPTY; @@ -154,9 +159,17 @@ void ActivityComponent::PlayerJoinLobby(Entity* player) { LDFData entityLDF("player", entity->GetObjectID()); LDFData entityName("playerName", entity->GetCharacter()->GetName()); std::string matchUpdate = entityLDF.GetString() + "\n" + entityName.GetString(); - GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchUpdate, eMatchUpdate::PLAYER_ADDED); + GameMessages::MatchUpdate existingPlayerUpdate; + existingPlayerUpdate.target = player->GetObjectID(); + existingPlayerUpdate.data = matchUpdate; + existingPlayerUpdate.type = eMatchUpdate::PLAYER_ADDED; + existingPlayerUpdate.SendToClient(player->GetSystemAddress()); PlayerReady(entity, joinedPlayer.ready); - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateJoined, eMatchUpdate::PLAYER_ADDED); + GameMessages::MatchUpdate joinedPlayerUpdate; + joinedPlayerUpdate.target = entity->GetObjectID(); + joinedPlayerUpdate.data = matchUpdateJoined; + joinedPlayerUpdate.type = eMatchUpdate::PLAYER_ADDED; + joinedPlayerUpdate.SendToClient(entity->GetSystemAddress()); } break; } @@ -174,7 +187,11 @@ void ActivityComponent::PlayerJoinLobby(Entity* player) { if (m_ActivityInfo.maxTeamSize != 1 && lobby.players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby.players.size() >= m_ActivityInfo.minTeams) { // Update the joining player on the match timer LDFData matchTimer("time", lobby.timer); - GameMessages::SendMatchUpdate(player, player->GetSystemAddress(), matchTimer.GetString(), eMatchUpdate::PHASE_WAIT_READY); + GameMessages::MatchUpdate matchUpdate; + matchUpdate.target = player->GetObjectID(); + matchUpdate.data = matchTimer.GetString(); + matchUpdate.type = eMatchUpdate::PHASE_WAIT_READY; + matchUpdate.SendToClient(player->GetSystemAddress()); } } @@ -190,7 +207,11 @@ void ActivityComponent::PlayerLeave(LWOOBJID playerID) { if (entity == nullptr) continue; - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchUpdateLeft.GetString(), eMatchUpdate::PLAYER_REMOVED); + GameMessages::MatchUpdate matchUpdate; + matchUpdate.target = entity->GetObjectID(); + matchUpdate.data = matchUpdateLeft.GetString(); + matchUpdate.type = eMatchUpdate::PLAYER_REMOVED; + matchUpdate.SendToClient(entity->GetSystemAddress()); } lobby.players.erase(lobby.players.begin() + i); @@ -229,7 +250,11 @@ void ActivityComponent::Update(float deltaTime) { continue; LDFData matchTimerUpdate("time", lobby.timer); - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate.GetString(), eMatchUpdate::PHASE_WAIT_READY); + GameMessages::MatchUpdate matchUpdate; + matchUpdate.target = entity->GetObjectID(); + matchUpdate.data = matchTimerUpdate.GetString(); + matchUpdate.type = eMatchUpdate::PHASE_WAIT_READY; + matchUpdate.SendToClient(entity->GetSystemAddress()); } } @@ -254,7 +279,11 @@ void ActivityComponent::Update(float deltaTime) { if (entity == nullptr) continue; - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchTimerUpdate.GetString(), eMatchUpdate::PHASE_WAIT_START); + GameMessages::MatchUpdate matchUpdate; + matchUpdate.target = entity->GetObjectID(); + matchUpdate.data = matchTimerUpdate.GetString(); + matchUpdate.type = eMatchUpdate::PHASE_WAIT_START; + matchUpdate.SendToClient(entity->GetSystemAddress()); } } @@ -349,7 +378,11 @@ void ActivityComponent::PlayerReady(Entity* player, bool bReady) { if (entity == nullptr) continue; - GameMessages::SendMatchUpdate(entity, entity->GetSystemAddress(), matchReadyUpdate.GetString(), readyStatus); + GameMessages::MatchUpdate matchUpdate; + matchUpdate.target = entity->GetObjectID(); + matchUpdate.data = matchReadyUpdate.GetString(); + matchUpdate.type = readyStatus; + matchUpdate.SendToClient(entity->GetSystemAddress()); } } } diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 927889e47..22c750434 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -14,6 +14,7 @@ #include "AmfSerialize.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "PlayerMessages.h" #include "User.h" #include "CDClientManager.h" #include "CDDestructibleComponentTable.h" @@ -47,6 +48,7 @@ #include #include "CDComponentsRegistryTable.h" +#include "InventoryMessages.h" Implementation DestroyableComponent::IsEnemyImplentation; Implementation DestroyableComponent::IsFriendImplentation; @@ -967,7 +969,11 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) { LOG("Player %llu has lost %llu uscore!", m_Parent->GetObjectID(), uscoreToLose); character->SetUScore(uscore - uscoreToLose, EconomyLedger::HARDCORE_DEATH_SOURCE); - GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::MISSION); + GameMessages::ModifyLEGOScore modifyScore; + modifyScore.target = m_Parent->GetObjectID(); + modifyScore.score = -uscoreToLose; + modifyScore.sourceType = eLootSourceType::MISSION; + modifyScore.SendToClient(m_Parent->GetSystemAddress()); if (Game::entityManager->GetHardcoreDropinventoryOnDeath()) { //drop all items from inventory: @@ -1051,7 +1057,11 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) { int uscore = maxHealth * Game::entityManager->GetHardcoreUscoreEnemiesMultiplier() * uscoreReduction; LOG("Rewarding player %llu with %i uscore for killing enemy %i", player->GetObjectID(), uscore, lot); playerStats->SetUScore(playerStats->GetUScore() + uscore, EconomyLedger::HARDCORE_KILL_SOURCE); - GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::MISSION); + GameMessages::ModifyLEGOScore modifyScore; + modifyScore.target = player->GetObjectID(); + modifyScore.score = uscore; + modifyScore.sourceType = eLootSourceType::MISSION; + modifyScore.SendToClient(player->GetSystemAddress()); Game::entityManager->SerializeEntity(m_Parent); } diff --git a/dGame/dComponents/GhostComponent.cpp b/dGame/dComponents/GhostComponent.cpp index 6c0800b82..c202ff87f 100644 --- a/dGame/dComponents/GhostComponent.cpp +++ b/dGame/dComponents/GhostComponent.cpp @@ -7,6 +7,7 @@ #include "Amf3.h" #include "GameMessages.h" +#include "PlayerMessages.h" GhostComponent::GhostComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) { m_GhostReferencePoint = NiPoint3Constant::ZERO; diff --git a/dGame/dComponents/GhostComponent.h b/dGame/dComponents/GhostComponent.h index 2011943d6..c66916b59 100644 --- a/dGame/dComponents/GhostComponent.h +++ b/dGame/dComponents/GhostComponent.h @@ -4,6 +4,7 @@ #include "Component.h" #include "eReplicaComponentType.h" #include +#include "PlayerMessages.h" class NiPoint3; diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 56f54a437..12b3c89e0 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -16,6 +16,7 @@ #include "InventoryMessages.h" #include "Database.h" #include "SkillMessages.h" +#include "MovementMessages.h" #include "SkillComponent.h" #include "Character.h" #include "EntityManager.h" @@ -1105,7 +1106,10 @@ void InventoryComponent::HandlePossession(Item* item) { // Set the mount item ID so that we know what we're handling possessorComponent->SetMountItemID(item->GetId()); - GameMessages::SendSetMountInventoryID(m_Parent, item->GetId(), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SetMountInventoryID mountInventoryID; + mountInventoryID.target = m_Parent->GetObjectID(); + mountInventoryID.inventoryMountID = item->GetId(); + mountInventoryID.Send(UNASSIGNED_SYSTEM_ADDRESS); // Create the mount entity EntityInfo info{}; diff --git a/dGame/dComponents/ModelComponent.cpp b/dGame/dComponents/ModelComponent.cpp index ffc325339..da24fa3fa 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -17,6 +17,7 @@ #include "Database.h" #include "DluAssert.h" +#include "ObjectMessages.h" ModelComponent::ModelComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) { m_OriginalPosition = m_Parent->GetDefaultPosition(); diff --git a/dGame/dComponents/ModelComponent.h b/dGame/dComponents/ModelComponent.h index fae2ada69..474fcbfd6 100644 --- a/dGame/dComponents/ModelComponent.h +++ b/dGame/dComponents/ModelComponent.h @@ -14,6 +14,7 @@ #include "PropertyBehavior.h" #include "PropertyBehaviorActions.h" #include "StripUiPosition.h" +#include "ObjectMessages.h" class AddMessage; class AMFArrayValue; diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index a504423ce..fe0c17448 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -4,6 +4,7 @@ #include "PetMessages.h" #include "InventoryMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "BrickDatabase.h" #include "CDClientDatabase.h" #include "CDTamingBuildPuzzleTable.h" @@ -740,7 +741,7 @@ void PetComponent::RequestSetPetName(std::u16string name) { characterComponent->SetCurrentActivity(eGameActivity::NONE); Game::entityManager->SerializeEntity(tamer); } - GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::TerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); auto* modelEntity = Game::entityManager->GetEntity(m_ModelId); @@ -791,7 +792,7 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { msg.Send(tamer->GetSystemAddress()); } - GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::TerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); currentActivities.erase(m_Tamer); @@ -847,7 +848,7 @@ void PetComponent::ClientFailTamingMinigame() { msg.Send(tamer->GetSystemAddress()); } - GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::TerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); currentActivities.erase(m_Tamer); diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index 0ac8129d4..e367255b0 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -14,6 +14,7 @@ #include "EntityManager.h" #include "ControllablePhysicsComponent.h" #include "GameMessages.h" +#include "MovementMessages.h" #include "ePhysicsEffectType.h" #include "CDClientManager.h" @@ -157,7 +158,10 @@ void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effec // dont want to apply an effect to nothing. if (!controllablePhysicsComponent) return; controllablePhysicsComponent->SetGravityScale(effectScale); - GameMessages::SendSetGravityScale(target, effectScale, targetEntity->GetSystemAddress()); + GameMessages::SetGravityScale gravityScale; + gravityScale.target = target; + gravityScale.scale = effectScale; + gravityScale.SendToClient(targetEntity->GetSystemAddress()); } break; } @@ -185,7 +189,11 @@ void PhantomPhysicsComponent::Update(float deltaTime) { auto* const entity = Game::entityManager->GetEntity(id); if (entity) { - GameMessages::SendPlayerReachedRespawnCheckpoint(entity, m_RespawnPos, m_RespawnRot); + GameMessages::PlayerReachedRespawnCheckpoint respawnCheckpoint; + respawnCheckpoint.target = entity->GetObjectID(); + respawnCheckpoint.pos = m_RespawnPos; + respawnCheckpoint.rot = m_RespawnRot; + respawnCheckpoint.SendToClient(entity->GetSystemAddress()); entity->SetRespawnPos(m_RespawnPos); entity->SetRespawnRot(m_RespawnRot); } diff --git a/dGame/dComponents/PossessorComponent.cpp b/dGame/dComponents/PossessorComponent.cpp index f4d5fa428..399c41f92 100644 --- a/dGame/dComponents/PossessorComponent.cpp +++ b/dGame/dComponents/PossessorComponent.cpp @@ -7,6 +7,9 @@ #include "RacingMessages.h" #include "eUnequippableActiveType.h" #include "InventoryMessages.h" +#include "MovementMessages.h" +#include "ControllablePhysicsComponent.h" +#include "SkillMessages.h" PossessorComponent::PossessorComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) { m_Possessable = LWOOBJID_EMPTY; @@ -63,7 +66,10 @@ void PossessorComponent::Mount(Entity* mount) { } // GM's to send - GameMessages::SendSetJetPackMode(m_Parent, false); + GameMessages::SetJetPackMode jetPackMode; + jetPackMode.target = m_Parent->GetObjectID(); + jetPackMode.bUse = false; + jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); if (mount->GetComponent()) { auto characterComponent = m_Parent->GetComponent(); if (characterComponent) characterComponent->SetIsRacing(true); @@ -105,3 +111,39 @@ void PossessorComponent::Dismount(Entity* mount, bool forceDismount) { } } } + +void PossessorComponent::OnDismountComplete(const LWOOBJID mountId) { + auto* mount = Game::entityManager->GetEntity(mountId); + // make sure we have the things we need and they aren't null + if (!mount) return; + if (!GetIsDismounting()) return; + SetIsDismounting(false); + SetPossessable(LWOOBJID_EMPTY); + SetPossessableType(ePossessionType::NO_POSSESSION); + + // character related things + auto* character = m_Parent->GetComponent(); + if (character) { + // If we had an active item turn it off + if (GetMountItemID() != LWOOBJID_EMPTY) { + GameMessages::MarkInventoryItemAsActive markActive; + markActive.target = m_Parent->GetObjectID(); + markActive.bActive = false; + markActive.iType = eUnequippableActiveType::MOUNT; + markActive.itemID = GetMountItemID(); + markActive.Send(m_Parent->GetSystemAddress()); + } + SetMountItemID(LWOOBJID_EMPTY); + } + + // Set that the controllabel phsyics comp is teleporting + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetIsTeleporting(true); + + // Call dismoint on the possessable comp to let it handle killing the possessable + auto* possessableComponent = mount->GetComponent(); + if (possessableComponent) possessableComponent->Dismount(); + + // Update the entity that was possessing + Game::entityManager->SerializeEntity(m_Parent); +} diff --git a/dGame/dComponents/PossessorComponent.h b/dGame/dComponents/PossessorComponent.h index 8fb6ee3f2..05ac59595 100644 --- a/dGame/dComponents/PossessorComponent.h +++ b/dGame/dComponents/PossessorComponent.h @@ -40,6 +40,13 @@ public: */ void Dismount(Entity* mount, bool forceDismount = false); + /** + * @brief Handles the client's DismountComplete: finishes a dismount started by Dismount + * + * @param mountId The object ID of the mount the client finished dismounting + */ + void OnDismountComplete(const LWOOBJID mountId); + /** * Sets the ID that this entity is possessing * @param value The ID that this entity is possessing diff --git a/dGame/dComponents/QuickBuildComponent.cpp b/dGame/dComponents/QuickBuildComponent.cpp index f41cc72c5..698750596 100644 --- a/dGame/dComponents/QuickBuildComponent.cpp +++ b/dGame/dComponents/QuickBuildComponent.cpp @@ -4,6 +4,8 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "ObjectMessages.h" +#include "QuickBuildMessages.h" #include "EntityManager.h" #include "Game.h" #include "Logger.h" @@ -406,8 +408,21 @@ void QuickBuildComponent::StartQuickBuild(Entity* const user) { Game::entityManager->SerializeEntity(user); - GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::BUILDING, user->GetObjectID()); - GameMessages::SendEnableQuickBuild(m_Parent, true, false, false, eQuickBuildFailReason::NOT_GIVEN, 0.0f, user->GetObjectID()); + GameMessages::RebuildNotifyState notifyState; + notifyState.target = m_Parent->GetObjectID(); + notifyState.prevState = m_State; + notifyState.state = eQuickBuildState::BUILDING; + notifyState.player = user->GetObjectID(); + notifyState.Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::EnableRebuild enableRebuild; + enableRebuild.target = m_Parent->GetObjectID(); + enableRebuild.bEnable = true; + enableRebuild.bFail = false; + enableRebuild.bSuccess = false; + enableRebuild.eFailReason = eQuickBuildFailReason::NOT_GIVEN; + enableRebuild.fDuration = 0.0f; + enableRebuild.user = user->GetObjectID(); + enableRebuild.Send(UNASSIGNED_SYSTEM_ADDRESS); SetState(eQuickBuildState::BUILDING); Game::entityManager->SerializeEntity(m_Parent); @@ -442,12 +457,25 @@ void QuickBuildComponent::CompleteQuickBuild(Entity* const user) { Game::entityManager->SerializeEntity(user); - GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::COMPLETED, user->GetObjectID()); + GameMessages::RebuildNotifyState notifyState; + notifyState.target = m_Parent->GetObjectID(); + notifyState.prevState = m_State; + notifyState.state = eQuickBuildState::COMPLETED; + notifyState.player = user->GetObjectID(); + notifyState.Send(UNASSIGNED_SYSTEM_ADDRESS); 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()); + GameMessages::EnableRebuild enableRebuild; + enableRebuild.target = m_Parent->GetObjectID(); + enableRebuild.bEnable = false; + enableRebuild.bFail = false; + enableRebuild.bSuccess = true; + enableRebuild.eFailReason = eQuickBuildFailReason::NOT_GIVEN; + enableRebuild.fDuration = m_ResetTime; + enableRebuild.user = user->GetObjectID(); + enableRebuild.Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); SetState(eQuickBuildState::COMPLETED); @@ -522,14 +550,27 @@ void QuickBuildComponent::ResetQuickBuild(const bool failed) { Entity* builder = GetBuilder(); if (m_State == eQuickBuildState::BUILDING && builder) { - GameMessages::SendEnableQuickBuild(m_Parent, false, false, failed, eQuickBuildFailReason::NOT_GIVEN, m_ResetTime, builder->GetObjectID()); + GameMessages::EnableRebuild enableRebuild; + enableRebuild.target = m_Parent->GetObjectID(); + enableRebuild.bEnable = false; + enableRebuild.bFail = false; + enableRebuild.bSuccess = failed; + enableRebuild.eFailReason = eQuickBuildFailReason::NOT_GIVEN; + enableRebuild.fDuration = m_ResetTime; + enableRebuild.user = builder->GetObjectID(); + enableRebuild.Send(UNASSIGNED_SYSTEM_ADDRESS); if (failed) { RenderComponent::PlayAnimation(builder, u"rebuild-fail"); } } - GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::RESETTING, LWOOBJID_EMPTY); + GameMessages::RebuildNotifyState notifyState; + notifyState.target = m_Parent->GetObjectID(); + notifyState.prevState = m_State; + notifyState.state = eQuickBuildState::RESETTING; + notifyState.player = LWOOBJID_EMPTY; + notifyState.Send(UNASSIGNED_SYSTEM_ADDRESS); SetState(eQuickBuildState::RESETTING); SetTimer(0.0f); @@ -559,12 +600,25 @@ void QuickBuildComponent::CancelQuickBuild(Entity* const entity, const eQuickBui const auto entityID = entity != nullptr ? entity->GetObjectID() : LWOOBJID_EMPTY; // Notify the client that a state has changed - GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::INCOMPLETE, entityID); - GameMessages::SendEnableQuickBuild(m_Parent, false, true, false, failReason, m_Timer, entityID); + GameMessages::RebuildNotifyState notifyState; + notifyState.target = m_Parent->GetObjectID(); + notifyState.prevState = m_State; + notifyState.state = eQuickBuildState::INCOMPLETE; + notifyState.player = entityID; + notifyState.Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::EnableRebuild enableRebuild; + enableRebuild.target = m_Parent->GetObjectID(); + enableRebuild.bEnable = false; + enableRebuild.bFail = true; + enableRebuild.bSuccess = false; + enableRebuild.eFailReason = failReason; + enableRebuild.fDuration = m_Timer; + enableRebuild.user = entityID; + enableRebuild.Send(UNASSIGNED_SYSTEM_ADDRESS); // Now terminate any interaction with the rebuild - GameMessages::SendTerminateInteraction(entityID, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); - GameMessages::SendTerminateInteraction(m_Parent->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); + GameMessages::TerminateInteraction(entityID, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::TerminateInteraction(m_Parent->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); // Now update the component itself SetState(eQuickBuildState::INCOMPLETE); diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index e86364e93..314ec2f0f 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -11,6 +11,7 @@ #include "CombatMessages.h" #include "ActivityMessages.h" #include "RacingMessages.h" +#include "MovementMessages.h" #include "InventoryComponent.h" #include "Item.h" #include "MissionComponent.h" @@ -152,8 +153,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player, // Make sure the player is at the correct position. - GameMessages::SendTeleport(player->GetObjectID(), startPosition, - startRotation, player->GetSystemAddress(), true); + GameMessages::Teleport(player->GetObjectID(), startPosition, startRotation, true).SendToClient(player->GetSystemAddress()); // Spawn the vehicle entity. @@ -265,7 +265,10 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player, resetPlayer.Send(UNASSIGNED_SYSTEM_ADDRESS); }); - GameMessages::SendSetJetPackMode(player, false); + GameMessages::SetJetPackMode jetPackMode; + jetPackMode.target = player->GetObjectID(); + jetPackMode.bUse = false; + jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); // Set the vehicle's state. GameMessages::NotifyVehicleOfRacingObject notifyVehicle; @@ -280,10 +283,8 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player, wheelLockState.Send(UNASSIGNED_SYSTEM_ADDRESS); // Make sure everything has the correct position. - GameMessages::SendTeleport(player->GetObjectID(), startPosition, - startRotation, player->GetSystemAddress(), true); - GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, - startRotation, player->GetSystemAddress(), true); + GameMessages::Teleport(player->GetObjectID(), startPosition, startRotation, true).SendToClient(player->GetSystemAddress()); + GameMessages::Teleport(carEntity->GetObjectID(), startPosition, startRotation, true).SendToClient(player->GetSystemAddress()); } void RacingControlComponent::OnRacingClientReady(Entity* player) { @@ -691,10 +692,7 @@ void RacingControlComponent::Update(float deltaTime) { Game::entityManager->GetEntity(player.playerID); if (vehicle != nullptr && playerEntity != nullptr) { - GameMessages::SendTeleport( - player.playerID, player.respawnPosition, - player.respawnRotation, - playerEntity->GetSystemAddress(), true); + GameMessages::Teleport(player.playerID, player.respawnPosition, player.respawnRotation, true).SendToClient(playerEntity->GetSystemAddress()); vehicle->SetPosition(player.respawnPosition); vehicle->SetRotation(player.respawnRotation); diff --git a/dGame/dComponents/RailActivatorComponent.cpp b/dGame/dComponents/RailActivatorComponent.cpp index 1df1b9917..6108e7f1e 100644 --- a/dGame/dComponents/RailActivatorComponent.cpp +++ b/dGame/dComponents/RailActivatorComponent.cpp @@ -6,6 +6,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "MovementMessages.h" #include "QuickBuildComponent.h" #include "Game.h" #include "Logger.h" @@ -74,11 +75,24 @@ void RailActivatorComponent::OnUse(Entity* originator) { return; } - GameMessages::SendStartRailMovement(originator->GetObjectID(), m_Path, m_StartSound, - m_loopSound, m_StopSound, originator->GetSystemAddress(), - m_PathStart, m_PathDirection, m_DamageImmune, m_NoAggro, m_NotifyArrived, - m_ShowNameBillboard, m_CameraLocked, m_CollisionEnabled, m_UseDB, m_ComponentID, - m_Parent->GetObjectID()); + GameMessages::StartRailMovement startRail; + startRail.target = originator->GetObjectID(); + startRail.pathName = m_Path; + startRail.startSound = m_StartSound; + startRail.loopSound = m_loopSound; + startRail.stopSound = m_StopSound; + startRail.pathStart = m_PathStart; + startRail.goForward = m_PathDirection; + startRail.bDamageImmune = m_DamageImmune; + startRail.bNoAggro = m_NoAggro; + startRail.bNotifyActor = m_NotifyArrived; + startRail.bShowNameBillboard = m_ShowNameBillboard; + startRail.bCameraLocked = m_CameraLocked; + startRail.bCollisionEnabled = m_CollisionEnabled; + startRail.bUseDB = m_UseDB; + startRail.railActivatorComponentID = m_ComponentID; + startRail.railActivatorObjectID = m_Parent->GetObjectID(); + startRail.Send(originator->GetSystemAddress()); }); } @@ -111,9 +125,14 @@ void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { RenderComponent::PlayAnimation(originator, m_LoopAnimation); } - GameMessages::SendSetRailMovement(originator->GetObjectID(), m_PathDirection, m_Path, m_PathStart, - originator->GetSystemAddress(), m_ComponentID, - m_Parent->GetObjectID()); + GameMessages::SetRailMovement setRail; + setRail.target = originator->GetObjectID(); + setRail.pathGoForward = m_PathDirection; + setRail.pathName = m_Path; + setRail.pathStart = m_PathStart; + setRail.railActivatorComponentID = m_ComponentID; + setRail.railActivatorObjectID = m_Parent->GetObjectID(); + setRail.Send(originator->GetSystemAddress()); } } diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.cpp b/dGame/dComponents/RocketLaunchpadControlComponent.cpp index a64cce767..73243c80b 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.cpp +++ b/dGame/dComponents/RocketLaunchpadControlComponent.cpp @@ -4,6 +4,8 @@ #include #include "GameMessages.h" +#include "ObjectMessages.h" +#include "ZoneMessages.h" #include "CharacterComponent.h" #include "dZoneManager.h" #include "EntityManager.h" @@ -78,9 +80,12 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, SetSelectedMapId(originator->GetObjectID(), zone); - GameMessages::SendFireEventClientSide(m_Parent->GetObjectID(), originator->GetSystemAddress(), u"RocketEquipped", rocket->GetId(), cloneId, -1, originator->GetObjectID()); + GameMessages::FireEventClientSide(m_Parent->GetObjectID(), u"RocketEquipped", rocket->GetId(), originator->GetObjectID()).SendToClient(originator->GetSystemAddress()); - GameMessages::SendChangeObjectWorldState(rocket->GetId(), eObjectWorldState::ATTACHED, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::ChangeObjectWorldState worldState; + worldState.target = rocket->GetId(); + worldState.newState = eObjectWorldState::ATTACHED; + worldState.Send(UNASSIGNED_SYSTEM_ADDRESS); Game::entityManager->SerializeEntity(originator); } diff --git a/dGame/dComponents/TriggerComponent.cpp b/dGame/dComponents/TriggerComponent.cpp index a159ff654..7aa97f65c 100644 --- a/dGame/dComponents/TriggerComponent.cpp +++ b/dGame/dComponents/TriggerComponent.cpp @@ -19,6 +19,7 @@ #include #include "EffectsMessages.h" +#include "ZoneMessages.h" TriggerComponent::TriggerComponent(Entity* parent, const int32_t componentID, const std::string triggerInfo) : Component(parent, componentID) { m_Parent = parent; @@ -130,9 +131,15 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity case eTriggerCommandType::CAST_SKILL: HandleCastSkill(targetEntity, command->args); break; - case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: - GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID()); + case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: { + GameMessages::DisplayZoneSummary zoneSummary; + zoneSummary.target = targetEntity->GetObjectID(); + zoneSummary.isPropertyMap = false; + zoneSummary.isZoneStart = command->args == "1"; + zoneSummary.sender = m_Parent->GetObjectID(); + zoneSummary.Send(targetEntity->GetSystemAddress()); break; + } case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: HandleSetPhysicsVolumeEffect(targetEntity, argArray); break; diff --git a/dGame/dGameMessages/ActivityMessages.cpp b/dGame/dGameMessages/ActivityMessages.cpp index 4f5709e41..dc54e2f10 100644 --- a/dGame/dGameMessages/ActivityMessages.cpp +++ b/dGame/dGameMessages/ActivityMessages.cpp @@ -4,6 +4,10 @@ #include "Entity.h" #include "EntityManager.h" #include "Game.h" +#include "LeaderboardManager.h" +#include "Logger.h" +#include "ScriptedActivityComponent.h" +#include "eReplicaComponentType.h" namespace GameMessages { void ActivityStop::Serialize(RakNet::BitStream& bitStream) const { @@ -79,4 +83,187 @@ namespace GameMessages { VALIDATE_READ(bitStream.Read(stateToPlaySoundOn)); return true; } + + namespace { + void WritePoint(RakNet::BitStream& bitStream, const NiPoint3& point) { + bitStream.Write(point.x); + bitStream.Write(point.y); + bitStream.Write(point.z); + } + + bool ReadPoint(RakNet::BitStream& bitStream, NiPoint3& point) { + return bitStream.Read(point.x) && bitStream.Read(point.y) && bitStream.Read(point.z); + } + } + + void MatchResponse::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(response); + } + + bool MatchResponse::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(response); + } + + void MatchUpdate::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteNameValueText(bitStream, std::u16string(data.begin(), data.end())); + bitStream.Write(type); + } + + bool MatchUpdate::Deserialize(RakNet::BitStream& bitStream) { + std::u16string wide; + VALIDATE_READ(BitStreamUtils::ReadNameValueText(bitStream, wide)); + data.assign(wide.begin(), wide.end()); + VALIDATE_READ(bitStream.Read(type)); + return true; + } + + void MatchRequest::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(activator); + BitStreamUtils::WriteNameValueText(bitStream, std::u16string(playerChoices.begin(), playerChoices.end())); + bitStream.Write(type); + bitStream.Write(value); + } + + bool MatchRequest::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(activator)); + std::u16string wide; + VALIDATE_READ(BitStreamUtils::ReadNameValueText(bitStream, wide)); + playerChoices.clear(); + for (const auto character : wide) playerChoices.push_back(character); + VALIDATE_READ(bitStream.Read(type)); + VALIDATE_READ(bitStream.Read(value)); + return true; + } + + void MatchRequest::Handle(Entity& entity, const SystemAddress& sysAddr) { + std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + if (type == 0) { // join + if (value != 0) { + for (Entity* scriptedAct : scriptedActs) { + auto* comp = scriptedAct->GetComponent(); + if (!comp) continue; + if (comp->GetActivityID() == value) { + comp->PlayerJoin(&entity); + } + } + } + } else if (type == 1) { // ready/unready + for (Entity* scriptedAct : scriptedActs) { + auto* comp = scriptedAct->GetComponent(); + if (!comp) continue; + if (comp->PlayerIsInQueue(&entity)) { + comp->PlayerReady(&entity, value); + } + } + } + } + + void RequestActivitySummaryLeaderboardData::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, gameID, 0); + BitStreamUtils::WriteOptional(bitStream, queryType, 1); + BitStreamUtils::WriteOptional(bitStream, resultsEnd, 10); + BitStreamUtils::WriteOptional(bitStream, resultsStart, 0); + bitStream.Write(targetID); + bitStream.Write(weekly); + } + + bool RequestActivitySummaryLeaderboardData::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, gameID, 0)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, queryType, 1)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, resultsEnd, 10)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, resultsStart, 0)); + VALIDATE_READ(bitStream.Read(targetID)); + VALIDATE_READ(bitStream.Read(weekly)); + return true; + } + + void RequestActivitySummaryLeaderboardData::Handle(Entity& entity, const SystemAddress& sysAddr) { + // The client won't accept more than 10 results even if we wanted it to + LeaderboardManager::SendLeaderboard(gameID, static_cast(queryType), weekly, entity.GetObjectID(), entity.GetObjectID(), 10); + } + + void SendActivitySummaryLeaderboardData::Serialize(RakNet::BitStream& bitStream) const { + if (leaderboard) leaderboard->Serialize(bitStream); + } + + void SendActivitySummaryLeaderboardData::Handle(Entity& entity, const SystemAddress& sysAddr) { + LOG("We got mail!"); + } + + void NotifyClientShootingGalleryScore::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(addTime); + bitStream.Write(score); + bitStream.Write(targetID); + WritePoint(bitStream, targetPos); + } + + bool NotifyClientShootingGalleryScore::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(addTime)); + VALIDATE_READ(bitStream.Read(score)); + VALIDATE_READ(bitStream.Read(targetID)); + VALIDATE_READ(ReadPoint(bitStream, targetPos)); + return true; + } + + void UpdateShootingGalleryRotation::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(angle); + WritePoint(bitStream, facing); + WritePoint(bitStream, muzzlePos); + } + + bool UpdateShootingGalleryRotation::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(angle)); + VALIDATE_READ(ReadPoint(bitStream, facing)); + VALIDATE_READ(ReadPoint(bitStream, muzzlePos)); + return true; + } + + void ShootingGalleryFire::Serialize(RakNet::BitStream& bitStream) const { + WritePoint(bitStream, target); + bitStream.Write(rotation.w); + bitStream.Write(rotation.x); + bitStream.Write(rotation.y); + bitStream.Write(rotation.z); + } + + bool ShootingGalleryFire::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(ReadPoint(bitStream, target)); + VALIDATE_READ(bitStream.Read(rotation.w)); + VALIDATE_READ(bitStream.Read(rotation.x)); + VALIDATE_READ(bitStream.Read(rotation.y)); + VALIDATE_READ(bitStream.Read(rotation.z)); + return true; + } + + void ShootingGalleryFire::Handle(Entity& entity, const SystemAddress& sysAddr) { + entity.OnShootingGalleryFire(*this); + } + + void ActivityStateChangeRequest::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(objectID); + bitStream.Write(value1); + bitStream.Write(value2); + BitStreamUtils::WriteLengthPrefixed(bitStream, stringValue); + } + + bool ActivityStateChangeRequest::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(objectID)); + VALIDATE_READ(bitStream.Read(value1)); + VALIDATE_READ(bitStream.Read(value2)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, stringValue)); + return true; + } + + void ActivityStateChangeRequest::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* assosiate = Game::entityManager->GetEntity(objectID); + + LOG("%s [%i, %i] from %i to %i", GeneralUtils::UTF16ToWTF8(stringValue).c_str(), value1, value2, entity.GetLOT(), assosiate != nullptr ? assosiate->GetLOT() : 0); + + std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY); + for (Entity* scriptEntity : scriptedActs) { + scriptEntity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); + } + + entity.OnActivityStateChangeRequest(objectID, value1, value2, stringValue); + } } diff --git a/dGame/dGameMessages/ActivityMessages.h b/dGame/dGameMessages/ActivityMessages.h index fff7f8023..ac51e2fbe 100644 --- a/dGame/dGameMessages/ActivityMessages.h +++ b/dGame/dGameMessages/ActivityMessages.h @@ -2,6 +2,8 @@ #define ACTIVITYMESSAGES_H #include "GameMessages.h" +#include "NiQuaternion.h" +#include "eMatchUpdate.h" #include @@ -83,6 +85,112 @@ namespace GameMessages { std::u16string sndName{}; int32_t stateToPlaySoundOn{}; }; + + // Server -> client, to one client. + struct MatchResponse : public NetGameMsg { + MatchResponse() : NetGameMsg(MessageType::Game::MATCH_RESPONSE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int32_t response{}; + }; + + // Server -> client, to one client. + struct MatchUpdate : public NetGameMsg { + MatchUpdate() : NetGameMsg(MessageType::Game::MATCH_UPDATE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + // Name-value (LDF) text. Each byte is widened to one UTF-16 unit on the wire. + std::string data{}; + eMatchUpdate type{}; + }; + + // Client -> server. Join (type 0, value = activity ID) or ready/unready (type 1, value = ready) a match. + struct MatchRequest : public NetGameMsg { + MatchRequest() : NetGameMsg(MessageType::Game::MATCH_REQUEST) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + LWOOBJID activator{}; + // Name-value (LDF) text, narrowed to one byte per character as DLU always did. + std::string playerChoices{}; + int32_t type{}; + int32_t value{}; + }; + + // Client -> server (and server -> client in the client's definition). Answered with the leaderboard. + struct RequestActivitySummaryLeaderboardData : public NetGameMsg { + RequestActivitySummaryLeaderboardData() : NetGameMsg(MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + int32_t gameID{ 0 }; // optional + int32_t queryType{ 1 }; // optional, a Leaderboard::InfoType + int32_t resultsEnd{ 10 }; // optional + int32_t resultsStart{ 0 }; // optional + LWOOBJID targetID{}; // "target" in the client; renamed so it doesn't hide NetGameMsg::target + bool weekly{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). The payload is written by Leaderboard::Serialize. + // When a client sends it, nothing is read (DLU only logs it). + struct SendActivitySummaryLeaderboardData : public NetGameMsg { + SendActivitySummaryLeaderboardData() : NetGameMsg(MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA) {} + void Serialize(RakNet::BitStream& bitStream) const override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + const Leaderboard* leaderboard{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct NotifyClientShootingGalleryScore : public NetGameMsg { + NotifyClientShootingGalleryScore() : NetGameMsg(MessageType::Game::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + float addTime{}; + int32_t score{}; + LWOOBJID targetID{}; + NiPoint3 targetPos{}; + }; + + // Client -> server. Nothing is done with it. + struct UpdateShootingGalleryRotation : public NetGameMsg { + UpdateShootingGalleryRotation() : NetGameMsg(MessageType::Game::UPDATE_SHOOTING_GALLERY_ROTATION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + float angle{}; + NiPoint3 facing{}; + NiPoint3 muzzlePos{}; + }; + + // Client -> server. + struct ShootingGalleryFire : public NetGameMsg { + ShootingGalleryFire() : NetGameMsg(MessageType::Game::SHOOTING_GALLERY_FIRE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + NiPoint3 target{}; + NiQuaternion rotation = QuatUtils::IDENTITY; // written w, x, y, z + }; + + // Client -> server. + struct ActivityStateChangeRequest : public NetGameMsg { + ActivityStateChangeRequest() : NetGameMsg(MessageType::Game::ACTIVITY_STATE_CHANGE_REQUEST) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + LWOOBJID objectID{}; + int32_t value1{}; + int32_t value2{}; + std::u16string stringValue{}; + }; }; #endif // ACTIVITYMESSAGES_H diff --git a/dGame/dGameMessages/BuildingMessages.cpp b/dGame/dGameMessages/BuildingMessages.cpp index e8a2e249f..96a7f0528 100644 --- a/dGame/dGameMessages/BuildingMessages.cpp +++ b/dGame/dGameMessages/BuildingMessages.cpp @@ -728,4 +728,37 @@ namespace GameMessages { } } } + + void SetModelToBuild::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(modelLot != -1); + if (modelLot != -1) bitStream.Write(modelLot); + } + + void SpawnModelBricks::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(amount != 0.0f); + if (amount != 0.0f) bitStream.Write(amount); + bitStream.Write(position != NiPoint3Constant::ZERO); + if (position != NiPoint3Constant::ZERO) { + bitStream.Write(position.x); + bitStream.Write(position.y); + bitStream.Write(position.z); + } + } + + bool SetModelToBuild::Deserialize(RakNet::BitStream& bitStream) { + return BitStreamUtils::ReadOptional(bitStream, modelLot, LOT{ -1 }); + } + + bool SpawnModelBricks::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, amount, 0.0f)); + bool hasPosition{}; + VALIDATE_READ(bitStream.Read(hasPosition)); + position = NiPoint3Constant::ZERO; + if (hasPosition) { + VALIDATE_READ(bitStream.Read(position.x)); + VALIDATE_READ(bitStream.Read(position.y)); + VALIDATE_READ(bitStream.Read(position.z)); + } + return true; + } } diff --git a/dGame/dGameMessages/BuildingMessages.h b/dGame/dGameMessages/BuildingMessages.h index 49e259414..4bf0d36c3 100644 --- a/dGame/dGameMessages/BuildingMessages.h +++ b/dGame/dGameMessages/BuildingMessages.h @@ -205,6 +205,22 @@ namespace GameMessages { std::string lxfmlDataCompressed{}; // u32 byte count, then the bytes uint32_t timeTakenInMs{}; }; + + struct SetModelToBuild : public NetGameMsg { + SetModelToBuild() : NetGameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + LOT modelLot{ -1 }; + }; + + struct SpawnModelBricks : public NetGameMsg { + SpawnModelBricks() : NetGameMsg(MessageType::Game::SPAWN_MODEL_BRICKS) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + float amount{ 0.0f }; + NiPoint3 position{ NiPoint3Constant::ZERO }; + }; }; #endif // BUILDINGMESSAGES_H diff --git a/dGame/dGameMessages/CMakeLists.txt b/dGame/dGameMessages/CMakeLists.txt index 1f95cdd73..c8968f83f 100644 --- a/dGame/dGameMessages/CMakeLists.txt +++ b/dGame/dGameMessages/CMakeLists.txt @@ -8,12 +8,17 @@ set(DGAME_DGAMEMESSAGES_SOURCES "GameMessages.cpp" "InventoryMessages.cpp" "MissionMessages.cpp" + "MovementMessages.cpp" + "ObjectMessages.cpp" "PetMessages.cpp" + "PlayerMessages.cpp" "PropertyMessages.cpp" + "QuickBuildMessages.cpp" "RacingMessages.cpp" "SkillMessages.cpp" "TradeMessages.cpp" - "VendorMessages.cpp") + "VendorMessages.cpp" + "ZoneMessages.cpp") add_library(dGameMessages OBJECT ${DGAME_DGAMEMESSAGES_SOURCES}) target_link_libraries(dGameMessages diff --git a/dGame/dGameMessages/EffectsMessages.cpp b/dGame/dGameMessages/EffectsMessages.cpp index 5fada082c..17fbbbd68 100644 --- a/dGame/dGameMessages/EffectsMessages.cpp +++ b/dGame/dGameMessages/EffectsMessages.cpp @@ -486,4 +486,41 @@ namespace GameMessages { VALIDATE_READ(bitStream.Read(emoteID)); return true; } + + void DisplayTooltip::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(doOrDie); + bitStream.Write(noRepeat); + bitStream.Write(noRevive); + bitStream.Write(isPropertyTooltip); + bitStream.Write(show); + bitStream.Write(translate); + bitStream.Write(time); + bitStream.Write(id.size()); + bitStream.Write(id); + + std::string toWrite; + for (const auto& item : localizeParams | std::views::values) { + toWrite += item->GetString() + "\n"; + } + if (!toWrite.empty()) toWrite.pop_back(); + bitStream.Write(toWrite.size()); + bitStream.Write(GeneralUtils::ASCIIToUTF16(toWrite)); + if (!toWrite.empty()) bitStream.Write(0x00); // Null Terminator + + bitStream.Write(imageName.size()); + bitStream.Write(imageName); + bitStream.Write(text.size()); + bitStream.Write(text); + } + + void EmotePlayed::Serialize(RakNet::BitStream& stream) const { + stream.Write(emoteID); + stream.Write(targetID); + } + + bool EmotePlayed::Deserialize(RakNet::BitStream& stream) { + VALIDATE_READ(stream.Read(emoteID)); + VALIDATE_READ(stream.Read(targetID)); + return true; + } } diff --git a/dGame/dGameMessages/EffectsMessages.h b/dGame/dGameMessages/EffectsMessages.h index 518603524..b6cace93d 100644 --- a/dGame/dGameMessages/EffectsMessages.h +++ b/dGame/dGameMessages/EffectsMessages.h @@ -322,6 +322,32 @@ namespace GameMessages { bool bLock{}; int32_t emoteID{}; }; + + struct DisplayTooltip : public NetGameMsg { + DisplayTooltip() : NetGameMsg(MessageType::Game::DISPLAY_TOOLTIP) {} + bool doOrDie{}; + bool noRepeat{}; + bool noRevive{}; + bool isPropertyTooltip{}; + bool show{}; + bool translate{}; + int32_t time{}; + std::u16string id{}; + LwoNameValue localizeParams{}; + std::u16string imageName{}; + std::u16string text{}; + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + struct EmotePlayed : public NetGameMsg { + EmotePlayed() : NetGameMsg(MessageType::Game::EMOTE_PLAYED), emoteID(0), targetID(0) {} + + void Serialize(RakNet::BitStream& stream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int32_t emoteID; + LWOOBJID targetID; + }; }; #endif // EFFECTSMESSAGES_H diff --git a/dGame/dGameMessages/GameMessageDecoder.cpp b/dGame/dGameMessages/GameMessageDecoder.cpp index 6681c0d53..1b2ee3b96 100644 --- a/dGame/dGameMessages/GameMessageDecoder.cpp +++ b/dGame/dGameMessages/GameMessageDecoder.cpp @@ -6,6 +6,9 @@ #include #include "GameMessages.h" +#include "ActivityMessages.h" +#include "InventoryMessages.h" +#include "ObjectMessages.h" #include "SkillMessages.h" #include "master/MessageCapture.h" diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 89fb16d01..de4e4559e 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -38,6 +38,11 @@ #include "InventoryMessages.h" #include "PetMessages.h" #include "PropertyMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" +#include "PlayerMessages.h" +#include "QuickBuildMessages.h" +#include "ZoneMessages.h" #include "eMissionTaskType.h" #include "eReplicaComponentType.h" #include "ServiceType.h" @@ -168,6 +173,43 @@ namespace { { RESURRECT, []() { return std::make_unique(); } }, { ACTIVATE_BUBBLE_BUFF, []() { return std::make_unique(); } }, { DECTIVATE_BUBBLE_BUFF, []() { return std::make_unique(); } }, + // Zone lifecycle + { PLAYER_LOADED, []() { return std::make_unique(); } }, + { READY_FOR_UPDATES, []() { return std::make_unique(); } }, + { NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE, []() { return std::make_unique(); } }, + { ZONE_SUMMARY_DISMISSED, []() { return std::make_unique(); } }, + { MISSION_DIALOGUE_CANCELLED, []() { return std::make_unique(); } }, + + // Objects and scripts + { FIRE_EVENT_SERVER_SIDE, []() { return std::make_unique(); } }, + + // Player state, chat commands, reports + { PARSE_CHAT_MESSAGE, []() { return std::make_unique(); } }, + { PICKUP_CURRENCY, []() { return std::make_unique(); } }, + { MODIFY_PLAYER_ZONE_STATISTIC, []() { return std::make_unique(); } }, + { UPDATE_PLAYER_STATISTIC, []() { return std::make_unique(); } }, + { REPORT_BUG, []() { return std::make_unique(); } }, + { VERIFY_ACK, []() { return std::make_unique(); } }, + + // Quickbuilds + { REBUILD_CANCEL, []() { return std::make_unique(); } }, + + // Activities, matches, leaderboards, shooting galleries + { MATCH_REQUEST, []() { return std::make_unique(); } }, + { REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA, []() { return std::make_unique(); } }, + { SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA, []() { return std::make_unique(); } }, + { ACTIVITY_STATE_CHANGE_REQUEST, []() { return std::make_unique(); } }, + { UPDATE_SHOOTING_GALLERY_ROTATION, []() { return std::make_unique(); } }, + + // Movement: platforms, rails, mounts, ghosting + { REQUEST_PLATFORM_RESYNC, []() { return std::make_unique(); } }, + { CLIENT_RAIL_MOVEMENT_READY, []() { return std::make_unique(); } }, + { CANCEL_RAIL_MOVEMENT, []() { return std::make_unique(); } }, + { PLAYER_RAIL_ARRIVED_NOTIFICATION, []() { return std::make_unique(); } }, + { DISMOUNT_COMPLETE, []() { return std::make_unique(); } }, + { ACKNOWLEDGE_POSSESSION, []() { return std::make_unique(); } }, + { TOGGLE_GHOST_REFERENCE_OVERRIDE, []() { return std::make_unique(); } }, + { SET_GHOST_REFERENCE_POSITION, []() { return std::make_unique(); } }, }; }; @@ -175,8 +217,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System // The dashboard's message inspector (sees every message a client sends; nothing to do unless a capture runs) if (MessageInspector::IsCapturing()) MessageInspector::RecordReceived(sysAddr, objectID, messageID, inStream); - CBITSTREAM; - // Get the entity Entity* entity = Game::entityManager->GetEntity(objectID); @@ -216,218 +256,5 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System return; } - switch (messageID) { - - case MessageType::Game::PLAYER_LOADED: { - GameMessages::SendPlayerReady(entity, sysAddr); - entity->SetPlayerReadyForUpdates(); - - auto* ghostComponent = entity->GetComponent(); - if (ghostComponent != nullptr) { - ghostComponent->ConstructLimboEntities(); - } - - InventoryComponent* inv = entity->GetComponent(); - if (inv) { - // Clear server-side skill state so AddItemSkills sends fresh AddSkill - // packets to the now-ready client. Skills sent during entity construction - // (Serialize) arrive before LWOSkillComponent is initialized and are dropped. - inv->ClearSkills(); - auto items = inv->GetEquippedItems(); - for (auto pair : items) { - const auto item = pair.second; - - inv->AddItemSkills(item.lot); - } - - // Fixes a bug where testmapping too fast causes large item inventories to become invisible. - // Only affects item inventory - GameMessages::SetInventorySize setSize; - setSize.target = entity->GetObjectID(); - setSize.inventoryType = eInventoryType::ITEMS; - setSize.size = inv->GetInventory(eInventoryType::ITEMS)->GetSize(); - setSize.SendToClient(entity->GetSystemAddress()); - } - - GameMessages::SendRestoreToPostLoadStats(entity, sysAddr); - - auto* const destroyable = entity->GetComponent(); - if (destroyable) destroyable->SetImagination(destroyable->GetImagination()); - Game::entityManager->SerializeEntity(entity); - - std::vector racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); - for (Entity* racingController : racingControllers) { - auto* racingComponent = racingController->GetComponent(); - if (racingComponent != nullptr) { - racingComponent->OnPlayerLoaded(entity); - } - } - - Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); - if (zoneControl) { - zoneControl->GetScript()->OnPlayerLoaded(zoneControl, entity); - } - - std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); - for (Entity* scriptEntity : scriptedActs) { - if (!zoneControl || scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - scriptEntity->GetScript()->OnPlayerLoaded(scriptEntity, entity); - } - } - - //Kill player if health == 0 - if (entity->GetIsDead()) { - entity->Smash(entity->GetObjectID()); - } - - //if the player has moved significantly, move them back: - if ((entity->GetPosition().y - entity->GetCharacter()->GetOriginalPos().y) > 2.0f) { - // Disabled until fixed - //GameMessages::SendTeleport(entity->GetObjectID(), entity->GetCharacter()->GetOriginalPos(), entity->GetCharacter()->GetOriginalRot(), entity->GetSystemAddress(), true, true); - } - - /** - * Invoke the OnZoneLoad event on the player character - */ - auto* character = entity->GetCharacter(); - - if (character != nullptr) { - character->OnZoneLoad(); - } - - // Moved here from another instance: put back what their save doesn't keep (the pet that was out) - WorldMigration::OnPlayerLoaded(entity); - - LOG("Player %s (%llu) loaded.", entity->GetCharacter()->GetName().c_str(), entity->GetObjectID()); - - // After we've done our thing, tell the client they're ready - GameMessages::SendPlayerReady(Game::zoneManager->GetZoneControlObject(), sysAddr); - - if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1" - || !entity->GetCharacter() - || !entity->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return; - entity->AddCallbackTimer(0.5f, [entity, sysAddr]() { - if (!entity) return; - GameMessages::EndCinematic endCinematic; - endCinematic.target = entity->GetObjectID(); - endCinematic.Send(sysAddr); - }); - break; - } - - case MessageType::Game::MISSION_DIALOGUE_CANCELLED: { - // This message is pointless for our implementation, as the client just carries on after - // rejecting a mission offer. We dont need to do anything. This is just here to remove a warning in our logs :) - break; - } - - case MessageType::Game::REQUEST_PLATFORM_RESYNC: { - GameMessages::HandleRequestPlatformResync(inStream, entity, sysAddr); - break; - } - - case MessageType::Game::FIRE_EVENT_SERVER_SIDE: { - GameMessages::HandleFireEventServerSide(inStream, entity, sysAddr); - break; - } - - case MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { - GameMessages::HandleActivitySummaryLeaderboardData(inStream, entity, sysAddr); - break; - } - - case MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { - GameMessages::HandleRequestActivitySummaryLeaderboardData(inStream, entity, sysAddr); - break; - } - - case MessageType::Game::ACTIVITY_STATE_CHANGE_REQUEST: { - GameMessages::HandleActivityStateChangeRequest(inStream, entity); - break; - } - - case MessageType::Game::PARSE_CHAT_MESSAGE: { - GameMessages::HandleParseChatMessage(inStream, entity, sysAddr); - break; - } - - case MessageType::Game::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE: { - GameMessages::HandleNotifyServerLevelProcessingComplete(inStream, entity); - break; - } - - case MessageType::Game::PICKUP_CURRENCY: { - GameMessages::HandlePickupCurrency(inStream, entity); - break; - } - - case MessageType::Game::REBUILD_CANCEL: - GameMessages::HandleQuickBuildCancel(inStream, entity); - break; - - case MessageType::Game::MATCH_REQUEST: - GameMessages::HandleMatchRequest(inStream, entity); - break; - - case MessageType::Game::VERIFY_ACK: - GameMessages::HandleVerifyAck(inStream, entity, sysAddr); - break; - - // Trading - case MessageType::Game::ACKNOWLEDGE_POSSESSION: - GameMessages::HandleAcknowledgePossession(inStream, entity, sysAddr); - break; - - case MessageType::Game::UPDATE_SHOOTING_GALLERY_ROTATION: - GameMessages::HandleUpdateShootingGalleryRotation(inStream, entity, sysAddr); - break; - - // NT - case MessageType::Game::TOGGLE_GHOST_REFERENCE_OVERRIDE: - GameMessages::HandleToggleGhostReferenceOverride(inStream, entity, sysAddr); - break; - - case MessageType::Game::SET_GHOST_REFERENCE_POSITION: - GameMessages::HandleSetGhostReferencePosition(inStream, entity, sysAddr); - break; - - case MessageType::Game::READY_FOR_UPDATES: - //We don't really care about this message, as it's simply here to inform us that the client is done loading an object. - //In the event we _do_ send an update to an object that hasn't finished loading, the client will handle it anyway. - break; - - case MessageType::Game::REPORT_BUG: - GameMessages::HandleReportBug(inStream, entity); - break; - - case MessageType::Game::CLIENT_RAIL_MOVEMENT_READY: - GameMessages::HandleClientRailMovementReady(inStream, entity, sysAddr); - break; - - case MessageType::Game::CANCEL_RAIL_MOVEMENT: - GameMessages::HandleCancelRailMovement(inStream, entity, sysAddr); - break; - - case MessageType::Game::PLAYER_RAIL_ARRIVED_NOTIFICATION: - GameMessages::HandlePlayerRailArrivedNotification(inStream, entity, sysAddr); - break; - - case MessageType::Game::MODIFY_PLAYER_ZONE_STATISTIC: - GameMessages::HandleModifyPlayerZoneStatistic(inStream, entity); - break; - - case MessageType::Game::UPDATE_PLAYER_STATISTIC: - GameMessages::HandleUpdatePlayerStatistic(inStream, entity); - break; - - case MessageType::Game::DISMOUNT_COMPLETE: - GameMessages::HandleDismountComplete(inStream, entity, sysAddr); - break; - case MessageType::Game::ZONE_SUMMARY_DISMISSED: - GameMessages::HandleZoneSummaryDismissed(inStream, entity); - break; - default: - LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); - break; - } + LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); } diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 82bca7225..48c1e72b1 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -1,1570 +1,12 @@ #include "GameMessages.h" -#include "EffectsMessages.h" -#include "InventoryMessages.h" -#include "DashboardNotify.h" -#include "PlayerReports.h" -#include "EconomyLedger.h" -#include "User.h" -#include "Entity.h" -#include "BitStreamUtils.h" + #include "BitStream.h" -#include "Game.h" -#include "SlashCommandHandler.h" -#include "NiPoint3.h" -#include "NiQuaternion.h" -#include "Logger.h" -#include "GeneralUtils.h" -#include "Character.h" +#include "BitStreamUtils.h" #include "EntityManager.h" -#include "Database.h" -#include "dServer.h" -#include "ObjectIDManager.h" -#include "CppScripts.h" -#include "UserManager.h" -#include "ZoneInstanceManager.h" -#include "ClientPackets.h" -#include "Item.h" -#include "ZCompression.h" -#include "dConfig.h" -#include "TeamManager.h" -#include "ChatPackets.h" -#include "MultiZoneEntranceComponent.h" -#include "eUnequippableActiveType.h" -#include "eMovementPlatformState.h" -#include "LeaderboardManager.h" -#include "Amf3.h" -#include "Loot.h" -#include "eRacingTaskParam.h" -#include "eMissionTaskType.h" -#include "eMissionState.h" -#include "eObjectBits.h" -#include "eTriggerEventType.h" -#include "eMatchUpdate.h" -#include "eCyclingMode.h" -#include "eCinematicEvent.h" -#include "eQuickBuildFailReason.h" -#include "eControlScheme.h" -#include "eStateChangeType.h" -#include "ServiceType.h" -#include "ePlayerFlag.h" - -#include -#include -#include -#include -#include "RakString.h" - -//CDB includes: -#include "CDClientManager.h" -#include "CDEmoteTable.h" - -//Component includes: -#include "ControllablePhysicsComponent.h" -#include "CharacterComponent.h" -#include "MissionOfferComponent.h" -#include "MissionComponent.h" -#include "DestroyableComponent.h" -#include "ScriptComponent.h" -#include "QuickBuildComponent.h" -#include "VendorComponent.h" -#include "InventoryComponent.h" -#include "RocketLaunchpadControlComponent.h" -#include "PropertyEntranceComponent.h" -#include "MovingPlatformComponent.h" -#include "PetComponent.h" -#include "ModuleAssemblyComponent.h" -#include "HavokVehiclePhysicsComponent.h" -#include "RenderComponent.h" -#include "PossessableComponent.h" -#include "PossessorComponent.h" -#include "RacingControlComponent.h" -#include "RailActivatorComponent.h" -#include "LevelProgressionComponent.h" -#include "DonationVendorComponent.h" -#include "GhostComponent.h" -#include "AchievementVendorComponent.h" - -// Message includes: -#include "dZoneManager.h" -#include "PropertyManagementComponent.h" -#include "PropertyVendorComponent.h" -#include "TradingManager.h" -#include "ControlBehaviors.h" -#include "AMFDeserialize.h" -#include "eBlueprintSaveResponseType.h" -#include "eAnimationFlags.h" -#include "AmfSerialize.h" -#include "eReplicaComponentType.h" +#include "Game.h" #include "MessageType/Client.h" -#include "MessageType/Game.h" -#include "ePetAbilityType.h" -#include "ActivityManager.h" -#include "PlayerManager.h" -#include "eVendorTransactionResult.h" -#include "eReponseMoveItemBetweenInventoryTypeCode.h" - -#include "CDComponentsRegistryTable.h" -#include "CDObjectsTable.h" -#include "eItemType.h" -#include "Lxfml.h" -#include "Sd0.h" - -void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::FIRE_EVENT_CLIENT_SIDE); - - //bitStream.Write(args); - uint32_t argSize = args.size(); - bitStream.Write(argSize); - for (uint32_t k = 0; k < argSize; k++) { - bitStream.Write(args[k]); - } - bitStream.Write(object); - bitStream.Write0(); - //bitStream.Write(param1); - bitStream.Write0(); - //bitStream.Write(param2); - bitStream.Write(sender); - - SEND_PACKET; -} - -void GameMessages::SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::TELEPORT); - - bool bIgnoreY = (pos.y == 0.0f); - bool bUseNavmesh = false; - bool bSkipAllChecks = false; - //float w = 1.0f; - //float x = 0.0f; - //float y = 0.0f; - //float z = 0.0f; - - bitStream.Write(bIgnoreY); - bitStream.Write(bSetRotation); - bitStream.Write(bSkipAllChecks); - bitStream.Write(pos.x); - bitStream.Write(pos.y); - bitStream.Write(pos.z); - bitStream.Write(bUseNavmesh); - - bitStream.Write(rot.w != 1.0f); - if (rot.w != 1.0f) bitStream.Write(rot.w); - - bitStream.Write(rot.x); - bitStream.Write(rot.y); - bitStream.Write(rot.z); - - SEND_PACKET; -} - -void GameMessages::SendPlayerReady(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLAYER_READY); - SEND_PACKET; -} - -void GameMessages::SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::INVALID_ZONE_TRANSFER_LIST); - - uint32_t CustomerFeedbackURLLength = feedbackURL.size(); - bitStream.Write(CustomerFeedbackURLLength); - for (uint32_t k = 0; k < CustomerFeedbackURLLength; k++) { - bitStream.Write(feedbackURL[k]); - } - - uint32_t InvalidMapTransferListLength = invalidMapTransferList.size(); - bitStream.Write(InvalidMapTransferListLength); - for (uint32_t k = 0; k < InvalidMapTransferListLength; k++) { - bitStream.Write(invalidMapTransferList[k]); - } - - bitStream.Write(feedbackOnExit); - bitStream.Write(feedbackOnInvalidTransfer); - - SEND_PACKET; -} - -void GameMessages::SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, - bool bAllowCyclingWhileDeadOnly, eCyclingMode cyclingMode) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::PLAYER_SET_CAMERA_CYCLING_MODE); - - bitStream.Write(bAllowCyclingWhileDeadOnly); - - bitStream.Write(cyclingMode != eCyclingMode::ALLOW_CYCLE_TEAMMATES); - if (cyclingMode != eCyclingMode::ALLOW_CYCLE_TEAMMATES) { - bitStream.Write(cyclingMode); - } - - SEND_PACKET; -} - -void GameMessages::SendStartPathing(Entity* entity) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::START_PATHING); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint, - int iIndex, int iDesiredWaypointIndex, int nextIndex, - eMovementPlatformState movementState, bool special) { - CBITSTREAM; - CMSGHEADER; - - const auto objID = entity->GetObjectID(); - const auto lot = entity->GetLOT(); - - if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449 || lot == 11306 || lot == 11308 || lot == 9483) { - iDesiredWaypointIndex = (lot == 11306 || lot == 11308) ? 1 : 0; - iIndex = lot == 9483 ? 1 : 0; - nextIndex = lot == 9483 && !special ? 1 : 0; - bStopAtDesiredWaypoint = true; - movementState = lot == 9483 && !special ? eMovementPlatformState::Stopped : eMovementPlatformState::Stationary; - } - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLATFORM_RESYNC); - - bool bReverse = false; - int eCommand = 0; - int eUnexpectedCommand = 0; - float fIdleTimeElapsed = 0.0f; - float fMoveTimeElapsed = 0.0f; - float fPercentBetweenPoints = 0.0f; - NiPoint3 ptUnexpectedLocation = NiPoint3Constant::ZERO; - NiQuaternion qUnexpectedRotation = QuatUtils::IDENTITY; - - bitStream.Write(bReverse); - bitStream.Write(bStopAtDesiredWaypoint); - bitStream.Write(eCommand); - bitStream.Write(static_cast(movementState)); - bitStream.Write(eUnexpectedCommand); - bitStream.Write(fIdleTimeElapsed); - bitStream.Write(fMoveTimeElapsed); - bitStream.Write(fPercentBetweenPoints); - bitStream.Write(iDesiredWaypointIndex); - bitStream.Write(iIndex); - bitStream.Write(nextIndex); - bitStream.Write(ptUnexpectedLocation.x); - bitStream.Write(ptUnexpectedLocation.y); - bitStream.Write(ptUnexpectedLocation.z); - - bitStream.Write(qUnexpectedRotation != QuatUtils::IDENTITY); - if (qUnexpectedRotation != QuatUtils::IDENTITY) { - bitStream.Write(qUnexpectedRotation.x); - bitStream.Write(qUnexpectedRotation.y); - bitStream.Write(qUnexpectedRotation.z); - bitStream.Write(qUnexpectedRotation.w); - } - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::RESTORE_TO_POST_LOAD_STATS); - SEND_PACKET; -} - -void GameMessages::SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SERVER_DONE_LOADING_ALL_OBJECTS); - SEND_PACKET; -} - -void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::UPDATE_CHAT_MODE); - bitStream.Write(level); - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::SET_GM_LEVEL); - bitStream.Write1(); - bitStream.Write(level); - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectWorldState state, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::CHANGE_OBJECT_WORLD_STATE); - bitStream.Write(state); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST - SEND_PACKET; -} - -void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::MODIFY_LEGO_SCORE); - bitStream.Write(score); - - bitStream.Write(sourceType != eLootSourceType::NONE); - if (sourceType != eLootSourceType::NONE) bitStream.Write(sourceType); - - SEND_PACKET; -} - -void GameMessages::SendSetCurrency(Entity* entity, int64_t currency, int lootType, const LWOOBJID& sourceID, const LOT& sourceLOT, int sourceTradeID, bool overrideCurrent, eLootSourceType sourceType) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SET_CURRENCY); - - bitStream.Write(currency); - - bitStream.Write(lootType != LOOTTYPE_NONE); - if (lootType != LOOTTYPE_NONE) bitStream.Write(lootType); - - bitStream.Write(NiPoint3Constant::ZERO); - - bitStream.Write(sourceLOT != LOT_NULL); - if (sourceLOT != LOT_NULL) bitStream.Write(sourceLOT); - - bitStream.Write(sourceID != LWOOBJID_EMPTY); - if (sourceID != LWOOBJID_EMPTY) bitStream.Write(sourceID); - - bitStream.Write(sourceTradeID != LWOOBJID_EMPTY); - if (sourceTradeID != LWOOBJID_EMPTY) bitStream.Write(sourceTradeID); - - bitStream.Write(sourceType != eLootSourceType::NONE); - if (sourceType != eLootSourceType::NONE) bitStream.Write(sourceType); - - SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - -void GameMessages::SendQuickBuildNotifyState(Entity* entity, eQuickBuildState prevState, eQuickBuildState state, const LWOOBJID& playerID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::REBUILD_NOTIFY_STATE); - - bitStream.Write(prevState); - bitStream.Write(state); - bitStream.Write(playerID); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendEnableQuickBuild(Entity* entity, bool enable, bool fail, bool success, eQuickBuildFailReason failReason, float duration, const LWOOBJID& playerID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::ENABLE_REBUILD); - - bitStream.Write(enable); - bitStream.Write(fail); - bitStream.Write(success); - - bitStream.Write(failReason != eQuickBuildFailReason::NOT_GIVEN); - if (failReason != eQuickBuildFailReason::NOT_GIVEN) bitStream.Write(failReason); - - bitStream.Write(duration); - bitStream.Write(playerID); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendTerminateInteraction(const LWOOBJID& objectID, eTerminateType type, const LWOOBJID& terminator) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::TERMINATE_INTERACTION); - - bitStream.Write(terminator); - bitStream.Write(type); - - SEND_PACKET_BROADCAST; -} - -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) { - fAirspeed = 75; - fMaxAirspeed = 75; - fVertVel = 15; - } - */ - - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SET_JET_PACK_MODE); - - bitStream.Write(bypassChecks); - bitStream.Write(doHover); - bitStream.Write(use); - - bitStream.Write(effectID != -1); - if (effectID != -1) bitStream.Write(effectID); - - bitStream.Write(airspeed != 10); - if (airspeed != 10) bitStream.Write(airspeed); - - bitStream.Write(maxAirspeed != 15); - if (maxAirspeed != 15) bitStream.Write(maxAirspeed); - - bitStream.Write(verticalVelocity != 1); - if (verticalVelocity != 1) bitStream.Write(verticalVelocity); - - bitStream.Write(warningEffectID != -1); - if (warningEffectID != -1) bitStream.Write(warningEffectID); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SCRIPT_NETWORK_VAR_UPDATE); - - // FIXME: this is a bad place to need to do a conversion because we have no clue whether data is utf8 or plain ascii - // an this has performance implications - const auto u16Data = GeneralUtils::ASCIIToUTF16(data); - uint32_t dataSize = static_cast(u16Data.size()); - - bitStream.Write(dataSize); - for (auto value : u16Data) { - bitStream.Write(value); - } - if (dataSize > 0) bitStream.Write(0); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme) { - CBITSTREAM; - CMSGHEADER; - - bool bDelayCamSwitchIfInCinematic = true; - bool bSwitchCam = true; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SET_PLAYER_CONTROL_SCHEME); - - bitStream.Write(bDelayCamSwitchIfInCinematic); - bitStream.Write(bSwitchCam); - - bitStream.Write(controlScheme != eControlScheme::SCHEME_A); - if (controlScheme != eControlScheme::SCHEME_A) bitStream.Write(controlScheme); - - SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - -void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPoint3& position, const NiQuaternion& rotation) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::PLAYER_REACHED_RESPAWN_CHECKPOINT); - - bitStream.Write(position.x); - bitStream.Write(position.y); - bitStream.Write(position.z); - - const bool bIsNotIdentity = rotation != QuatUtils::IDENTITY; - bitStream.Write(bIsNotIdentity); - - if (bIsNotIdentity) { - bitStream.Write(rotation.w); - bitStream.Write(rotation.x); - bitStream.Write(rotation.y); - bitStream.Write(rotation.z); - } - - SystemAddress sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - -void GameMessages::SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::MATCH_RESPONSE); - bitStream.Write(response); - - SEND_PACKET; -} - -void GameMessages::SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::MATCH_UPDATE); - bitStream.Write(data.size()); - for (char character : data) { - bitStream.Write(character); - } - if (data.size() > 0) bitStream.Write(0); - bitStream.Write(type); - - SEND_PACKET; -} - -void GameMessages::SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, - const SystemAddress& sysAddr, const int32_t& gameID, - const int32_t& queryType, const int32_t& resultsEnd, - const int32_t& resultsStart, bool weekly) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA); - - bitStream.Write(gameID != 0); - if (gameID != 0) { - bitStream.Write(gameID); - } - - bitStream.Write(queryType != 1); - if (queryType != 1) { - bitStream.Write(queryType); - } - - bitStream.Write(resultsEnd != 10); - if (resultsEnd != 10) { - bitStream.Write(resultsEnd); - } - - bitStream.Write(resultsStart != 0); - if (resultsStart != 0) { - bitStream.Write(resultsStart); - } - - bitStream.Write(targetID); - bitStream.Write(weekly); - - SEND_PACKET; -} - -void GameMessages::SendSetShootingGalleryParams(LWOOBJID objectId, const SystemAddress& sysAddr, - float cameraFOV, - float cooldown, - float minDistance, - NiPoint3 muzzlePosOffset, - NiPoint3 playerPosOffset, - float projectileVelocity, - float timeLimit, - bool bUseLeaderboards) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::SET_SHOOTING_GALLERY_PARAMS); - /* - bitStream.Write(cameraFOV); - bitStream.Write(cooldown); - bitStream.Write(minDistance); - bitStream.Write(muzzlePosOffset); - bitStream.Write(playerPosOffset); - bitStream.Write(projectileVelocity); - bitStream.Write(timeLimit); - bitStream.Write(bUseLeaderboards); - */ - // No clue about the order here - bitStream.Write(playerPosOffset); - bitStream.Write(projectileVelocity); - bitStream.Write(cooldown); - bitStream.Write(muzzlePosOffset); - bitStream.Write(minDistance); - bitStream.Write(cameraFOV); - bitStream.Write(bUseLeaderboards); - bitStream.Write(timeLimit); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - - -void GameMessages::SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const SystemAddress& sysAddr, - float addTime, - int32_t score, - LWOOBJID target, - NiPoint3 targetPos) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE); - bitStream.Write(addTime); - bitStream.Write(score); - bitStream.Write(target); - bitStream.Write(targetPos); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - - -void GameMessages::HandleUpdateShootingGalleryRotation(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - float angle = 0.0f; - NiPoint3 facing = NiPoint3Constant::ZERO; - NiPoint3 muzzlePos = NiPoint3Constant::ZERO; - inStream.Read(angle); - inStream.Read(facing); - inStream.Read(muzzlePos); -} - - -void GameMessages::HandleActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, - const SystemAddress& sysAddr) { - LOG("We got mail!"); -} - -void GameMessages::SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); - - leaderboard->Serialize(bitStream); - SEND_PACKET; -} - -void GameMessages::HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - int32_t gameID = 0; - if (inStream.ReadBit()) inStream.Read(gameID); - - Leaderboard::InfoType queryType = Leaderboard::InfoType::MyStanding; - if (inStream.ReadBit()) inStream.Read(queryType); - - int32_t resultsEnd = 10; - if (inStream.ReadBit()) inStream.Read(resultsEnd); - - int32_t resultsStart = 0; - if (inStream.ReadBit()) inStream.Read(resultsStart); - - LWOOBJID target{}; - inStream.Read(target); - - bool weekly = inStream.ReadBit(); - - // The client won't accept more than 10 results even if we wanted it to - LeaderboardManager::SendLeaderboard(gameID, queryType, weekly, entity->GetObjectID(), entity->GetObjectID(), 10); -} - -void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream& inStream, Entity* entity) { - LWOOBJID objectID; - inStream.Read(objectID); - - int32_t value1; - inStream.Read(value1); - - int32_t value2; - inStream.Read(value2); - - uint32_t stringValueLength; - inStream.Read(stringValueLength); - - std::u16string stringValue; - for (uint32_t i = 0; i < stringValueLength; ++i) { - uint16_t character; - inStream.Read(character); - stringValue.push_back(character); - } - - auto* assosiate = Game::entityManager->GetEntity(objectID); - - LOG("%s [%i, %i] from %i to %i", GeneralUtils::UTF16ToWTF8(stringValue).c_str(), value1, value2, entity->GetLOT(), assosiate != nullptr ? assosiate->GetLOT() : 0); - - std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY); - for (Entity* scriptEntity : scriptedActs) { - scriptEntity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); - } - - entity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); -} - -void GameMessages::SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, - uint32_t pathStart, const SystemAddress& sysAddr, int32_t railActivatorComponentID, - LWOOBJID railActivatorObjectID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::SET_RAIL_MOVEMENT); - - bitStream.Write(pathGoForward); - - bitStream.Write(pathName.size()); - for (auto character : pathName) { - bitStream.Write(character); - } - - bitStream.Write(pathStart); - - const auto componentIDIsDefault = railActivatorComponentID == -1; - bitStream.Write(!componentIDIsDefault); - if (!componentIDIsDefault) - bitStream.Write(railActivatorComponentID); - - const auto activatorObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; - bitStream.Write(!activatorObjectIDIsDefault); - if (!activatorObjectIDIsDefault) - bitStream.Write(railActivatorObjectID); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendStartRailMovement(const LWOOBJID& objectID, std::u16string pathName, std::u16string startSound, - std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr, - uint32_t pathStart, bool goForward, bool damageImmune, bool noAggro, bool notifyActor, - bool showNameBillboard, bool cameraLocked, bool collisionEnabled, bool useDB, - int32_t railComponentID, LWOOBJID railActivatorObjectID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::START_RAIL_MOVEMENT); - - bitStream.Write(damageImmune); - bitStream.Write(noAggro); - bitStream.Write(notifyActor); - bitStream.Write(showNameBillboard); - bitStream.Write(cameraLocked); - bitStream.Write(collisionEnabled); - - bitStream.Write(loopSound.size()); - for (auto character : loopSound) { - bitStream.Write(character); - } - - bitStream.Write(goForward); - - bitStream.Write(pathName.size()); - for (auto character : pathName) { - bitStream.Write(character); - } - - const auto pathStartIsDefault = pathStart == 0; - bitStream.Write(!pathStartIsDefault); - if (!pathStartIsDefault) { - bitStream.Write(pathStart); - } - - const auto railComponentIDIsDefault = railComponentID == -1; - bitStream.Write(!railComponentIDIsDefault); - if (!railComponentIDIsDefault) { - bitStream.Write(railComponentID); - } - - const auto railObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; - bitStream.Write(!railObjectIDIsDefault); - if (!railObjectIDIsDefault) { - bitStream.Write(railActivatorObjectID); - } - - bitStream.Write(startSound.size()); - for (auto character : startSound) { - bitStream.Write(character); - } - - bitStream.Write(stopSound.size()); - for (auto character : stopSound) { - bitStream.Write(character); - } - - bitStream.Write(useDB); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16string name, int param1, int param2, const LWOOBJID& paramObj, std::string paramStr, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::NOTIFY_CLIENT_OBJECT); - - bitStream.Write(name.size()); - for (auto character : name) { - bitStream.Write(character); - } - - bitStream.Write(param1); - - bitStream.Write(param2); - - bitStream.Write(paramObj); - - bitStream.Write(paramStr.size()); - for (auto character : paramStr) { - bitStream.Write(character); - } - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendNotifyClientZoneObject(const LWOOBJID& objectID, const std::u16string& name, int param1, - int param2, const LWOOBJID& paramObj, const std::string& paramStr, - const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::NOTIFY_CLIENT_ZONE_OBJECT); - - bitStream.Write(name.size()); - for (const auto& character : name) { - bitStream.Write(character); - } - - bitStream.Write(param1); - bitStream.Write(param2); - bitStream.Write(paramObj); - - bitStream.Write(paramStr.size()); - for (const auto& character : paramStr) { - bitStream.Write(character); - } - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendNotifyClientFailedPrecondition(LWOOBJID objectId, const SystemAddress& sysAddr, - const std::u16string& failedReason, int preconditionID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::NOTIFY_CLIENT_FAILED_PRECONDITION); - - bitStream.Write(failedReason.size()); - for (uint16_t character : failedReason) { - bitStream.Write(character); - } - - bitStream.Write(preconditionID); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::SendSetName(LWOOBJID objectID, std::u16string name, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectID); - bitStream.Write(MessageType::Game::SET_NAME); - - bitStream.Write(name.size()); - - for (size_t i = 0; i < name.size(); ++i) - bitStream.Write(name[i]); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -// Property - -void GameMessages::SendLockNodeRotation(Entity* entity, std::string nodeName) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::LOCK_NODE_ROTATION); - - bitStream.Write(nodeName.size()); - for (char character : nodeName) { - bitStream.Write(character); - } - - SEND_PACKET_BROADCAST; -} - -void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::ORIENT_TO_ANGLE); - - bitStream.Write(bRelativeToCurrent); - bitStream.Write(fAngle); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - - -void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1, int param2) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::NOTIFY_OBJECT); - - bitStream.Write(objIDSender); - bitStream.Write(name.size()); - for (const auto character : name) { - bitStream.Write(character); - } - - bitStream.Write(param1); - bitStream.Write(param2); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -void GameMessages::HandleVerifyAck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - bool bDifferent; - std::string sBitStream; - uint32_t uiHandle = 0; - - bDifferent = inStream.ReadBit(); - - uint32_t sBitStreamLength = 0; - inStream.Read(sBitStreamLength); - if (sBitStreamLength > MAX_MESSAGE_LENGTH) return; - for (uint64_t k = 0; k < sBitStreamLength; k++) { - uint8_t character; - inStream.Read(character); - sBitStream.push_back(character); - } - - if (inStream.ReadBit()) { - inStream.Read(uiHandle); - } -} - -void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::TEAM_PICKUP_ITEM); - - bitStream.Write(lootID); - bitStream.Write(lootOwnerID); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -//Pets: - -void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::DISPLAY_ZONE_SUMMARY); - - bitStream.Write(isPropertyMap); - bitStream.Write(isZoneStart); - bitStream.Write(sender != LWOOBJID_EMPTY); - if (sender != LWOOBJID_EMPTY) bitStream.Write(sender); - - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; - SEND_PACKET; -} - -//UI - -// Mounts - -void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::SET_MOUNT_INVENTORY_ID); - bitStream.Write(objectID != LWOOBJID_EMPTY); - if (objectID != LWOOBJID_EMPTY) bitStream.Write(objectID); - - SEND_PACKET_BROADCAST; -} - -void GameMessages::UseSkillSet::Serialize(RakNet::BitStream& bitStream) const { - bitStream.Write(bRemove); - bitStream.Write(possessedId != LWOOBJID_EMPTY); - if (possessedId != LWOOBJID_EMPTY) bitStream.Write(possessedId); - bitStream.Write(setId != -1); - if (setId != -1) bitStream.Write(setId); -} - -void GameMessages::HandleDismountComplete(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - // Get the objectID from the bitstream - LWOOBJID objectId{}; - inStream.Read(objectId); - - // If we aren't possessing somethings, the don't do anything - if (objectId != LWOOBJID_EMPTY) { - auto* possessorComponent = entity->GetComponent(); - auto* mount = Game::entityManager->GetEntity(objectId); - // make sure we have the things we need and they aren't null - if (possessorComponent && mount) { - if (!possessorComponent->GetIsDismounting()) return; - possessorComponent->SetIsDismounting(false); - possessorComponent->SetPossessable(LWOOBJID_EMPTY); - possessorComponent->SetPossessableType(ePossessionType::NO_POSSESSION); - - // character related things - auto* character = entity->GetComponent(); - if (character) { - // If we had an active item turn it off - if (possessorComponent->GetMountItemID() != LWOOBJID_EMPTY) { - GameMessages::MarkInventoryItemAsActive markActive; - markActive.target = entity->GetObjectID(); - markActive.bActive = false; - markActive.iType = eUnequippableActiveType::MOUNT; - markActive.itemID = possessorComponent->GetMountItemID(); - markActive.Send(entity->GetSystemAddress()); - } - possessorComponent->SetMountItemID(LWOOBJID_EMPTY); - } - - // Set that the controllabel phsyics comp is teleporting - auto* controllablePhysicsComponent = entity->GetComponent(); - if (controllablePhysicsComponent) controllablePhysicsComponent->SetIsTeleporting(true); - - // Call dismoint on the possessable comp to let it handle killing the possessable - auto* possessableComponent = mount->GetComponent(); - if (possessableComponent) possessableComponent->Dismount(); - - // Update the entity that was possessing - Game::entityManager->SerializeEntity(entity); - } - } -} - - -void GameMessages::HandleAcknowledgePossession(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - Game::entityManager->SerializeEntity(entity); - bool hasObjectId{}; - inStream.Read(hasObjectId); - if (hasObjectId) { - LWOOBJID objectId{}; - inStream.Read(objectId); - auto* mount = Game::entityManager->GetEntity(objectId); - if (mount) Game::entityManager->SerializeEntity(mount); - } -} - -//Racing - - - - - -void GameMessages::SendUpdateReputation(const LWOOBJID objectId, const int64_t reputation, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(objectId); - bitStream.Write(MessageType::Game::UPDATE_REPUTATION); - - bitStream.Write(reputation); - - SEND_PACKET; -} - -// NT - -//----------------------------------------------------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------- Handlers ------------------------------------------------------------------ -//----------------------------------------------------------------------------------------------------------------------------------------------- - -void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - bool bOverride = false; - - inStream.Read(bOverride); - - auto* player = PlayerManager::GetPlayer(sysAddr); - - if (player != nullptr) { - auto* ghostComponent = entity->GetComponent(); - if (ghostComponent) ghostComponent->SetGhostOverride(bOverride); - - Game::entityManager->UpdateGhosting(player); - } -} - - -void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - NiPoint3 position; - - inStream.Read(position); - - auto* player = PlayerManager::GetPlayer(sysAddr); - - if (player != nullptr) { - auto* ghostComponent = entity->GetComponent(); - if (ghostComponent) ghostComponent->SetGhostOverridePoint(position); - - Game::entityManager->UpdateGhosting(player); - } -} - - -void GameMessages::HandleParseChatMessage(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - std::u16string wsString; - int iClientState; - inStream.Read(iClientState); - - uint32_t wsStringLength; - inStream.Read(wsStringLength); - - if (wsStringLength > MAX_MESSAGE_LENGTH) { - LOG("Max message length reached, capping message."); - wsStringLength = MAX_MESSAGE_LENGTH; - } - - for (uint32_t i = 0; i < wsStringLength; ++i) { - uint16_t character; - inStream.Read(character); - wsString.push_back(character); - } - - if (!wsString.empty() && wsString[0] == L'/') { - SlashCommandHandler::HandleChatCommand(wsString, entity, sysAddr); - } -} - -void GameMessages::HandleFireEventServerSide(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - uint32_t argsLength{}; - std::u16string args{}; - bool param1IsDefault{}; - int param1 = -1; - bool param2IsDefault{}; - int param2 = -1; - bool param3IsDefault{}; - int param3 = -1; - LWOOBJID senderID{}; - - inStream.Read(argsLength); - if (argsLength > MAX_MESSAGE_LENGTH) return; - for (uint32_t i = 0; i < argsLength; ++i) { - uint16_t character; - inStream.Read(character); - args.push_back(character); - } - inStream.Read(param1IsDefault); - if (param1IsDefault) inStream.Read(param1); - inStream.Read(param2IsDefault); - if (param2IsDefault) inStream.Read(param2); - inStream.Read(param3IsDefault); - if (param3IsDefault) inStream.Read(param3); - inStream.Read(senderID); - - auto* sender = Game::entityManager->GetEntity(senderID); - auto* player = PlayerManager::GetPlayer(sysAddr); - - if (!player) { - return; - } - - // This should probably get it's own "ServerEvents" system or something at some point - if (args == u"ZonePlayer") { - // Should probably check to make sure they're using a launcher at some point before someone makes a hack that lets you testmap - - LWOCLONEID cloneId = 0; - LWOMAPID mapId = 0; - - auto* rocketPad = entity->GetComponent(); - - if (rocketPad == nullptr) return; - - cloneId = rocketPad->GetSelectedCloneId(player->GetObjectID()); - - if (param2) { - mapId = rocketPad->GetDefaultZone(); - } else { - mapId = param3; - } - - if (mapId == 0) { - mapId = rocketPad->GetSelectedMapId(player->GetObjectID()); - } - - if (mapId == 0) { - mapId = Game::zoneManager->GetZoneID().GetMapID(); // Fallback to sending the player back to the same zone. - } - - LOG("Player %llu has requested zone transfer to (%i, %i).", sender->GetObjectID(), static_cast(mapId), static_cast(cloneId)); - - auto* character = player->GetCharacter(); - - if (mapId <= 0) { - return; - } - - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, mapId, cloneId, false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - - if (character) { - auto* characterComponent = player->GetComponent(); - if (characterComponent) { - characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); - } - - character->SetZoneID(zoneID); - character->SetZoneInstance(zoneInstance); - character->SetZoneClone(zoneClone); - } - - ClientPackets::TransferToWorld transfer; - transfer.serverIP = LUString(serverIP); - transfer.serverPort = serverPort; - transfer.mythranShift = mythranShift; - transfer.Send(sysAddr); - return; - }); - } - - entity->OnFireEventServerSide(sender, GeneralUtils::UTF16ToWTF8(args), param1, param2, param3); -} - -void GameMessages::HandleRequestPlatformResync(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - if (entity->GetLOT() == 6267 || entity->GetLOT() == 16141) return; - GameMessages::SendPlatformResync(entity, sysAddr); -} - -void GameMessages::HandleQuickBuildCancel(RakNet::BitStream& inStream, Entity* entity) { - bool bEarlyRelease; - LWOOBJID userID; - - inStream.Read(bEarlyRelease); - inStream.Read(userID); - - auto* quickBuildComponent = static_cast(entity->GetComponent(eReplicaComponentType::QUICK_BUILD));; - if (!quickBuildComponent) return; - - quickBuildComponent->CancelQuickBuild(Game::entityManager->GetEntity(userID), eQuickBuildFailReason::CANCELED_EARLY); -} - -void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& inStream, Entity* entity) { - auto* levelComp = entity->GetComponent(); - if (!levelComp) return; - auto* character = entity->GetComponent(); - if (!character) return; - - //Update our character's level in memory: - levelComp->SetLevel(levelComp->GetLevel() + 1); - - levelComp->HandleLevelUp(); - - auto* inventoryComponent = entity->GetComponent(); - - if (inventoryComponent != nullptr) { - auto* inventory = inventoryComponent->GetInventory(ITEMS); - - if (inventory != nullptr && Game::config->GetValue("disable_extra_backpack") != "1") { - inventory->SetSize(inventory->GetSize() + 2); - } - } - - //Play the level up effect: - GameMessages::PlayFXEffect(entity->GetObjectID(), 7074, u"create", "7074").Send(UNASSIGNED_SYSTEM_ADDRESS); - - //Send a notification in chat: - std::stringstream wss; - wss << "level=1:"; - wss << levelComp->GetLevel(); - wss << "\n"; - wss << "name=0:"; - wss << character->GetName(); - - // FIXME: only really need utf8 conversion for the name, so move that up? - std::u16string attrs = GeneralUtils::UTF8ToUTF16(wss.str()); - std::u16string wsText = u"UI_LEVEL_PROGRESSION_LEVELUP_MESSAGE"; - - 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) { - unsigned int currency; - inStream.Read(currency); - - if (currency == 0) return; - - auto* ch = entity->GetCharacter(); - if (ch && entity->PickupCoins(currency)) { - ch->SetCoins(ch->GetCoins() + currency, eLootSourceType::PICKUP); - } -} - -void GameMessages::SendSetGravityScale(const LWOOBJID& target, const float effectScale, const SystemAddress& sysAddr) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(target); - bitStream.Write(MessageType::Game::SET_GRAVITY_SCALE); - - bitStream.Write(effectScale); - - SEND_PACKET; -} - -void GameMessages::HandleMatchRequest(RakNet::BitStream& inStream, Entity* entity) { - LWOOBJID activator; - uint32_t playerChoicesLen; - std::string playerChoices; - int type; - int value; - - inStream.Read(activator); - inStream.Read(playerChoicesLen); - if (playerChoicesLen > MAX_MESSAGE_LENGTH) return; - for (uint32_t i = 0; i < playerChoicesLen; ++i) { - uint16_t character; - inStream.Read(character); - playerChoices.push_back(character); - } - if (playerChoicesLen > 0) { - uint16_t nullTerm; - inStream.Read(nullTerm); - } - inStream.Read(type); - inStream.Read(value); - - std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); - if (type == 0) { // join - if (value != 0) { - for (Entity* scriptedAct : scriptedActs) { - ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY)); - if (!comp) continue; - if (comp->GetActivityID() == value) { - comp->PlayerJoin(entity); - } - } - } else { - - } - } else if (type == 1) { // ready/unready - for (Entity* scriptedAct : scriptedActs) { - ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY)); - if (!comp) continue; - if (comp->PlayerIsInQueue(entity)) { - comp->PlayerReady(entity, value); - } - } - } -} - -void GameMessages::HandleReportBug(RakNet::BitStream& inStream, Entity* entity) { - //Definitely not stolen from autogenerated code, no sir: - IBugReports::Info reportInfo; - - //Reading: - uint32_t messageLength; - inStream.Read(messageLength); - - if (messageLength > MAX_MESSAGE_LENGTH) return; - - for (uint32_t i = 0; i < (messageLength); ++i) { - uint16_t character; - inStream.Read(character); - reportInfo.body.push_back(static_cast(character)); - } - - auto character = entity->GetCharacter(); - if (character) reportInfo.characterId = character->GetID(); - - uint32_t clientVersionLength; - inStream.Read(clientVersionLength); - if (clientVersionLength > MAX_MESSAGE_LENGTH) return; - for (unsigned int k = 0; k < clientVersionLength; k++) { - unsigned char character; - inStream.Read(character); - reportInfo.clientVersion.push_back(character); - } - - uint32_t nOtherPlayerIDLength; - inStream.Read(nOtherPlayerIDLength); - if (nOtherPlayerIDLength > MAX_MESSAGE_LENGTH) return; - for (unsigned int k = 0; k < nOtherPlayerIDLength; k++) { - unsigned char character; - inStream.Read(character); - reportInfo.otherPlayer.push_back(character); - } - - uint32_t selectionLength; - inStream.Read(selectionLength); - if (selectionLength > MAX_MESSAGE_LENGTH) return; - for (unsigned int k = 0; k < selectionLength; k++) { - unsigned char character; - inStream.Read(character); - reportInfo.selection.push_back(character); - } - - // Report Abuse about another player sends their ID here (and "0" otherwise); that's a player report, not a bug - if (const auto reportedId = GeneralUtils::TryParse(reportInfo.otherPlayer).value_or(LWOOBJID_EMPTY); reportedId != LWOOBJID_EMPTY) { - PlayerReports::ReportPlayer(entity, reportedId, reportInfo.body); - return; - } - - Database::Get()->InsertNewBugReport(reportInfo); - DashboardNotify::Changed("bug_reports"); -} - -void -GameMessages::HandleClientRailMovementReady(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); - for (const auto* possibleRail : possibleRails) { - const auto* rail = possibleRail->GetComponent(); - if (rail != nullptr) { - rail->OnRailMovementReady(entity); - } - } -} - -void GameMessages::HandleCancelRailMovement(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { - const auto immediate = inStream.ReadBit(); - - const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); - for (const auto* possibleRail : possibleRails) { - auto* rail = possibleRail->GetComponent(); - if (rail != nullptr) { - rail->OnCancelRailMovement(entity); - } - } -} - -void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream& inStream, Entity* entity, - const SystemAddress& sysAddr) { - uint32_t pathNameLength; - inStream.Read(pathNameLength); - if (pathNameLength > MAX_MESSAGE_LENGTH) return; - std::u16string pathName; - for (auto k = 0; k < pathNameLength; k++) { - uint16_t c; - inStream.Read(c); - pathName.push_back(c); - } - - int32_t waypointNumber; - inStream.Read(waypointNumber); - - const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); - for (auto* possibleRail : possibleRails) { - if (possibleRail) possibleRail->GetScript()->OnPlayerRailArrived(possibleRail, entity, pathName, waypointNumber); - } -} - -void GameMessages::HandleModifyPlayerZoneStatistic(RakNet::BitStream& inStream, Entity* entity) { - const auto set = inStream.ReadBit(); - const auto statisticsName = GeneralUtils::ReadWString(inStream); - - int32_t value; - if (inStream.ReadBit()) { - inStream.Read(value); - } else { - value = 0; - } - - LWOMAPID zone; - if (inStream.ReadBit()) { - inStream.Read(zone); - } else { - zone = LWOMAPID_INVALID; - } - - // Notify the character component that something's changed - auto* characterComponent = entity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->HandleZoneStatisticsUpdate(zone, statisticsName, value); - } -} - -void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream& inStream, Entity* entity) { - int32_t updateID; - inStream.Read(updateID); - - int64_t updateValue; - if (inStream.ReadBit()) { - inStream.Read(updateValue); - } else { - updateValue = 1; - } - - auto* characterComponent = entity->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(static_cast(updateID), static_cast(std::max(updateValue, static_cast(0))), true); - } -} - -void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream& inStream, Entity* entity) { - LWOOBJID player_id; - inStream.Read(player_id); - auto target = Game::entityManager->GetEntity(player_id); - entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target); -}; - -void GameMessages::SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) { - CBITSTREAM; - CMSGHEADER; - - bitStream.Write(entity->GetObjectID()); - bitStream.Write(MessageType::Game::FORCE_CAMERA_TARGET_CYCLE); - bitStream.Write(bForceCycling); - bitStream.Write(cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES); - if (cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES) bitStream.Write(cyclingMode); - bitStream.Write(optionalTargetID); - - auto sysAddr = entity->GetSystemAddress(); - SEND_PACKET; -} - +#include "ServiceType.h" +#include "dServer.h" namespace GameMessages { bool GameMsg::Send() { @@ -1577,7 +19,7 @@ namespace GameMessages { } void NetGameMsg::WritePacket(RakNet::BitStream& bitStream) const { - CMSGHEADER; + LUBitStream(ServiceType::CLIENT, MessageType::Client::GAME_MSG).WriteHeader(bitStream); bitStream.Write(target); // Who this message will be sent to on the (a) client bitStream.Write(msgId); // the ID of this message @@ -1586,216 +28,22 @@ namespace GameMessages { } void NetGameMsg::SendToClient(const SystemAddress& sysAddr) const { - CBITSTREAM; + RakNet::BitStream bitStream; WritePacket(bitStream); - SEND_PACKET; + Game::server->Send(bitStream, sysAddr, false); } void NetGameMsg::BroadcastExcept(const SystemAddress& excluded) const { - CBITSTREAM; + RakNet::BitStream bitStream; WritePacket(bitStream); Game::server->Send(bitStream, excluded, true); } void NetGameMsg::Send(const SystemAddress& sysAddr) const { - CBITSTREAM; + RakNet::BitStream bitStream; WritePacket(bitStream); // Send to everyone if someone sent unassigned system address, or to one specific client. - if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) { - SEND_PACKET_BROADCAST; - } else { - SEND_PACKET; - } - } - - void DisplayTooltip::Serialize(RakNet::BitStream& bitStream) const { - bitStream.Write(doOrDie); - bitStream.Write(noRepeat); - bitStream.Write(noRevive); - bitStream.Write(isPropertyTooltip); - bitStream.Write(show); - bitStream.Write(translate); - bitStream.Write(time); - bitStream.Write(id.size()); - bitStream.Write(id); - - std::string toWrite; - for (const auto& item : localizeParams | std::views::values) { - toWrite += item->GetString() + "\n"; - } - if (!toWrite.empty()) toWrite.pop_back(); - bitStream.Write(toWrite.size()); - bitStream.Write(GeneralUtils::ASCIIToUTF16(toWrite)); - if (!toWrite.empty()) bitStream.Write(0x00); // Null Terminator - - bitStream.Write(imageName.size()); - bitStream.Write(imageName); - bitStream.Write(text.size()); - bitStream.Write(text); - } - - void UseItemOnClient::Serialize(RakNet::BitStream& bitStream) const { - bitStream.Write(itemLOT); - bitStream.Write(itemToUse); - bitStream.Write(itemType); - bitStream.Write(playerId); - bitStream.Write(targetPosition.x); - bitStream.Write(targetPosition.y); - bitStream.Write(targetPosition.z); - } - - void SetModelToBuild::Serialize(RakNet::BitStream& bitStream) const { - bitStream.Write(modelLot != -1); - if (modelLot != -1) bitStream.Write(modelLot); - } - - void SpawnModelBricks::Serialize(RakNet::BitStream& bitStream) const { - bitStream.Write(amount != 0.0f); - if (amount != 0.0f) bitStream.Write(amount); - bitStream.Write(position != NiPoint3Constant::ZERO); - if (position != NiPoint3Constant::ZERO) { - bitStream.Write(position.x); - bitStream.Write(position.y); - bitStream.Write(position.z); - } - } - - bool ShootingGalleryFire::Deserialize(RakNet::BitStream& bitStream) { - if (!bitStream.Read(target.x)) return false; - if (!bitStream.Read(target.y)) return false; - if (!bitStream.Read(target.z)) return false; - if (!bitStream.Read(rotation.w)) return false; - if (!bitStream.Read(rotation.x)) return false; - if (!bitStream.Read(rotation.y)) return false; - if (!bitStream.Read(rotation.z)) return false; - return true; - } - - void ShootingGalleryFire::Handle(Entity& entity, const SystemAddress& sysAddr) { - entity.OnShootingGalleryFire(*this); - } - - bool RequestServerObjectInfo::Deserialize(RakNet::BitStream& bitStream) { - if (!bitStream.Read(bVerbose)) return false; - if (!bitStream.Read(clientId)) return false; - if (!bitStream.Read(targetForReport)) return false; - return true; - } - - void RequestServerObjectInfo::Handle(Entity& entity, const SystemAddress& sysAddr) { - auto* handlingEntity = Game::entityManager->GetEntity(targetForReport); - if (handlingEntity) { - RequestServerObjectInfoEvent event(*this); - handlingEntity->HandleMsg(event); - } else LOG("Failed to find target %llu", targetForReport); - } - - bool RequestUse::Deserialize(RakNet::BitStream& stream) { - if (!stream.Read(bIsMultiInteractUse)) return false; - if (!stream.Read(multiInteractID)) return false; - if (!stream.Read(multiInteractType)) return false; - if (!stream.Read(object)) return false; - if (!stream.Read(secondary)) return false; - return true; - } - - void RequestUse::Handle(Entity& entity, const SystemAddress& sysAddr) { - Entity* interactedObject = Game::entityManager->GetEntity(object); - - if (interactedObject == nullptr) { - LOG("Object %llu tried to interact, but doesn't exist!", object); - - return; - } - - if (interactedObject->GetLOT() == 9524) { - entity.GetCharacter()->SetBuildMode(true); - } - - if (bIsMultiInteractUse) { - if (multiInteractType == 0) { - auto* missionOfferComponent = static_cast(interactedObject->GetComponent(eReplicaComponentType::MISSION_OFFER)); - - if (missionOfferComponent != nullptr) { - missionOfferComponent->OfferMissions(&entity, multiInteractID); - } - } else { - interactedObject->OnUse(&entity); - } - } else { - interactedObject->OnUse(&entity); - } - - RequestUseEvent event(*this); - interactedObject->HandleMsg(event); - - //Perform use task if possible: - auto missionComponent = entity.GetComponent(); - - if (!missionComponent) return; - - missionComponent->Progress(eMissionTaskType::TALK_TO_NPC, interactedObject->GetLOT(), interactedObject->GetObjectID()); - missionComponent->Progress(eMissionTaskType::INTERACT, interactedObject->GetLOT(), interactedObject->GetObjectID()); - } - - void PlayBehaviorSound::Serialize(RakNet::BitStream& stream) const { - stream.Write(soundID != -1); - if (soundID != -1) stream.Write(soundID); - } - - void EmotePlayed::Serialize(RakNet::BitStream& stream) const { - stream.Write(emoteID); - stream.Write(targetID); - } - - void DropClientLoot::Serialize(RakNet::BitStream& stream) const { - stream.Write(bUsePosition); - - stream.Write(finalPosition != NiPoint3Constant::ZERO); - if (finalPosition != NiPoint3Constant::ZERO) stream.Write(finalPosition); - - stream.Write(currency); - stream.Write(item); - stream.Write(lootID); - stream.Write(ownerID); - stream.Write(sourceID); - - stream.Write(spawnPos != NiPoint3Constant::ZERO); - if (spawnPos != NiPoint3Constant::ZERO) stream.Write(spawnPos); - } - - bool PickupItem::Deserialize(RakNet::BitStream& stream) { - if (!stream.Read(lootID)) return false; - if (!stream.Read(lootOwnerID)) return false; - return true; - } - - void PickupItem::Handle(Entity& entity, const SystemAddress& sysAddr) { - auto* team = TeamManager::Instance()->GetTeam(entity.GetObjectID()); - LOG("Has team %i picking up %llu:%llu", team != nullptr, lootID, lootOwnerID); - if (team) { - for (const auto memberId : team->members) { - PickupItemEvent event(*this); - event.Send(memberId); - TeamPickupItem teamPickupMsg{}; - teamPickupMsg.target = lootID; - teamPickupMsg.lootID = lootID; - teamPickupMsg.lootOwnerID = lootOwnerID; - const auto* const memberEntity = Game::entityManager->GetEntity(memberId); - if (memberEntity) teamPickupMsg.Send(memberEntity->GetSystemAddress()); - } - } else { - entity.PickupItem(lootID); - } - } - - void TeamPickupItem::Serialize(RakNet::BitStream& stream) const { - stream.Write(lootID); - stream.Write(lootOwnerID); - } - - void ToggleGMInvis::Serialize(RakNet::BitStream& stream) const { - stream.Write(bStateOut); + Game::server->Send(bitStream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index e0d2c2b8e..4e565aba5 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -47,11 +47,6 @@ enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t; enum class eMissionState : int; enum class AiState : uint32_t; -enum class eCameraTargetCyclingMode : int32_t { - ALLOW_CYCLE_TEAMMATES, - DISALLOW_CYCLING -}; - namespace GameMessages { /** * A server-internal event, delivered only to the handlers entities/components/scripts registered with @@ -129,203 +124,7 @@ namespace GameMessages { return event.Send(); } - 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 SendPlayerReady(Entity* entity, const SystemAddress& sysAddr); - void SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer); - - void SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, bool bAllowCyclingWhileDeadOnly = true, eCyclingMode cyclingMode = eCyclingMode::ALLOW_CYCLE_TEAMMATES); - - void SendStartPathing(Entity* entity); - - // special is for the FV tree platform, feature is complete if we just do that so meh - void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint = false, - int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1, - eMovementPlatformState movementState = eMovementPlatformState::Moving, bool special = false); - - void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr); - void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr); - void SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level); - void SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level); - - void SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectWorldState state, const SystemAddress& sysAddr); - - void SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType); - - 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); - void SendEnableQuickBuild(Entity* entity, bool enable, bool fail, bool success, eQuickBuildFailReason failReason, float duration, const LWOOBJID& playerID); - void AddActivityOwner(Entity* entity, LWOOBJID& ownerID); - void SendTerminateInteraction(const LWOOBJID& objectID, eTerminateType type, const LWOOBJID& terminator); - - void SendSetGravityScale(const LWOOBJID& target, const float effectScale, const SystemAddress& sysAddr); - - 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 SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data); - - void SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme); - void SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPoint3& position, const NiQuaternion& rotation); - - void SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response); - void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type); - - // Rails stuff - void SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, uint32_t pathStart, - const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, - int32_t railActivatorComponentID = -1, LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); - - void SendStartRailMovement(const LWOOBJID& objectID, std::u16string pathName, std::u16string startSound, - std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, - uint32_t pathStart = 0, bool goForward = true, bool damageImmune = true, bool noAggro = true, - bool notifyActor = false, bool showNameBillboard = true, bool cameraLocked = true, - bool collisionEnabled = true, bool useDB = true, int32_t railComponentID = -1, - LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); - - void HandleClientRailMovementReady(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleCancelRailMovement(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePlayerRailArrivedNotification(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - void SendNotifyClientObject(const LWOOBJID& objectID, std::u16string name, int param1 = 0, int param2 = 0, const LWOOBJID& paramObj = LWOOBJID_EMPTY, std::string paramStr = "", const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); - void SendNotifyClientZoneObject(const LWOOBJID& objectID, const std::u16string& name, int param1, int param2, const LWOOBJID& paramObj, const std::string& paramStr, const SystemAddress& sysAddr); - - void SendNotifyClientFailedPrecondition(LWOOBJID objectId, const SystemAddress& sysAddr, const std::u16string& failedReason, int preconditionID); - - void SendSetName(LWOOBJID objectID, std::u16string name, const SystemAddress& sysAddr); - - void SendLockNodeRotation(Entity* entity, std::string nodeName); - - void SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr); - - void SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1 = 0, int param2 = 0); - - void HandleVerifyAck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - void SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr); - - //Pets: - - void SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap = false, bool isZoneStart = false, LWOOBJID sender = LWOOBJID_EMPTY); - - // Mounts - /** - * @brief Set the Inventory LWOOBJID of the mount - * - * @param entity The entity that is mounting - * @param sysAddr the system address to send game message responses to - * @param objectID LWOOBJID of the item in inventory that is being used - */ - void SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr); - - /** - * @brief Handle client dismounting mount - * - * @param inStream Raknet BitStream of incoming data - * @param entity The Entity that is dismounting - * @param sysAddr the system address to send game message responses to - */ - void HandleDismountComplete(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - /** - * @brief Handle acknowledging that the client possessed something - * - * @param inStream Raknet BitStream of incoming data - * @param entity The Entity that is possessing - * @param sysAddr the system address to send game message responses to - */ - void HandleAcknowledgePossession(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - //Racing: - - // SG: - - void SendSetShootingGalleryParams(LWOOBJID objectId, const SystemAddress& sysAddr, - float cameraFOV, - float cooldown, - float minDistance, - NiPoint3 muzzlePosOffset, - NiPoint3 playerPosOffset, - float projectileVelocity, - float timeLimit, - bool bUseLeaderboards - ); - - void SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const SystemAddress& sysAddr, - float addTime, - int32_t score, - LWOOBJID target, - NiPoint3 targetPos - ); - - void HandleUpdateShootingGalleryRotation(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - void SendUpdateReputation(const LWOOBJID objectId, const int64_t reputation, const SystemAddress& sysAddr); - - // Leaderboards - void SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, - const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); - void HandleActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, - const SystemAddress& sysAddr, const int32_t& gameID = 0, - const int32_t& queryType = 1, const int32_t& resultsEnd = 10, - const int32_t& resultsStart = 0, bool weekly = false); - void HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleActivityStateChangeRequest(RakNet::BitStream& inStream, Entity* entity); - - //NT: - - //Handlers: - - void HandleToggleGhostReferenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetGhostReferencePosition(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - - void HandleParseChatMessage(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleToggleGhostReffrenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetGhostReffrenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - 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 HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& inStream, Entity* entity); - void HandlePickupCurrency(RakNet::BitStream& inStream, Entity* entity); - void HandlePickupItem(RakNet::BitStream& inStream, Entity* entity); - void HandleModifyPlayerZoneStatistic(RakNet::BitStream& inStream, Entity* entity); - void HandleUpdatePlayerStatistic(RakNet::BitStream& inStream, Entity* entity); - - void HandleMatchRequest(RakNet::BitStream& inStream, Entity* entity); - - void HandleReportBug(RakNet::BitStream& inStream, Entity* entity); - - // bubble - - void HandleZoneSummaryDismissed(RakNet::BitStream& inStream, Entity* entity); - - void SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID); - - struct DisplayTooltip : public NetGameMsg { - DisplayTooltip() : NetGameMsg(MessageType::Game::DISPLAY_TOOLTIP) {} - bool doOrDie{}; - bool noRepeat{}; - bool noRevive{}; - bool isPropertyTooltip{}; - bool show{}; - bool translate{}; - int32_t time{}; - std::u16string id{}; - LwoNameValue localizeParams{}; - std::u16string imageName{}; - std::u16string text{}; - void Serialize(RakNet::BitStream& bitStream) const override; - }; - - struct UseItemOnClient : public NetGameMsg { - UseItemOnClient() : NetGameMsg(MessageType::Game::USE_ITEM_ON_CLIENT) {} - LWOOBJID playerId{}; - LWOOBJID itemToUse{}; - uint32_t itemType{}; - LOT itemLOT{}; - NiPoint3 targetPosition{}; - void Serialize(RakNet::BitStream& bitStream) const override; - }; + // Server-internal events (GameMsg). Wire messages live in the per-domain Messages.h files. struct ZoneLoadedInfo : public GameMsg { ZoneLoadedInfo() : GameMsg(MessageType::Game::ZONE_LOADED_INFO) {} @@ -337,19 +136,7 @@ namespace GameMessages { LwoNameValue racingSettings{}; }; - struct SetModelToBuild : public NetGameMsg { - SetModelToBuild() : NetGameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {} - void Serialize(RakNet::BitStream& bitStream) const override; - LOT modelLot{ -1 }; - }; - struct SpawnModelBricks : public NetGameMsg { - SpawnModelBricks() : NetGameMsg(MessageType::Game::SPAWN_MODEL_BRICKS) {} - void Serialize(RakNet::BitStream& bitStream) const override; - - float amount{ 0.0f }; - NiPoint3 position{ NiPoint3Constant::ZERO }; - }; struct ActivityNotify : public GameMsg { ActivityNotify() : GameMsg(MessageType::Game::ACTIVITY_NOTIFY) {} @@ -357,14 +144,6 @@ namespace GameMessages { LwoNameValue notification{}; }; - struct ShootingGalleryFire : public NetGameMsg { - ShootingGalleryFire() : NetGameMsg(MessageType::Game::SHOOTING_GALLERY_FIRE) {} - bool Deserialize(RakNet::BitStream& bitStream) override; - void Handle(Entity& entity, const SystemAddress& sysAddr) override; - - NiPoint3 target{}; - NiQuaternion rotation = QuatUtils::IDENTITY; - }; struct ChildLoaded : public GameMsg { ChildLoaded() : GameMsg(MessageType::Game::CHILD_LOADED) {} @@ -377,16 +156,6 @@ namespace GameMessages { PlayerResurrectionFinished() : GameMsg(MessageType::Game::PLAYER_RESURRECTION_FINISHED) {} }; - struct RequestServerObjectInfo : public NetGameMsg { - bool bVerbose{}; - LWOOBJID clientId{}; - LWOOBJID targetForReport{}; - - RequestServerObjectInfo() : NetGameMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, eGameMasterLevel::DEVELOPER) {} - bool Deserialize(RakNet::BitStream& bitStream) override; - void Handle(Entity& entity, const SystemAddress& sysAddr) override; - }; - using RequestServerObjectInfoEvent = NetGameMsgEvent; struct GetObjectReportInfo : public GameMsg { AMFArrayValue* info{}; @@ -397,34 +166,7 @@ namespace GameMessages { GetObjectReportInfo() : GameMsg(MessageType::Game::GET_OBJECT_REPORT_INFO) {} }; - struct RequestUse : public NetGameMsg { - RequestUse() : NetGameMsg(MessageType::Game::REQUEST_USE) {} - bool Deserialize(RakNet::BitStream& stream) override; - void Handle(Entity& entity, const SystemAddress& sysAddr) override; - - LWOOBJID object{}; - - bool secondary{ false }; - - // Set to true if this coming from a multi-interaction UI on the client. - bool bIsMultiInteractUse{}; - - // Used only for multi-interaction - unsigned int multiInteractID{}; - - // Used only for multi-interaction, is of the enum type InteractionType - int multiInteractType{}; - }; - using RequestUseEvent = NetGameMsgEvent; - - struct PlayBehaviorSound : public NetGameMsg { - PlayBehaviorSound() : NetGameMsg(MessageType::Game::PLAY_BEHAVIOR_SOUND) {} - - void Serialize(RakNet::BitStream& stream) const override; - - int32_t soundID{ -1 }; - }; struct ResetModelToDefaults : public GameMsg { ResetModelToDefaults() : GameMsg(MessageType::Game::RESET_MODEL_TO_DEFAULTS) {} @@ -435,14 +177,6 @@ namespace GameMessages { bool bResetBehaviors{ true }; }; - struct EmotePlayed : public NetGameMsg { - EmotePlayed() : NetGameMsg(MessageType::Game::EMOTE_PLAYED), emoteID(0), targetID(0) {} - - void Serialize(RakNet::BitStream& stream) const override; - - int32_t emoteID; - LWOOBJID targetID; - }; struct GetPosition : public GameMsg { GetPosition() : GameMsg(MessageType::Game::GET_POSITION) {} @@ -458,21 +192,6 @@ namespace GameMessages { bool bIgnoreChecks{ false }; }; - struct DropClientLoot : public NetGameMsg { - DropClientLoot() : NetGameMsg(MessageType::Game::DROP_CLIENT_LOOT) {} - - void Serialize(RakNet::BitStream& stream) const override; - LWOOBJID sourceID{ LWOOBJID_EMPTY }; - LOT item{ LOT_NULL }; - int32_t currency{}; - NiPoint3 spawnPos{}; - NiPoint3 finalPosition{}; - int32_t count{}; - bool bUsePosition{}; - LWOOBJID lootID{ LWOOBJID_EMPTY }; - LWOOBJID ownerID{ LWOOBJID_EMPTY }; - }; - using DropClientLootEvent = NetGameMsgEvent; struct GetMissionState : public GameMsg { GetMissionState() : GameMsg(MessageType::Game::GET_MISSION_STATE) {} @@ -502,23 +221,7 @@ namespace GameMessages { LOT item{}; }; - struct PickupItem : public NetGameMsg { - PickupItem() : NetGameMsg(MessageType::Game::PICKUP_ITEM) {} - void Handle(Entity& entity, const SystemAddress& sysAddr) override; - bool Deserialize(RakNet::BitStream& stream) override; - LWOOBJID lootID{}; - LWOOBJID lootOwnerID{}; - }; - using PickupItemEvent = NetGameMsgEvent; - - struct TeamPickupItem : public NetGameMsg { - TeamPickupItem() : NetGameMsg(MessageType::Game::TEAM_PICKUP_ITEM) {} - - void Serialize(RakNet::BitStream& stream) const override; - LWOOBJID lootID{}; - LWOOBJID lootOwnerID{}; - }; struct IsDead : public GameMsg { IsDead() : GameMsg(MessageType::Game::IS_DEAD) {} @@ -526,14 +229,6 @@ namespace GameMessages { bool bDead{}; }; - struct ToggleGMInvis : public NetGameMsg { - ToggleGMInvis() : NetGameMsg(MessageType::Game::TOGGLE_GM_INVIS) {} - - void Serialize(RakNet::BitStream& stream) const override; - bool bStateOut{ false }; - - }; - using ToggleGMInvisEvent = NetGameMsgEvent; struct GetGMInvis : public GameMsg { GetGMInvis() : GameMsg(MessageType::Game::GET_GM_INVIS) {} @@ -547,14 +242,6 @@ namespace GameMessages { LWOOBJID childID{}; }; - struct UseSkillSet : public NetGameMsg { - UseSkillSet() : NetGameMsg(MessageType::Game::USE_SKILL_SET) {} - void Serialize(RakNet::BitStream& bitStream) const override; - - bool bRemove{}; - LWOOBJID possessedId{ LWOOBJID_EMPTY }; - int32_t setId{ -1 }; - }; struct ObjectLoaded : public GameMsg { ObjectLoaded() : GameMsg(MessageType::Game::OBJECT_LOADED) {} diff --git a/dGame/dGameMessages/InventoryMessages.cpp b/dGame/dGameMessages/InventoryMessages.cpp index 91e3636fc..97289bd8f 100644 --- a/dGame/dGameMessages/InventoryMessages.cpp +++ b/dGame/dGameMessages/InventoryMessages.cpp @@ -1,6 +1,7 @@ #include "InventoryMessages.h" #include "BitStreamUtils.h" +#include "TeamManager.h" #include "EntityManager.h" #include "Game.h" #include "Entity.h" @@ -455,4 +456,94 @@ namespace GameMessages { auto* inventoryComponent = entity.GetComponent(); if (inventoryComponent) inventoryComponent->OnUpdateInventoryGroupContents(*this); } + + void UseItemOnClient::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(itemLOT); + bitStream.Write(itemToUse); + bitStream.Write(itemType); + bitStream.Write(playerId); + bitStream.Write(targetPosition.x); + bitStream.Write(targetPosition.y); + bitStream.Write(targetPosition.z); + } + + void DropClientLoot::Serialize(RakNet::BitStream& stream) const { + stream.Write(bUsePosition); + + stream.Write(finalPosition != NiPoint3Constant::ZERO); + if (finalPosition != NiPoint3Constant::ZERO) stream.Write(finalPosition); + + stream.Write(currency); + stream.Write(item); + stream.Write(lootID); + stream.Write(ownerID); + stream.Write(sourceID); + + stream.Write(spawnPos != NiPoint3Constant::ZERO); + if (spawnPos != NiPoint3Constant::ZERO) stream.Write(spawnPos); + } + + bool PickupItem::Deserialize(RakNet::BitStream& stream) { + if (!stream.Read(lootID)) return false; + if (!stream.Read(lootOwnerID)) return false; + return true; + } + + void PickupItem::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* team = TeamManager::Instance()->GetTeam(entity.GetObjectID()); + LOG("Has team %i picking up %llu:%llu", team != nullptr, lootID, lootOwnerID); + if (team) { + for (const auto memberId : team->members) { + PickupItemEvent event(*this); + event.Send(memberId); + TeamPickupItem teamPickupMsg{}; + teamPickupMsg.target = lootID; + teamPickupMsg.lootID = lootID; + teamPickupMsg.lootOwnerID = lootOwnerID; + const auto* const memberEntity = Game::entityManager->GetEntity(memberId); + if (memberEntity) teamPickupMsg.Send(memberEntity->GetSystemAddress()); + } + } else { + entity.PickupItem(lootID); + } + } + + void TeamPickupItem::Serialize(RakNet::BitStream& stream) const { + stream.Write(lootID); + stream.Write(lootOwnerID); + } + + bool UseItemOnClient::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(itemLOT)); + VALIDATE_READ(bitStream.Read(itemToUse)); + VALIDATE_READ(bitStream.Read(itemType)); + VALIDATE_READ(bitStream.Read(playerId)); + VALIDATE_READ(bitStream.Read(targetPosition.x)); + VALIDATE_READ(bitStream.Read(targetPosition.y)); + VALIDATE_READ(bitStream.Read(targetPosition.z)); + return true; + } + + bool DropClientLoot::Deserialize(RakNet::BitStream& stream) { + VALIDATE_READ(stream.Read(bUsePosition)); + VALIDATE_READ(BitStreamUtils::ReadOptional(stream, finalPosition, NiPoint3Constant::ZERO)); + VALIDATE_READ(stream.Read(currency)); + VALIDATE_READ(stream.Read(item)); + VALIDATE_READ(stream.Read(lootID)); + VALIDATE_READ(stream.Read(ownerID)); + VALIDATE_READ(stream.Read(sourceID)); + VALIDATE_READ(BitStreamUtils::ReadOptional(stream, spawnPos, NiPoint3Constant::ZERO)); + return true; + } + + void PickupItem::Serialize(RakNet::BitStream& stream) const { + stream.Write(lootID); + stream.Write(lootOwnerID); + } + + bool TeamPickupItem::Deserialize(RakNet::BitStream& stream) { + VALIDATE_READ(stream.Read(lootID)); + VALIDATE_READ(stream.Read(lootOwnerID)); + return true; + } } diff --git a/dGame/dGameMessages/InventoryMessages.h b/dGame/dGameMessages/InventoryMessages.h index 366948a12..41c56f68e 100644 --- a/dGame/dGameMessages/InventoryMessages.h +++ b/dGame/dGameMessages/InventoryMessages.h @@ -309,6 +309,54 @@ namespace GameMessages { eInventoryType inventoryType{}; LOT lot{}; }; + + struct UseItemOnClient : public NetGameMsg { + UseItemOnClient() : NetGameMsg(MessageType::Game::USE_ITEM_ON_CLIENT) {} + LWOOBJID playerId{}; + LWOOBJID itemToUse{}; + uint32_t itemType{}; + LOT itemLOT{}; + NiPoint3 targetPosition{}; + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + }; + + struct DropClientLoot : public NetGameMsg { + DropClientLoot() : NetGameMsg(MessageType::Game::DROP_CLIENT_LOOT) {} + + void Serialize(RakNet::BitStream& stream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + LWOOBJID sourceID{ LWOOBJID_EMPTY }; + LOT item{ LOT_NULL }; + int32_t currency{}; + NiPoint3 spawnPos{}; + NiPoint3 finalPosition{}; + int32_t count{}; + bool bUsePosition{}; + LWOOBJID lootID{ LWOOBJID_EMPTY }; + LWOOBJID ownerID{ LWOOBJID_EMPTY }; + }; + using DropClientLootEvent = NetGameMsgEvent; + + struct PickupItem : public NetGameMsg { + PickupItem() : NetGameMsg(MessageType::Game::PICKUP_ITEM) {} + + void Serialize(RakNet::BitStream& bitStream) const override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + bool Deserialize(RakNet::BitStream& stream) override; + LWOOBJID lootID{}; + LWOOBJID lootOwnerID{}; + }; + using PickupItemEvent = NetGameMsgEvent; + + struct TeamPickupItem : public NetGameMsg { + TeamPickupItem() : NetGameMsg(MessageType::Game::TEAM_PICKUP_ITEM) {} + + void Serialize(RakNet::BitStream& stream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + LWOOBJID lootID{}; + LWOOBJID lootOwnerID{}; + }; }; #endif // INVENTORYMESSAGES_H diff --git a/dGame/dGameMessages/MissionMessages.cpp b/dGame/dGameMessages/MissionMessages.cpp index f4cf041b0..76e5d04aa 100644 --- a/dGame/dGameMessages/MissionMessages.cpp +++ b/dGame/dGameMessages/MissionMessages.cpp @@ -123,6 +123,21 @@ namespace GameMessages { return true; } + void MissionDialogueCancelled::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bIsComplete); + bitStream.Write(iMissionState); + bitStream.Write(missionID); + bitStream.Write(responder); + } + + bool MissionDialogueCancelled::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bIsComplete)); + VALIDATE_READ(bitStream.Read(iMissionState)); + VALIDATE_READ(bitStream.Read(missionID)); + VALIDATE_READ(bitStream.Read(responder)); + return true; + } + void MissionDialogueOK::Handle(Entity& entityRef, const SystemAddress& sysAddr) { Entity* entity = &entityRef; Entity* player = Game::entityManager->GetEntity(responder); diff --git a/dGame/dGameMessages/MissionMessages.h b/dGame/dGameMessages/MissionMessages.h index 1613bccfa..85b35c94d 100644 --- a/dGame/dGameMessages/MissionMessages.h +++ b/dGame/dGameMessages/MissionMessages.h @@ -79,6 +79,18 @@ namespace GameMessages { LWOOBJID responder{}; }; + // Client -> server. The player closed a mission offer without accepting. Nothing to do: the client carries on. + struct MissionDialogueCancelled : public NetGameMsg { + MissionDialogueCancelled() : NetGameMsg(MessageType::Game::MISSION_DIALOGUE_CANCELLED) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bIsComplete{}; + eMissionState iMissionState{}; + int32_t missionID{}; + LWOOBJID responder{}; + }; + // Client -> server. struct RequestLinkedMission : public NetGameMsg { RequestLinkedMission() : NetGameMsg(MessageType::Game::REQUEST_LINKED_MISSION) {} diff --git a/dGame/dGameMessages/MovementMessages.cpp b/dGame/dGameMessages/MovementMessages.cpp new file mode 100644 index 000000000..d50153321 --- /dev/null +++ b/dGame/dGameMessages/MovementMessages.cpp @@ -0,0 +1,414 @@ +#include "MovementMessages.h" + +#include "BitStreamUtils.h" +#include "CppScripts.h" +#include "Entity.h" +#include "EntityManager.h" +#include "Game.h" +#include "GhostComponent.h" +#include "PlayerManager.h" +#include "PossessorComponent.h" +#include "RailActivatorComponent.h" +#include "eReplicaComponentType.h" + +namespace GameMessages { + namespace { + void WritePoint(RakNet::BitStream& bitStream, const NiPoint3& point) { + bitStream.Write(point.x); + bitStream.Write(point.y); + bitStream.Write(point.z); + } + + bool ReadPoint(RakNet::BitStream& bitStream, NiPoint3& point) { + return bitStream.Read(point.x) && bitStream.Read(point.y) && bitStream.Read(point.z); + } + } + + void Teleport::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bIgnoreY); + bitStream.Write(bSetRotation); + bitStream.Write(bSkipAllChecks); + WritePoint(bitStream, pos); + bitStream.Write(bUseNavmesh); + BitStreamUtils::WriteOptional(bitStream, rot.w, 1.0f); + bitStream.Write(rot.x); + bitStream.Write(rot.y); + bitStream.Write(rot.z); + } + + bool Teleport::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bIgnoreY)); + VALIDATE_READ(bitStream.Read(bSetRotation)); + VALIDATE_READ(bitStream.Read(bSkipAllChecks)); + VALIDATE_READ(ReadPoint(bitStream, pos)); + VALIDATE_READ(bitStream.Read(bUseNavmesh)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, rot.w, 1.0f)); + VALIDATE_READ(bitStream.Read(rot.x)); + VALIDATE_READ(bitStream.Read(rot.y)); + VALIDATE_READ(bitStream.Read(rot.z)); + return true; + } + + PlatformResync::PlatformResync(const Entity& entity, bool bStopAtDesiredWaypoint, int32_t iIndex, int32_t iDesiredWaypointIndex, + int32_t nextIndex, eMovementPlatformState movementState, bool special) : PlatformResync() { + const auto lot = entity.GetLOT(); + + if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449 || lot == 11306 || lot == 11308 || lot == 9483) { + iDesiredWaypointIndex = (lot == 11306 || lot == 11308) ? 1 : 0; + iIndex = lot == 9483 ? 1 : 0; + nextIndex = lot == 9483 && !special ? 1 : 0; + bStopAtDesiredWaypoint = true; + movementState = lot == 9483 && !special ? eMovementPlatformState::Stopped : eMovementPlatformState::Stationary; + } + + target = entity.GetObjectID(); + this->bStopAtDesiredWaypoint = bStopAtDesiredWaypoint; + this->iIndex = iIndex; + this->iDesiredWaypointIndex = iDesiredWaypointIndex; + this->iNextIndex = nextIndex; + this->eState = movementState; + } + + void PlatformResync::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bReverse); + bitStream.Write(bStopAtDesiredWaypoint); + bitStream.Write(eCommand); + bitStream.Write(static_cast(eState)); + bitStream.Write(eUnexpectedCommand); + bitStream.Write(fIdleTimeElapsed); + bitStream.Write(fMoveTimeElapsed); + bitStream.Write(fPercentBetweenPoints); + bitStream.Write(iDesiredWaypointIndex); + bitStream.Write(iIndex); + bitStream.Write(iNextIndex); + WritePoint(bitStream, ptUnexpectedLocation); + const bool hasRotation = qUnexpectedRotation != QuatUtils::IDENTITY; + bitStream.Write(hasRotation); + if (hasRotation) { + bitStream.Write(qUnexpectedRotation.x); + bitStream.Write(qUnexpectedRotation.y); + bitStream.Write(qUnexpectedRotation.z); + bitStream.Write(qUnexpectedRotation.w); + } + } + + bool PlatformResync::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bReverse)); + VALIDATE_READ(bitStream.Read(bStopAtDesiredWaypoint)); + VALIDATE_READ(bitStream.Read(eCommand)); + int32_t state{}; + VALIDATE_READ(bitStream.Read(state)); + eState = static_cast(state); + VALIDATE_READ(bitStream.Read(eUnexpectedCommand)); + VALIDATE_READ(bitStream.Read(fIdleTimeElapsed)); + VALIDATE_READ(bitStream.Read(fMoveTimeElapsed)); + VALIDATE_READ(bitStream.Read(fPercentBetweenPoints)); + VALIDATE_READ(bitStream.Read(iDesiredWaypointIndex)); + VALIDATE_READ(bitStream.Read(iIndex)); + VALIDATE_READ(bitStream.Read(iNextIndex)); + VALIDATE_READ(ReadPoint(bitStream, ptUnexpectedLocation)); + bool hasRotation{}; + VALIDATE_READ(bitStream.Read(hasRotation)); + qUnexpectedRotation = QuatUtils::IDENTITY; + if (hasRotation) { + VALIDATE_READ(bitStream.Read(qUnexpectedRotation.x)); + VALIDATE_READ(bitStream.Read(qUnexpectedRotation.y)); + VALIDATE_READ(bitStream.Read(qUnexpectedRotation.z)); + VALIDATE_READ(bitStream.Read(qUnexpectedRotation.w)); + } + return true; + } + + void RequestPlatformResync::Handle(Entity& entity, const SystemAddress& sysAddr) { + if (entity.GetLOT() == 6267 || entity.GetLOT() == 16141) return; + PlatformResync(entity).Send(sysAddr); + } + + void OrientToAngle::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bRelativeToCurrent); + bitStream.Write(fAngle); + } + + bool OrientToAngle::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bRelativeToCurrent)); + VALIDATE_READ(bitStream.Read(fAngle)); + return true; + } + + void LockNodeRotation::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, nodeName); + } + + bool LockNodeRotation::Deserialize(RakNet::BitStream& bitStream) { + return BitStreamUtils::ReadLengthPrefixed(bitStream, nodeName); + } + + void SetGravityScale::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(scale); + } + + bool SetGravityScale::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(scale); + } + + void SetJetPackMode::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bBypassChecks); + bitStream.Write(bDoHover); + bitStream.Write(bUse); + BitStreamUtils::WriteOptional(bitStream, effectID, -1); + BitStreamUtils::WriteOptional(bitStream, fAirspeed, 10.0f); + BitStreamUtils::WriteOptional(bitStream, fMaxAirspeed, 15.0f); + BitStreamUtils::WriteOptional(bitStream, fVertVel, 1.0f); + BitStreamUtils::WriteOptional(bitStream, iWarningEffectID, -1); + } + + bool SetJetPackMode::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bBypassChecks)); + VALIDATE_READ(bitStream.Read(bDoHover)); + VALIDATE_READ(bitStream.Read(bUse)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, effectID, -1)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, fAirspeed, 10.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, fMaxAirspeed, 15.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, fVertVel, 1.0f)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, iWarningEffectID, -1)); + return true; + } + + void SetPlayerControlScheme::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bDelayCamSwitchIfInCinematic); + bitStream.Write(bSwitchCam); + BitStreamUtils::WriteOptional(bitStream, iScheme, eControlScheme::SCHEME_A); + } + + bool SetPlayerControlScheme::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bDelayCamSwitchIfInCinematic)); + VALIDATE_READ(bitStream.Read(bSwitchCam)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, iScheme, eControlScheme::SCHEME_A)); + return true; + } + + void PlayerReachedRespawnCheckpoint::Serialize(RakNet::BitStream& bitStream) const { + WritePoint(bitStream, pos); + const bool hasRotation = rot != QuatUtils::IDENTITY; + bitStream.Write(hasRotation); + if (hasRotation) { + bitStream.Write(rot.w); + bitStream.Write(rot.x); + bitStream.Write(rot.y); + bitStream.Write(rot.z); + } + } + + bool PlayerReachedRespawnCheckpoint::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(ReadPoint(bitStream, pos)); + bool hasRotation{}; + VALIDATE_READ(bitStream.Read(hasRotation)); + rot = QuatUtils::IDENTITY; + if (hasRotation) { + VALIDATE_READ(bitStream.Read(rot.w)); + VALIDATE_READ(bitStream.Read(rot.x)); + VALIDATE_READ(bitStream.Read(rot.y)); + VALIDATE_READ(bitStream.Read(rot.z)); + } + return true; + } + + void SetRailMovement::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(pathGoForward); + BitStreamUtils::WriteLengthPrefixed(bitStream, pathName); + bitStream.Write(pathStart); + BitStreamUtils::WriteOptional(bitStream, railActivatorComponentID, -1); + BitStreamUtils::WriteOptional(bitStream, railActivatorObjectID, LWOOBJID_EMPTY); + } + + bool SetRailMovement::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(pathGoForward)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathName)); + VALIDATE_READ(bitStream.Read(pathStart)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, railActivatorComponentID, -1)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, railActivatorObjectID, LWOOBJID_EMPTY)); + return true; + } + + void StartRailMovement::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bDamageImmune); + bitStream.Write(bNoAggro); + bitStream.Write(bNotifyActor); + bitStream.Write(bShowNameBillboard); + bitStream.Write(bCameraLocked); + bitStream.Write(bCollisionEnabled); + BitStreamUtils::WriteLengthPrefixed(bitStream, loopSound); + bitStream.Write(goForward); + BitStreamUtils::WriteLengthPrefixed(bitStream, pathName); + BitStreamUtils::WriteOptional(bitStream, pathStart, 0); + BitStreamUtils::WriteOptional(bitStream, railActivatorComponentID, -1); + BitStreamUtils::WriteOptional(bitStream, railActivatorObjectID, LWOOBJID_EMPTY); + BitStreamUtils::WriteLengthPrefixed(bitStream, startSound); + BitStreamUtils::WriteLengthPrefixed(bitStream, stopSound); + bitStream.Write(bUseDB); + } + + bool StartRailMovement::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bDamageImmune)); + VALIDATE_READ(bitStream.Read(bNoAggro)); + VALIDATE_READ(bitStream.Read(bNotifyActor)); + VALIDATE_READ(bitStream.Read(bShowNameBillboard)); + VALIDATE_READ(bitStream.Read(bCameraLocked)); + VALIDATE_READ(bitStream.Read(bCollisionEnabled)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, loopSound)); + VALIDATE_READ(bitStream.Read(goForward)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathName)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, pathStart, 0)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, railActivatorComponentID, -1)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, railActivatorObjectID, LWOOBJID_EMPTY)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, startSound)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, stopSound)); + VALIDATE_READ(bitStream.Read(bUseDB)); + return true; + } + + void ClientRailMovementReady::Handle(Entity& entity, const SystemAddress& sysAddr) { + const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); + for (const auto* possibleRail : possibleRails) { + const auto* rail = possibleRail->GetComponent(); + if (rail != nullptr) { + rail->OnRailMovementReady(&entity); + } + } + } + + void CancelRailMovement::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bImmediate); + } + + bool CancelRailMovement::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(bImmediate); + } + + void CancelRailMovement::Handle(Entity& entity, const SystemAddress& sysAddr) { + const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); + for (const auto* possibleRail : possibleRails) { + auto* rail = possibleRail->GetComponent(); + if (rail != nullptr) { + rail->OnCancelRailMovement(&entity); + } + } + } + + void PlayerRailArrivedNotification::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, pathName); + bitStream.Write(waypointNumber); + } + + bool PlayerRailArrivedNotification::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, pathName)); + VALIDATE_READ(bitStream.Read(waypointNumber)); + return true; + } + + void PlayerRailArrivedNotification::Handle(Entity& entity, const SystemAddress& sysAddr) { + const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); + for (auto* possibleRail : possibleRails) { + if (possibleRail) possibleRail->GetScript()->OnPlayerRailArrived(possibleRail, &entity, pathName, waypointNumber); + } + } + + void SetMountInventoryID::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, inventoryMountID, LWOOBJID_EMPTY); + } + + bool SetMountInventoryID::Deserialize(RakNet::BitStream& bitStream) { + return BitStreamUtils::ReadOptional(bitStream, inventoryMountID, LWOOBJID_EMPTY); + } + + void DismountComplete::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(mountID); + } + + bool DismountComplete::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(mountID); + } + + void DismountComplete::Handle(Entity& entity, const SystemAddress& sysAddr) { + // If we aren't possessing something, don't do anything + if (mountID == LWOOBJID_EMPTY) return; + auto* possessorComponent = entity.GetComponent(); + if (possessorComponent) possessorComponent->OnDismountComplete(mountID); + } + + void AcknowledgePossession::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteOptional(bitStream, possessedObjID, LWOOBJID_EMPTY); + } + + bool AcknowledgePossession::Deserialize(RakNet::BitStream& bitStream) { + return BitStreamUtils::ReadOptional(bitStream, possessedObjID, LWOOBJID_EMPTY); + } + + void AcknowledgePossession::Handle(Entity& entity, const SystemAddress& sysAddr) { + Game::entityManager->SerializeEntity(&entity); + if (possessedObjID != LWOOBJID_EMPTY) { + auto* mount = Game::entityManager->GetEntity(possessedObjID); + if (mount) Game::entityManager->SerializeEntity(mount); + } + } + + void ToggleGhostReferenceOverride::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bOverride); + } + + bool ToggleGhostReferenceOverride::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(bOverride); + } + + void ToggleGhostReferenceOverride::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* player = PlayerManager::GetPlayer(sysAddr); + if (player == nullptr) return; + + auto* ghostComponent = entity.GetComponent(); + if (ghostComponent) ghostComponent->SetGhostOverride(bOverride); + + Game::entityManager->UpdateGhosting(player); + } + + void SetGhostReferencePosition::Serialize(RakNet::BitStream& bitStream) const { + WritePoint(bitStream, pos); + } + + bool SetGhostReferencePosition::Deserialize(RakNet::BitStream& bitStream) { + return ReadPoint(bitStream, pos); + } + + void SetGhostReferencePosition::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* player = PlayerManager::GetPlayer(sysAddr); + if (player == nullptr) return; + + auto* ghostComponent = entity.GetComponent(); + if (ghostComponent) ghostComponent->SetGhostOverridePoint(pos); + + Game::entityManager->UpdateGhosting(player); + } + + void PlayerSetCameraCyclingMode::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bAllowCyclingWhileDeadOnly); + BitStreamUtils::WriteOptional(bitStream, cyclingMode, eCyclingMode::ALLOW_CYCLE_TEAMMATES); + } + + bool PlayerSetCameraCyclingMode::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bAllowCyclingWhileDeadOnly)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, cyclingMode, eCyclingMode::ALLOW_CYCLE_TEAMMATES)); + return true; + } + + void ForceCameraTargetCycle::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bForceCycling); + BitStreamUtils::WriteOptional(bitStream, cyclingMode, eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES); + bitStream.Write(optionalTargetID); + } + + bool ForceCameraTargetCycle::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bForceCycling)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, cyclingMode, eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES)); + VALIDATE_READ(bitStream.Read(optionalTargetID)); + return true; + } +} diff --git a/dGame/dGameMessages/MovementMessages.h b/dGame/dGameMessages/MovementMessages.h new file mode 100644 index 000000000..efcc51b39 --- /dev/null +++ b/dGame/dGameMessages/MovementMessages.h @@ -0,0 +1,282 @@ +#ifndef MOVEMENTMESSAGES_H +#define MOVEMENTMESSAGES_H + +#include "GameMessages.h" +#include "NiQuaternion.h" +#include "eControlScheme.h" +#include "eCyclingMode.h" +#include "eMovementPlatformState.h" + +#include + +enum class eCameraTargetCyclingMode : int32_t { + ALLOW_CYCLE_TEAMMATES, + DISALLOW_CYCLING +}; + +// Game messages for moving things around: teleports, moving platforms, rails, mounts and possession, jetpacks, +// ghosting reference points, the camera and the control scheme. +// Fields are listed in wire order; names follow the client (legouniverse.exe 1.10.64) where known. +namespace GameMessages { + // Server -> client, to one client (UNASSIGNED broadcasts). + struct Teleport : public NetGameMsg { + Teleport() : NetGameMsg(MessageType::Game::TELEPORT) {} + // bIgnoreY is set when pos.y is 0, as DLU always did. + Teleport(const LWOOBJID _target, const NiPoint3& _pos, const NiQuaternion& _rot, const bool _bSetRotation = false) : Teleport() { + target = _target; + bIgnoreY = _pos.y == 0.0f; + bSetRotation = _bSetRotation; + pos = _pos; + rot = _rot; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bIgnoreY{ true }; + bool bSetRotation{ false }; + bool bSkipAllChecks{ false }; + NiPoint3 pos{}; + bool bUseNavmesh{ false }; + // w is optional (default 1.0f), then x, y, z always. + NiQuaternion rot{ QuatUtils::IDENTITY }; + }; + + // Server -> client, broadcast. No payload. + struct StartPathing : public NetGameMsg { + StartPathing() : NetGameMsg(MessageType::Game::START_PATHING) {} + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct PlatformResync : public NetGameMsg { + PlatformResync() : NetGameMsg(MessageType::Game::PLATFORM_RESYNC) {} + // What DLU sends for a platform entity: the arguments, overridden for a few LOTs whose paths only have a + // start and an end (special is for the FV tree platform). + PlatformResync(const Entity& entity, bool bStopAtDesiredWaypoint = false, + int32_t iIndex = 0, int32_t iDesiredWaypointIndex = 1, int32_t nextIndex = 1, + eMovementPlatformState movementState = eMovementPlatformState::Moving, bool special = false); + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bReverse{ false }; + bool bStopAtDesiredWaypoint{ false }; + int32_t eCommand{ 0 }; + eMovementPlatformState eState{ eMovementPlatformState::Moving }; // written as int32_t + int32_t eUnexpectedCommand{ 0 }; + float fIdleTimeElapsed{ 0.0f }; + float fMoveTimeElapsed{ 0.0f }; + float fPercentBetweenPoints{ 0.0f }; + int32_t iDesiredWaypointIndex{ 1 }; + int32_t iIndex{ 0 }; + int32_t iNextIndex{ 1 }; + NiPoint3 ptUnexpectedLocation{ NiPoint3Constant::ZERO }; + // optional (default identity), written x, y, z, w + NiQuaternion qUnexpectedRotation{ QuatUtils::IDENTITY }; + }; + + // Client -> server. No payload. Answered with a PlatformResync. + struct RequestPlatformResync : public NetGameMsg { + RequestPlatformResync() : NetGameMsg(MessageType::Game::REQUEST_PLATFORM_RESYNC) {} + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct OrientToAngle : public NetGameMsg { + OrientToAngle() : NetGameMsg(MessageType::Game::ORIENT_TO_ANGLE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bRelativeToCurrent{}; + float fAngle{}; + }; + + // Server -> client, broadcast. + struct LockNodeRotation : public NetGameMsg { + LockNodeRotation() : NetGameMsg(MessageType::Game::LOCK_NODE_ROTATION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::string nodeName{}; + }; + + // Server -> client, to one client. + struct SetGravityScale : public NetGameMsg { + SetGravityScale() : NetGameMsg(MessageType::Game::SET_GRAVITY_SCALE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + float scale{}; + }; + + // Server -> client, broadcast. + struct SetJetPackMode : public NetGameMsg { + SetJetPackMode() : NetGameMsg(MessageType::Game::SET_JET_PACK_MODE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bBypassChecks{ false }; + bool bDoHover{ false }; + bool bUse{}; + int32_t effectID{ -1 }; // optional + float fAirspeed{ 10.0f }; // optional + float fMaxAirspeed{ 15.0f }; // optional + float fVertVel{ 1.0f }; // optional + int32_t iWarningEffectID{ -1 }; // optional + }; + + // Server -> client, to one client. + struct SetPlayerControlScheme : public NetGameMsg { + SetPlayerControlScheme() : NetGameMsg(MessageType::Game::SET_PLAYER_CONTROL_SCHEME) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bDelayCamSwitchIfInCinematic{ true }; + bool bSwitchCam{ true }; + eControlScheme iScheme{ eControlScheme::SCHEME_A }; // optional + }; + + // Server -> client, to one client. + struct PlayerReachedRespawnCheckpoint : public NetGameMsg { + PlayerReachedRespawnCheckpoint() : NetGameMsg(MessageType::Game::PLAYER_REACHED_RESPAWN_CHECKPOINT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + NiPoint3 pos{}; + // optional (default identity), written w, x, y, z + NiQuaternion rot{ QuatUtils::IDENTITY }; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct SetRailMovement : public NetGameMsg { + SetRailMovement() : NetGameMsg(MessageType::Game::SET_RAIL_MOVEMENT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool pathGoForward{}; + std::u16string pathName{}; + uint32_t pathStart{}; + int32_t railActivatorComponentID{ -1 }; // optional + LWOOBJID railActivatorObjectID{ LWOOBJID_EMPTY }; // optional + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct StartRailMovement : public NetGameMsg { + StartRailMovement() : NetGameMsg(MessageType::Game::START_RAIL_MOVEMENT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bDamageImmune{ true }; + bool bNoAggro{ true }; + bool bNotifyActor{ false }; + bool bShowNameBillboard{ true }; + bool bCameraLocked{ true }; + bool bCollisionEnabled{ true }; + std::u16string loopSound{}; + bool goForward{ true }; + std::u16string pathName{}; + uint32_t pathStart{ 0 }; // optional + int32_t railActivatorComponentID{ -1 }; // optional + LWOOBJID railActivatorObjectID{ LWOOBJID_EMPTY }; // optional + std::u16string startSound{}; + std::u16string stopSound{}; + bool bUseDB{ true }; + }; + + // Client -> server. No payload. + struct ClientRailMovementReady : public NetGameMsg { + ClientRailMovementReady() : NetGameMsg(MessageType::Game::CLIENT_RAIL_MOVEMENT_READY) {} + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + }; + + // Client -> server. + struct CancelRailMovement : public NetGameMsg { + CancelRailMovement() : NetGameMsg(MessageType::Game::CANCEL_RAIL_MOVEMENT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + bool bImmediate{}; + }; + + // Client -> server. + struct PlayerRailArrivedNotification : public NetGameMsg { + PlayerRailArrivedNotification() : NetGameMsg(MessageType::Game::PLAYER_RAIL_ARRIVED_NOTIFICATION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + std::u16string pathName{}; + int32_t waypointNumber{}; + }; + + // Server -> client, broadcast. + struct SetMountInventoryID : public NetGameMsg { + SetMountInventoryID() : NetGameMsg(MessageType::Game::SET_MOUNT_INVENTORY_ID) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + LWOOBJID inventoryMountID{ LWOOBJID_EMPTY }; // optional + }; + + // Client -> server. + struct DismountComplete : public NetGameMsg { + DismountComplete() : NetGameMsg(MessageType::Game::DISMOUNT_COMPLETE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + LWOOBJID mountID{}; + }; + + // Client -> server. + struct AcknowledgePossession : public NetGameMsg { + AcknowledgePossession() : NetGameMsg(MessageType::Game::ACKNOWLEDGE_POSSESSION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + LWOOBJID possessedObjID{ LWOOBJID_EMPTY }; // optional + }; + + // Client -> server. + struct ToggleGhostReferenceOverride : public NetGameMsg { + ToggleGhostReferenceOverride() : NetGameMsg(MessageType::Game::TOGGLE_GHOST_REFERENCE_OVERRIDE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + bool bOverride{ false }; + }; + + // Client -> server. + struct SetGhostReferencePosition : public NetGameMsg { + SetGhostReferencePosition() : NetGameMsg(MessageType::Game::SET_GHOST_REFERENCE_POSITION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + NiPoint3 pos{}; + }; + + // Server -> client, to one client. + struct PlayerSetCameraCyclingMode : public NetGameMsg { + PlayerSetCameraCyclingMode() : NetGameMsg(MessageType::Game::PLAYER_SET_CAMERA_CYCLING_MODE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bAllowCyclingWhileDeadOnly{ true }; + eCyclingMode cyclingMode{ eCyclingMode::ALLOW_CYCLE_TEAMMATES }; // optional + }; + + // Server -> client, to one client. + struct ForceCameraTargetCycle : public NetGameMsg { + ForceCameraTargetCycle() : NetGameMsg(MessageType::Game::FORCE_CAMERA_TARGET_CYCLE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bForceCycling{}; + eCameraTargetCyclingMode cyclingMode{ eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES }; // optional + LWOOBJID optionalTargetID{}; + }; +} + +#endif // MOVEMENTMESSAGES_H diff --git a/dGame/dGameMessages/ObjectMessages.cpp b/dGame/dGameMessages/ObjectMessages.cpp new file mode 100644 index 000000000..93c976f5a --- /dev/null +++ b/dGame/dGameMessages/ObjectMessages.cpp @@ -0,0 +1,292 @@ +#include "ObjectMessages.h" + +#include "BitStreamUtils.h" +#include "Character.h" +#include "CharacterComponent.h" +#include "ClientPackets.h" +#include "Entity.h" +#include "EntityManager.h" +#include "Game.h" +#include "GeneralUtils.h" +#include "Logger.h" +#include "MissionComponent.h" +#include "MissionOfferComponent.h" +#include "PlayerManager.h" +#include "RocketLaunchpadControlComponent.h" +#include "ZoneInstanceManager.h" +#include "dServer.h" +#include "dZoneManager.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" + +namespace GameMessages { + void FireEventClientSide::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, args); + bitStream.Write(object); + BitStreamUtils::WriteOptional(bitStream, param1, 0); + BitStreamUtils::WriteOptional(bitStream, param2, -1); + bitStream.Write(senderID); + } + + bool FireEventClientSide::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, args)); + VALIDATE_READ(bitStream.Read(object)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, param1, 0)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, param2, -1)); + VALIDATE_READ(bitStream.Read(senderID)); + return true; + } + + void FireEventServerSide::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, args); + BitStreamUtils::WriteOptional(bitStream, param1, -1); + BitStreamUtils::WriteOptional(bitStream, param2, -1); + BitStreamUtils::WriteOptional(bitStream, param3, -1); + bitStream.Write(senderID); + } + + bool FireEventServerSide::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, args)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, param1, -1)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, param2, -1)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, param3, -1)); + VALIDATE_READ(bitStream.Read(senderID)); + return true; + } + + void FireEventServerSide::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* sender = Game::entityManager->GetEntity(senderID); + auto* player = PlayerManager::GetPlayer(sysAddr); + + if (!player) { + return; + } + + // This should probably get it's own "ServerEvents" system or something at some point + if (args == u"ZonePlayer") { + // Should probably check to make sure they're using a launcher at some point before someone makes a hack that lets you testmap + + LWOCLONEID cloneId = 0; + LWOMAPID mapId = 0; + + auto* rocketPad = entity.GetComponent(); + + if (rocketPad == nullptr) return; + + cloneId = rocketPad->GetSelectedCloneId(player->GetObjectID()); + + if (param2) { + mapId = rocketPad->GetDefaultZone(); + } else { + mapId = param3; + } + + if (mapId == 0) { + mapId = rocketPad->GetSelectedMapId(player->GetObjectID()); + } + + if (mapId == 0) { + mapId = Game::zoneManager->GetZoneID().GetMapID(); // Fallback to sending the player back to the same zone. + } + + LOG("Player %llu has requested zone transfer to (%i, %i).", sender->GetObjectID(), static_cast(mapId), static_cast(cloneId)); + + auto* character = player->GetCharacter(); + + if (mapId <= 0) { + return; + } + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, mapId, cloneId, false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + + if (character) { + auto* characterComponent = player->GetComponent(); + if (characterComponent) { + characterComponent->AddVisitedLevel(LWOZONEID(zoneID, LWOINSTANCEID_INVALID, zoneClone)); + } + + character->SetZoneID(zoneID); + character->SetZoneInstance(zoneInstance); + character->SetZoneClone(zoneClone); + } + + ClientPackets::TransferToWorld transfer; + transfer.serverIP = LUString(serverIP); + transfer.serverPort = serverPort; + transfer.mythranShift = mythranShift; + transfer.Send(sysAddr); + return; + }); + } + + entity.OnFireEventServerSide(sender, GeneralUtils::UTF16ToWTF8(args), param1, param2, param3); + } + + namespace { + template + void WriteNotify(RakNet::BitStream& bitStream, const Msg& msg) { + BitStreamUtils::WriteLengthPrefixed(bitStream, msg.name); + bitStream.Write(msg.param1); + bitStream.Write(msg.param2); + bitStream.Write(msg.paramObj); + BitStreamUtils::WriteLengthPrefixed(bitStream, msg.paramStr); + } + + template + bool ReadNotify(RakNet::BitStream& bitStream, Msg& msg) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, msg.name)); + VALIDATE_READ(bitStream.Read(msg.param1)); + VALIDATE_READ(bitStream.Read(msg.param2)); + VALIDATE_READ(bitStream.Read(msg.paramObj)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, msg.paramStr)); + return true; + } + } + + void NotifyClientObject::Serialize(RakNet::BitStream& bitStream) const { + WriteNotify(bitStream, *this); + } + + bool NotifyClientObject::Deserialize(RakNet::BitStream& bitStream) { + return ReadNotify(bitStream, *this); + } + + void NotifyClientZoneObject::Serialize(RakNet::BitStream& bitStream) const { + WriteNotify(bitStream, *this); + } + + bool NotifyClientZoneObject::Deserialize(RakNet::BitStream& bitStream) { + return ReadNotify(bitStream, *this); + } + + void NotifyObject::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(objIDSender); + BitStreamUtils::WriteLengthPrefixed(bitStream, name); + bitStream.Write(param1); + bitStream.Write(param2); + } + + bool NotifyObject::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(objIDSender)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, name)); + VALIDATE_READ(bitStream.Read(param1)); + VALIDATE_READ(bitStream.Read(param2)); + return true; + } + + void ScriptNetworkVarUpdate::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteNameValueText(bitStream, tableOfVars); + } + + bool ScriptNetworkVarUpdate::Deserialize(RakNet::BitStream& bitStream) { + return BitStreamUtils::ReadNameValueText(bitStream, tableOfVars); + } + + void NotifyClientFailedPrecondition::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, failedReason); + bitStream.Write(preconditionID); + } + + bool NotifyClientFailedPrecondition::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, failedReason)); + VALIDATE_READ(bitStream.Read(preconditionID)); + return true; + } + + void TerminateInteraction::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(terminator); + bitStream.Write(type); + } + + bool TerminateInteraction::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(terminator)); + VALIDATE_READ(bitStream.Read(type)); + return true; + } + + void SetName::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, name); + } + + bool SetName::Deserialize(RakNet::BitStream& bitStream) { + return BitStreamUtils::ReadLengthPrefixed(bitStream, name); + } + + void RequestUse::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bIsMultiInteractUse); + bitStream.Write(multiInteractID); + bitStream.Write(multiInteractType); + bitStream.Write(object); + bitStream.Write(secondary); + } + + bool RequestUse::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bIsMultiInteractUse)); + VALIDATE_READ(bitStream.Read(multiInteractID)); + VALIDATE_READ(bitStream.Read(multiInteractType)); + VALIDATE_READ(bitStream.Read(object)); + VALIDATE_READ(bitStream.Read(secondary)); + return true; + } + + void RequestUse::Handle(Entity& entity, const SystemAddress& sysAddr) { + Entity* interactedObject = Game::entityManager->GetEntity(object); + + if (interactedObject == nullptr) { + LOG("Object %llu tried to interact, but doesn't exist!", object); + + return; + } + + if (interactedObject->GetLOT() == 9524) { + entity.GetCharacter()->SetBuildMode(true); + } + + if (bIsMultiInteractUse) { + if (multiInteractType == 0) { + auto* missionOfferComponent = static_cast(interactedObject->GetComponent(eReplicaComponentType::MISSION_OFFER)); + + if (missionOfferComponent != nullptr) { + missionOfferComponent->OfferMissions(&entity, multiInteractID); + } + } else { + interactedObject->OnUse(&entity); + } + } else { + interactedObject->OnUse(&entity); + } + + RequestUseEvent event(*this); + interactedObject->HandleMsg(event); + + //Perform use task if possible: + auto missionComponent = entity.GetComponent(); + + if (!missionComponent) return; + + missionComponent->Progress(eMissionTaskType::TALK_TO_NPC, interactedObject->GetLOT(), interactedObject->GetObjectID()); + missionComponent->Progress(eMissionTaskType::INTERACT, interactedObject->GetLOT(), interactedObject->GetObjectID()); + } + + void RequestServerObjectInfo::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bVerbose); + bitStream.Write(clientId); + bitStream.Write(targetForReport); + } + + bool RequestServerObjectInfo::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bVerbose)); + VALIDATE_READ(bitStream.Read(clientId)); + VALIDATE_READ(bitStream.Read(targetForReport)); + return true; + } + + void RequestServerObjectInfo::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* handlingEntity = Game::entityManager->GetEntity(targetForReport); + if (handlingEntity) { + RequestServerObjectInfoEvent event(*this); + handlingEntity->HandleMsg(event); + } else LOG("Failed to find target %llu", targetForReport); + } +} diff --git a/dGame/dGameMessages/ObjectMessages.h b/dGame/dGameMessages/ObjectMessages.h new file mode 100644 index 000000000..7e0a0475b --- /dev/null +++ b/dGame/dGameMessages/ObjectMessages.h @@ -0,0 +1,188 @@ +#ifndef OBJECTMESSAGES_H +#define OBJECTMESSAGES_H + +#include "GameMessages.h" +#include "eTerminateType.h" + +#include + +// Game messages between an object's server script and its client script (fire event, notify object), and object +// interaction (use, terminate, names, debug info). +// Fields are listed in wire order; names follow the client (legouniverse.exe 1.10.64) where known. +namespace GameMessages { + // Server -> client, to one client. + struct FireEventClientSide : public NetGameMsg { + FireEventClientSide() : NetGameMsg(MessageType::Game::FIRE_EVENT_CLIENT_SIDE) {} + FireEventClientSide(const LWOOBJID _target, const std::u16string& _args, const LWOOBJID _object, const LWOOBJID _senderID) : FireEventClientSide() { + target = _target; + args = _args; + object = _object; + senderID = _senderID; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string args{}; + LWOOBJID object{}; + int64_t param1{ 0 }; // optional + int32_t param2{ -1 }; // optional + LWOOBJID senderID{}; + }; + + // Client -> server. + struct FireEventServerSide : public NetGameMsg { + FireEventServerSide() : NetGameMsg(MessageType::Game::FIRE_EVENT_SERVER_SIDE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + std::u16string args{}; + int32_t param1{ -1 }; // optional + int32_t param2{ -1 }; // optional + int32_t param3{ -1 }; // optional + LWOOBJID senderID{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct NotifyClientObject : public NetGameMsg { + NotifyClientObject() : NetGameMsg(MessageType::Game::NOTIFY_CLIENT_OBJECT) {} + NotifyClientObject(const LWOOBJID _target, const std::u16string& _name, const int32_t _param1 = 0, const int32_t _param2 = 0, + const LWOOBJID _paramObj = LWOOBJID_EMPTY, const std::string& _paramStr = "") : NotifyClientObject() { + target = _target; + name = _name; + param1 = _param1; + param2 = _param2; + paramObj = _paramObj; + paramStr = _paramStr; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string name{}; + int32_t param1{}; + int32_t param2{}; + LWOOBJID paramObj{}; + std::string paramStr{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). Same layout as NotifyClientObject. + struct NotifyClientZoneObject : public NetGameMsg { + NotifyClientZoneObject() : NetGameMsg(MessageType::Game::NOTIFY_CLIENT_ZONE_OBJECT) {} + NotifyClientZoneObject(const LWOOBJID _target, const std::u16string& _name, const int32_t _param1 = 0, const int32_t _param2 = 0, + const LWOOBJID _paramObj = LWOOBJID_EMPTY, const std::string& _paramStr = "") : NotifyClientZoneObject() { + target = _target; + name = _name; + param1 = _param1; + param2 = _param2; + paramObj = _paramObj; + paramStr = _paramStr; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string name{}; + int32_t param1{}; + int32_t param2{}; + LWOOBJID paramObj{}; + std::string paramStr{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct NotifyObject : public NetGameMsg { + NotifyObject() : NetGameMsg(MessageType::Game::NOTIFY_OBJECT) {} + NotifyObject(const LWOOBJID _target, const LWOOBJID _objIDSender, const std::u16string& _name, const int32_t _param1 = 0, const int32_t _param2 = 0) : NotifyObject() { + target = _target; + objIDSender = _objIDSender; + name = _name; + param1 = _param1; + param2 = _param2; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + LWOOBJID objIDSender{}; + std::u16string name{}; + int32_t param1{ 0 }; + int32_t param2{ 0 }; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct ScriptNetworkVarUpdate : public NetGameMsg { + ScriptNetworkVarUpdate() : NetGameMsg(MessageType::Game::SCRIPT_NETWORK_VAR_UPDATE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string tableOfVars{}; // name-value (LDF) text + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct NotifyClientFailedPrecondition : public NetGameMsg { + NotifyClientFailedPrecondition() : NetGameMsg(MessageType::Game::NOTIFY_CLIENT_FAILED_PRECONDITION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string failedReason{}; + int32_t preconditionID{}; + }; + + // Server -> client, broadcast. + struct TerminateInteraction : public NetGameMsg { + TerminateInteraction() : NetGameMsg(MessageType::Game::TERMINATE_INTERACTION) {} + TerminateInteraction(const LWOOBJID _target, const eTerminateType _type, const LWOOBJID _terminator) : TerminateInteraction() { + target = _target; + type = _type; + terminator = _terminator; + } + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + LWOOBJID terminator{}; + eTerminateType type{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct SetName : public NetGameMsg { + SetName() : NetGameMsg(MessageType::Game::SET_NAME) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string name{}; + }; + + // Client -> server. + struct RequestUse : public NetGameMsg { + RequestUse() : NetGameMsg(MessageType::Game::REQUEST_USE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + // Set to true if this coming from a multi-interaction UI on the client. + bool bIsMultiInteractUse{}; + + // Used only for multi-interaction + uint32_t multiInteractID{}; + + // Used only for multi-interaction, is of the enum type InteractionType + int32_t multiInteractType{}; + + LWOOBJID object{}; + + bool secondary{ false }; + }; + using RequestUseEvent = NetGameMsgEvent; + + // Client -> server. Developer only. + struct RequestServerObjectInfo : public NetGameMsg { + RequestServerObjectInfo() : NetGameMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, eGameMasterLevel::DEVELOPER) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + bool bVerbose{}; + LWOOBJID clientId{}; + LWOOBJID targetForReport{}; + }; + using RequestServerObjectInfoEvent = NetGameMsgEvent; +} + +#endif // OBJECTMESSAGES_H diff --git a/dGame/dGameMessages/PlayerMessages.cpp b/dGame/dGameMessages/PlayerMessages.cpp new file mode 100644 index 000000000..fd9a2a5c2 --- /dev/null +++ b/dGame/dGameMessages/PlayerMessages.cpp @@ -0,0 +1,209 @@ +#include "PlayerMessages.h" + +#include "BitStreamUtils.h" +#include "Character.h" +#include "CharacterComponent.h" +#include "DashboardNotify.h" +#include "Database.h" +#include "Entity.h" +#include "GeneralUtils.h" +#include "IBugReports.h" +#include "PlayerReports.h" +#include "SlashCommandHandler.h" + +namespace GameMessages { + void UpdateChatMode::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(level); + } + + bool UpdateChatMode::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(level); + } + + void SetGMLevel::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bOverride); + bitStream.Write(level); + } + + bool SetGMLevel::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bOverride)); + VALIDATE_READ(bitStream.Read(level)); + return true; + } + + void ModifyLEGOScore::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(score); + BitStreamUtils::WriteOptional(bitStream, sourceType, eLootSourceType::NONE); + } + + bool ModifyLEGOScore::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(score)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, sourceType, eLootSourceType::NONE)); + return true; + } + + void SetCurrency::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(currency); + BitStreamUtils::WriteOptional(bitStream, lootType, LOOTTYPE_NONE); + bitStream.Write(position.x); + bitStream.Write(position.y); + bitStream.Write(position.z); + BitStreamUtils::WriteOptional(bitStream, sourceLOT, LOT_NULL); + BitStreamUtils::WriteOptional(bitStream, sourceID, LWOOBJID_EMPTY); + BitStreamUtils::WriteOptional(bitStream, sourceTradeID, 0); + BitStreamUtils::WriteOptional(bitStream, sourceType, eLootSourceType::NONE); + } + + bool SetCurrency::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(currency)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, lootType, LOOTTYPE_NONE)); + VALIDATE_READ(bitStream.Read(position.x)); + VALIDATE_READ(bitStream.Read(position.y)); + VALIDATE_READ(bitStream.Read(position.z)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, sourceLOT, LOT_NULL)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, sourceID, LWOOBJID_EMPTY)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, sourceTradeID, 0)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, sourceType, eLootSourceType::NONE)); + return true; + } + + void UpdateReputation::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(reputation); + } + + bool UpdateReputation::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(reputation); + } + + void ToggleGMInvis::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bStateOut); + } + + bool ToggleGMInvis::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(bStateOut); + } + + void PickupCurrency::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(currency); + } + + bool PickupCurrency::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(currency); + } + + void PickupCurrency::Handle(Entity& entity, const SystemAddress& sysAddr) { + if (currency == 0) return; + + auto* ch = entity.GetCharacter(); + if (ch && entity.PickupCoins(currency)) { + ch->SetCoins(ch->GetCoins() + currency, eLootSourceType::PICKUP); + } + } + + void ModifyPlayerZoneStatistic::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bSet); + BitStreamUtils::WriteLengthPrefixed(bitStream, statName); + BitStreamUtils::WriteOptional(bitStream, statValue, 0); + BitStreamUtils::WriteOptional(bitStream, zoneID, LWOMAPID_INVALID); + } + + bool ModifyPlayerZoneStatistic::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bSet)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, statName)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, statValue, 0)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, zoneID, LWOMAPID_INVALID)); + return true; + } + + void ModifyPlayerZoneStatistic::Handle(Entity& entity, const SystemAddress& sysAddr) { + // Notify the character component that something's changed + auto* characterComponent = entity.GetComponent(); + if (characterComponent != nullptr) { + characterComponent->HandleZoneStatisticsUpdate(zoneID, statName, statValue); + } + } + + void UpdatePlayerStatistic::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(updateID); + BitStreamUtils::WriteOptional(bitStream, updateValue, 1); + } + + bool UpdatePlayerStatistic::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(updateID)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, updateValue, 1)); + return true; + } + + void UpdatePlayerStatistic::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* characterComponent = entity.GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(static_cast(updateID), static_cast(std::max(updateValue, static_cast(0))), true); + } + } + + void ParseChatMessage::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(iClientState); + BitStreamUtils::WriteLengthPrefixed(bitStream, wsString); + } + + bool ParseChatMessage::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(iClientState)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, wsString)); + return true; + } + + void ParseChatMessage::Handle(Entity& entity, const SystemAddress& sysAddr) { + if (!wsString.empty() && wsString[0] == L'/') { + SlashCommandHandler::HandleChatCommand(wsString, &entity, sysAddr); + } + } + + void ReportBug::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, body); + BitStreamUtils::WriteLengthPrefixed(bitStream, clientVersion); + BitStreamUtils::WriteLengthPrefixed(bitStream, otherPlayerID); + BitStreamUtils::WriteLengthPrefixed(bitStream, selection); + } + + bool ReportBug::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, body)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, clientVersion)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, otherPlayerID)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, selection)); + return true; + } + + void ReportBug::Handle(Entity& entity, const SystemAddress& sysAddr) { + IBugReports::Info reportInfo; + // The body is stored narrowed to one byte per character, as DLU always did. + for (const auto character : body) reportInfo.body.push_back(static_cast(character)); + reportInfo.clientVersion = clientVersion; + reportInfo.otherPlayer = otherPlayerID; + reportInfo.selection = selection; + + auto character = entity.GetCharacter(); + if (character) reportInfo.characterId = character->GetID(); + + // Report Abuse about another player sends their ID here (and "0" otherwise); that's a player report, not a bug + if (const auto reportedId = GeneralUtils::TryParse(reportInfo.otherPlayer).value_or(LWOOBJID_EMPTY); reportedId != LWOOBJID_EMPTY) { + PlayerReports::ReportPlayer(&entity, reportedId, reportInfo.body); + return; + } + + Database::Get()->InsertNewBugReport(reportInfo); + DashboardNotify::Changed("bug_reports"); + } + + void VerifyAck::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bDifferent); + BitStreamUtils::WriteLengthPrefixed(bitStream, sBitStream); + BitStreamUtils::WriteOptional(bitStream, uiHandle, 0); + } + + bool VerifyAck::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bDifferent)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, sBitStream)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, uiHandle, 0)); + return true; + } +} diff --git a/dGame/dGameMessages/PlayerMessages.h b/dGame/dGameMessages/PlayerMessages.h new file mode 100644 index 000000000..168ed7039 --- /dev/null +++ b/dGame/dGameMessages/PlayerMessages.h @@ -0,0 +1,149 @@ +#ifndef PLAYERMESSAGES_H +#define PLAYERMESSAGES_H + +#include "GameMessages.h" +#include "eGameMasterLevel.h" +#include "eLootSourceType.h" + +#include + +// Game messages about a player's own state: GM level and chat mode, score, coins, reputation, statistics, chat +// commands and bug reports. +// Fields are listed in wire order; names follow the client (legouniverse.exe 1.10.64) where known. +namespace GameMessages { + // Server -> client, broadcast. + struct UpdateChatMode : public NetGameMsg { + UpdateChatMode() : NetGameMsg(MessageType::Game::UPDATE_CHAT_MODE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + eGameMasterLevel level{}; + }; + + // Server -> client, broadcast. + struct SetGMLevel : public NetGameMsg { + SetGMLevel() : NetGameMsg(MessageType::Game::SET_GM_LEVEL) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + // DLU always writes this bit set. + bool bOverride{ true }; + eGameMasterLevel level{}; + }; + + // Server -> client, to one client. + struct ModifyLEGOScore : public NetGameMsg { + ModifyLEGOScore() : NetGameMsg(MessageType::Game::MODIFY_LEGO_SCORE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int64_t score{}; + eLootSourceType sourceType{ eLootSourceType::NONE }; // optional + }; + + // Server -> client, to one client. + struct SetCurrency : public NetGameMsg { + SetCurrency() : NetGameMsg(MessageType::Game::SET_CURRENCY) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int64_t currency{}; + int32_t lootType{ LOOTTYPE_NONE }; // optional + NiPoint3 position{ NiPoint3Constant::ZERO }; + LOT sourceLOT{ LOT_NULL }; // optional + LWOOBJID sourceID{ LWOOBJID_EMPTY }; // optional + // optional (default 0). DLU writes it as an int32_t; lu_packets has an object ID (8 bytes). Only ever 0. + int32_t sourceTradeID{ 0 }; + eLootSourceType sourceType{ eLootSourceType::NONE }; // optional + }; + + // Server -> client, to one client. + struct UpdateReputation : public NetGameMsg { + UpdateReputation() : NetGameMsg(MessageType::Game::UPDATE_REPUTATION) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int64_t reputation{}; + }; + + // Server -> client, broadcast. + struct ToggleGMInvis : public NetGameMsg { + ToggleGMInvis() : NetGameMsg(MessageType::Game::TOGGLE_GM_INVIS) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bStateOut{ false }; + }; + using ToggleGMInvisEvent = NetGameMsgEvent; + + // Client -> server. DLU reads only the amount; lu_packets has a position after it. + struct PickupCurrency : public NetGameMsg { + PickupCurrency() : NetGameMsg(MessageType::Game::PICKUP_CURRENCY) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + uint32_t currency{}; + }; + + // Client -> server. + struct ModifyPlayerZoneStatistic : public NetGameMsg { + ModifyPlayerZoneStatistic() : NetGameMsg(MessageType::Game::MODIFY_PLAYER_ZONE_STATISTIC) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + bool bSet{ false }; + std::u16string statName{}; + int32_t statValue{ 0 }; // optional + LWOMAPID zoneID{ LWOMAPID_INVALID }; // optional + }; + + // Client -> server. + struct UpdatePlayerStatistic : public NetGameMsg { + UpdatePlayerStatistic() : NetGameMsg(MessageType::Game::UPDATE_PLAYER_STATISTIC) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + int32_t updateID{}; + int64_t updateValue{ 1 }; // optional + }; + + // Client -> server. Chat text the client parses as a command (starts with '/'). + struct ParseChatMessage : public NetGameMsg { + ParseChatMessage() : NetGameMsg(MessageType::Game::PARSE_CHAT_MESSAGE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + int32_t iClientState{}; + std::u16string wsString{}; + }; + + // Client -> server. A bug report, or a player report when otherPlayerID holds a player's ID. + struct ReportBug : public NetGameMsg { + ReportBug() : NetGameMsg(MessageType::Game::REPORT_BUG) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + std::u16string body{}; + std::string clientVersion{}; + std::string otherPlayerID{}; + std::string selection{}; + }; + + // Client -> server. Nothing is done with it. + struct VerifyAck : public NetGameMsg { + VerifyAck() : NetGameMsg(MessageType::Game::VERIFY_ACK) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bDifferent{ false }; + std::string sBitStream{}; + uint32_t uiHandle{ 0 }; // optional + }; +} + +#endif // PLAYERMESSAGES_H diff --git a/dGame/dGameMessages/PropertyMessages.cpp b/dGame/dGameMessages/PropertyMessages.cpp index 4ee41e004..9e7e09db2 100644 --- a/dGame/dGameMessages/PropertyMessages.cpp +++ b/dGame/dGameMessages/PropertyMessages.cpp @@ -738,4 +738,13 @@ namespace GameMessages { } return true; } + + void PlayBehaviorSound::Serialize(RakNet::BitStream& stream) const { + stream.Write(soundID != -1); + if (soundID != -1) stream.Write(soundID); + } + + bool PlayBehaviorSound::Deserialize(RakNet::BitStream& stream) { + return BitStreamUtils::ReadOptional(stream, soundID, -1); + } } diff --git a/dGame/dGameMessages/PropertyMessages.h b/dGame/dGameMessages/PropertyMessages.h index 24f847d86..103fba34c 100644 --- a/dGame/dGameMessages/PropertyMessages.h +++ b/dGame/dGameMessages/PropertyMessages.h @@ -393,6 +393,15 @@ namespace GameMessages { std::vector properties; }; + + struct PlayBehaviorSound : public NetGameMsg { + PlayBehaviorSound() : NetGameMsg(MessageType::Game::PLAY_BEHAVIOR_SOUND) {} + + void Serialize(RakNet::BitStream& stream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + int32_t soundID{ -1 }; + }; }; #endif // PROPERTYMESSAGES_H diff --git a/dGame/dGameMessages/QuickBuildMessages.cpp b/dGame/dGameMessages/QuickBuildMessages.cpp new file mode 100644 index 000000000..9191b5255 --- /dev/null +++ b/dGame/dGameMessages/QuickBuildMessages.cpp @@ -0,0 +1,58 @@ +#include "QuickBuildMessages.h" + +#include "BitStreamUtils.h" +#include "Entity.h" +#include "EntityManager.h" +#include "QuickBuildComponent.h" + +namespace GameMessages { + void RebuildNotifyState::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(prevState); + bitStream.Write(state); + bitStream.Write(player); + } + + bool RebuildNotifyState::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(prevState)); + VALIDATE_READ(bitStream.Read(state)); + VALIDATE_READ(bitStream.Read(player)); + return true; + } + + void EnableRebuild::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bEnable); + bitStream.Write(bFail); + bitStream.Write(bSuccess); + BitStreamUtils::WriteOptional(bitStream, eFailReason, eQuickBuildFailReason::NOT_GIVEN); + bitStream.Write(fDuration); + bitStream.Write(user); + } + + bool EnableRebuild::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bEnable)); + VALIDATE_READ(bitStream.Read(bFail)); + VALIDATE_READ(bitStream.Read(bSuccess)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, eFailReason, eQuickBuildFailReason::NOT_GIVEN)); + VALIDATE_READ(bitStream.Read(fDuration)); + VALIDATE_READ(bitStream.Read(user)); + return true; + } + + void RebuildCancel::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bEarlyRelease); + bitStream.Write(userID); + } + + bool RebuildCancel::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bEarlyRelease)); + VALIDATE_READ(bitStream.Read(userID)); + return true; + } + + void RebuildCancel::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* quickBuildComponent = entity.GetComponent(); + if (!quickBuildComponent) return; + + quickBuildComponent->CancelQuickBuild(Game::entityManager->GetEntity(userID), eQuickBuildFailReason::CANCELED_EARLY); + } +} diff --git a/dGame/dGameMessages/QuickBuildMessages.h b/dGame/dGameMessages/QuickBuildMessages.h new file mode 100644 index 000000000..e9df7ff16 --- /dev/null +++ b/dGame/dGameMessages/QuickBuildMessages.h @@ -0,0 +1,48 @@ +#ifndef QUICKBUILDMESSAGES_H +#define QUICKBUILDMESSAGES_H + +#include "GameMessages.h" +#include "eQuickBuildFailReason.h" +#include "eQuickBuildState.h" + +// Game messages for quickbuilds (rebuilds in the client). +// Fields are listed in wire order; names follow the client (legouniverse.exe 1.10.64) where known. +namespace GameMessages { + // Server -> client, broadcast. + struct RebuildNotifyState : public NetGameMsg { + RebuildNotifyState() : NetGameMsg(MessageType::Game::REBUILD_NOTIFY_STATE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + eQuickBuildState prevState{}; + eQuickBuildState state{}; + LWOOBJID player{}; + }; + + // Server -> client, broadcast. + struct EnableRebuild : public NetGameMsg { + EnableRebuild() : NetGameMsg(MessageType::Game::ENABLE_REBUILD) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bEnable{}; + bool bFail{}; + bool bSuccess{}; + eQuickBuildFailReason eFailReason{ eQuickBuildFailReason::NOT_GIVEN }; // optional + float fDuration{}; + LWOOBJID user{}; + }; + + // Client -> server. + struct RebuildCancel : public NetGameMsg { + RebuildCancel() : NetGameMsg(MessageType::Game::REBUILD_CANCEL) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + bool bEarlyRelease{}; + LWOOBJID userID{}; + }; +} + +#endif // QUICKBUILDMESSAGES_H diff --git a/dGame/dGameMessages/SkillMessages.cpp b/dGame/dGameMessages/SkillMessages.cpp index b1929c358..eba5413d5 100644 --- a/dGame/dGameMessages/SkillMessages.cpp +++ b/dGame/dGameMessages/SkillMessages.cpp @@ -262,4 +262,19 @@ namespace GameMessages { VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, sBitStream)); return true; } + + void UseSkillSet::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(bRemove); + bitStream.Write(possessedId != LWOOBJID_EMPTY); + if (possessedId != LWOOBJID_EMPTY) bitStream.Write(possessedId); + bitStream.Write(setId != -1); + if (setId != -1) bitStream.Write(setId); + } + + bool UseSkillSet::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(bRemove)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, possessedId, LWOOBJID_EMPTY)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, setId, -1)); + return true; + } } diff --git a/dGame/dGameMessages/SkillMessages.h b/dGame/dGameMessages/SkillMessages.h index 26d1195b7..c6cd5f14b 100644 --- a/dGame/dGameMessages/SkillMessages.h +++ b/dGame/dGameMessages/SkillMessages.h @@ -137,6 +137,16 @@ namespace GameMessages { LWOOBJID i64TargetID{ LWOOBJID_EMPTY }; // optional std::string sBitStream{}; }; + + struct UseSkillSet : public NetGameMsg { + UseSkillSet() : NetGameMsg(MessageType::Game::USE_SKILL_SET) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool bRemove{}; + LWOOBJID possessedId{ LWOOBJID_EMPTY }; + int32_t setId{ -1 }; + }; }; #endif // SKILLMESSAGES_H diff --git a/dGame/dGameMessages/ZoneMessages.cpp b/dGame/dGameMessages/ZoneMessages.cpp new file mode 100644 index 000000000..f1681b86e --- /dev/null +++ b/dGame/dGameMessages/ZoneMessages.cpp @@ -0,0 +1,259 @@ +#include "ZoneMessages.h" + +#include "BitStreamUtils.h" +#include "CDClientManager.h" +#include "Character.h" +#include "CharacterComponent.h" +#include "CppScripts.h" +#include "DestroyableComponent.h" +#include "EffectsMessages.h" +#include "Entity.h" +#include "EntityManager.h" +#include "Game.h" +#include "GhostComponent.h" +#include "InventoryComponent.h" +#include "InventoryMessages.h" +#include "LevelProgressionComponent.h" +#include "RacingControlComponent.h" +#include "WorldMigration.h" +#include "dConfig.h" +#include "dZoneManager.h" +#include "eReplicaComponentType.h" +#include "eTriggerEventType.h" +#include "ePlayerFlag.h" + +#include + +namespace GameMessages { + void PlayerLoaded::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(playerID); + } + + bool PlayerLoaded::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(playerID); + } + + void PlayerLoaded::Handle(Entity& entityRef, const SystemAddress& sysAddr) { + auto* entity = &entityRef; + PlayerReady playerReady; + playerReady.target = entity->GetObjectID(); + playerReady.SendToClient(sysAddr); + entity->SetPlayerReadyForUpdates(); + + auto* ghostComponent = entity->GetComponent(); + if (ghostComponent != nullptr) { + ghostComponent->ConstructLimboEntities(); + } + + InventoryComponent* inv = entity->GetComponent(); + if (inv) { + // Clear server-side skill state so AddItemSkills sends fresh AddSkill + // packets to the now-ready client. Skills sent during entity construction + // (Serialize) arrive before LWOSkillComponent is initialized and are dropped. + inv->ClearSkills(); + auto items = inv->GetEquippedItems(); + for (auto pair : items) { + const auto item = pair.second; + + inv->AddItemSkills(item.lot); + } + + // Fixes a bug where testmapping too fast causes large item inventories to become invisible. + // Only affects item inventory + GameMessages::SetInventorySize setSize; + setSize.target = entity->GetObjectID(); + setSize.inventoryType = eInventoryType::ITEMS; + setSize.size = inv->GetInventory(eInventoryType::ITEMS)->GetSize(); + setSize.SendToClient(entity->GetSystemAddress()); + } + + RestoreToPostLoadStats restoreStats; + restoreStats.target = entity->GetObjectID(); + restoreStats.SendToClient(sysAddr); + + auto* const destroyable = entity->GetComponent(); + if (destroyable) destroyable->SetImagination(destroyable->GetImagination()); + Game::entityManager->SerializeEntity(entity); + + std::vector racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + for (Entity* racingController : racingControllers) { + auto* racingComponent = racingController->GetComponent(); + if (racingComponent != nullptr) { + racingComponent->OnPlayerLoaded(entity); + } + } + + Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); + if (zoneControl) { + zoneControl->GetScript()->OnPlayerLoaded(zoneControl, entity); + } + + std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); + for (Entity* scriptEntity : scriptedActs) { + if (!zoneControl || scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds + scriptEntity->GetScript()->OnPlayerLoaded(scriptEntity, entity); + } + } + + //Kill player if health == 0 + if (entity->GetIsDead()) { + entity->Smash(entity->GetObjectID()); + } + + //if the player has moved significantly, move them back: + if ((entity->GetPosition().y - entity->GetCharacter()->GetOriginalPos().y) > 2.0f) { + // Disabled until fixed + //GameMessages::Teleport(entity->GetObjectID(), entity->GetCharacter()->GetOriginalPos(), entity->GetCharacter()->GetOriginalRot(), true).Send(entity->GetSystemAddress()); + } + + /** + * Invoke the OnZoneLoad event on the player character + */ + auto* character = entity->GetCharacter(); + + if (character != nullptr) { + character->OnZoneLoad(); + } + + // Moved here from another instance: put back what their save doesn't keep (the pet that was out) + WorldMigration::OnPlayerLoaded(entity); + + LOG("Player %s (%llu) loaded.", entity->GetCharacter()->GetName().c_str(), entity->GetObjectID()); + + // After we've done our thing, tell the client they're ready + PlayerReady zoneReady; + zoneReady.target = Game::zoneManager->GetZoneControlObject()->GetObjectID(); + zoneReady.SendToClient(sysAddr); + + if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1" + || !entity->GetCharacter() + || !entity->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return; + entity->AddCallbackTimer(0.5f, [entity, sysAddr]() { + if (!entity) return; + GameMessages::EndCinematic endCinematic; + endCinematic.target = entity->GetObjectID(); + endCinematic.Send(sysAddr); + }); + } + + void ReadyForUpdates::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(objectID); + } + + bool ReadyForUpdates::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(objectID); + } + + void InvalidZoneTransferList::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteLengthPrefixed(bitStream, customerFeedbackURL); + BitStreamUtils::WriteLengthPrefixed(bitStream, invalidMapTransferList); + bitStream.Write(bCustomerFeedbackOnExit); + bitStream.Write(bCustomerFeedbackOnInvalidMapTransfer); + } + + bool InvalidZoneTransferList::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, customerFeedbackURL)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, invalidMapTransferList)); + VALIDATE_READ(bitStream.Read(bCustomerFeedbackOnExit)); + VALIDATE_READ(bitStream.Read(bCustomerFeedbackOnInvalidMapTransfer)); + return true; + } + + void DisplayZoneSummary::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(isPropertyMap); + bitStream.Write(isZoneStart); + BitStreamUtils::WriteOptional(bitStream, sender, LWOOBJID_EMPTY); + } + + bool DisplayZoneSummary::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(isPropertyMap)); + VALIDATE_READ(bitStream.Read(isZoneStart)); + VALIDATE_READ(BitStreamUtils::ReadOptional(bitStream, sender, LWOOBJID_EMPTY)); + return true; + } + + void ZoneSummaryDismissed::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(playerID); + } + + bool ZoneSummaryDismissed::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(playerID); + } + + void ZoneSummaryDismissed::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* player = Game::entityManager->GetEntity(playerID); + entity.TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, player); + } + + void NotifyServerLevelProcessingComplete::Handle(Entity& entity, const SystemAddress& sysAddr) { + auto* levelComp = entity.GetComponent(); + if (!levelComp) return; + auto* character = entity.GetComponent(); + if (!character) return; + + //Update our character's level in memory: + levelComp->SetLevel(levelComp->GetLevel() + 1); + + levelComp->HandleLevelUp(); + + auto* inventoryComponent = entity.GetComponent(); + + if (inventoryComponent != nullptr) { + auto* inventory = inventoryComponent->GetInventory(ITEMS); + + if (inventory != nullptr && Game::config->GetValue("disable_extra_backpack") != "1") { + inventory->SetSize(inventory->GetSize() + 2); + } + } + + //Play the level up effect: + GameMessages::PlayFXEffect(entity.GetObjectID(), 7074, u"create", "7074").Send(UNASSIGNED_SYSTEM_ADDRESS); + + //Send a notification in chat: + std::stringstream wss; + wss << "level=1:"; + wss << levelComp->GetLevel(); + wss << "\n"; + wss << "name=0:"; + wss << character->GetName(); + + // FIXME: only really need utf8 conversion for the name, so move that up? + std::u16string attrs = GeneralUtils::UTF8ToUTF16(wss.str()); + std::u16string wsText = u"UI_LEVEL_PROGRESSION_LEVELUP_MESSAGE"; + + GameMessages::BroadcastTextToChatbox chatboxText; + chatboxText.target = entity.GetObjectID(); + chatboxText.attrs = attrs; + chatboxText.wsText = wsText; + chatboxText.Send(UNASSIGNED_SYSTEM_ADDRESS); + } + + void ChangeObjectWorldState::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(newState); + } + + bool ChangeObjectWorldState::Deserialize(RakNet::BitStream& bitStream) { + return bitStream.Read(newState); + } + + void LocalizedAnnouncementServerToSingleClient::Serialize(RakNet::BitStream& bitStream) const { + BitStreamUtils::WriteNameValueText(bitStream, bodyParams); + bitStream.Write(bForceOpenChatBox); + bitStream.Write(bShowAnnouncement); + bitStream.Write(bShowInChat); + BitStreamUtils::WriteLengthPrefixed(bitStream, body); + BitStreamUtils::WriteLengthPrefixed(bitStream, title); + BitStreamUtils::WriteNameValueText(bitStream, titleParams); + } + + bool LocalizedAnnouncementServerToSingleClient::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(BitStreamUtils::ReadNameValueText(bitStream, bodyParams)); + VALIDATE_READ(bitStream.Read(bForceOpenChatBox)); + VALIDATE_READ(bitStream.Read(bShowAnnouncement)); + VALIDATE_READ(bitStream.Read(bShowInChat)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, body)); + VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, title)); + VALIDATE_READ(BitStreamUtils::ReadNameValueText(bitStream, titleParams)); + return true; + } +} diff --git a/dGame/dGameMessages/ZoneMessages.h b/dGame/dGameMessages/ZoneMessages.h new file mode 100644 index 000000000..0597e1ff7 --- /dev/null +++ b/dGame/dGameMessages/ZoneMessages.h @@ -0,0 +1,112 @@ +#ifndef ZONEMESSAGES_H +#define ZONEMESSAGES_H + +#include "GameMessages.h" +#include "eObjectWorldState.h" + +#include + +// Game messages for a player's zone lifecycle: loading in, zone summaries, level ups, announcements. +// Fields are listed in wire order; names follow the client (legouniverse.exe 1.10.64) where known. +namespace GameMessages { + // Client -> server. The client finished loading the zone and its player. + struct PlayerLoaded : public NetGameMsg { + PlayerLoaded() : NetGameMsg(MessageType::Game::PLAYER_LOADED) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + LWOOBJID playerID{}; + }; + + // Client -> server. The client finished loading an object. Nothing to do. + struct ReadyForUpdates : public NetGameMsg { + ReadyForUpdates() : NetGameMsg(MessageType::Game::READY_FOR_UPDATES) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + LWOOBJID objectID{}; + }; + + // Server -> client, to one client. No payload. + struct PlayerReady : public NetGameMsg { + PlayerReady() : NetGameMsg(MessageType::Game::PLAYER_READY) {} + }; + + // Server -> client, to one client. No payload. + struct RestoreToPostLoadStats : public NetGameMsg { + RestoreToPostLoadStats() : NetGameMsg(MessageType::Game::RESTORE_TO_POST_LOAD_STATS) {} + }; + + // Server -> client, to one client. No payload. + struct ServerDoneLoadingAllObjects : public NetGameMsg { + ServerDoneLoadingAllObjects() : NetGameMsg(MessageType::Game::SERVER_DONE_LOADING_ALL_OBJECTS) {} + }; + + // Server -> client, to one client. + struct InvalidZoneTransferList : public NetGameMsg { + InvalidZoneTransferList() : NetGameMsg(MessageType::Game::INVALID_ZONE_TRANSFER_LIST) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + std::u16string customerFeedbackURL{}; + std::u16string invalidMapTransferList{}; + bool bCustomerFeedbackOnExit{}; + bool bCustomerFeedbackOnInvalidMapTransfer{}; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct DisplayZoneSummary : public NetGameMsg { + DisplayZoneSummary() : NetGameMsg(MessageType::Game::DISPLAY_ZONE_SUMMARY) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + bool isPropertyMap{ false }; + bool isZoneStart{ false }; + LWOOBJID sender{ LWOOBJID_EMPTY }; // optional + }; + + // Client -> server. + struct ZoneSummaryDismissed : public NetGameMsg { + ZoneSummaryDismissed() : NetGameMsg(MessageType::Game::ZONE_SUMMARY_DISMISSED) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + + LWOOBJID playerID{}; + }; + + // Client -> server. No payload. The client finished showing a level up. + struct NotifyServerLevelProcessingComplete : public NetGameMsg { + NotifyServerLevelProcessingComplete() : NetGameMsg(MessageType::Game::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE) {} + void Handle(Entity& entity, const SystemAddress& sysAddr) override; + }; + + // Server -> client, to one client (UNASSIGNED broadcasts). + struct ChangeObjectWorldState : public NetGameMsg { + ChangeObjectWorldState() : NetGameMsg(MessageType::Game::CHANGE_OBJECT_WORLD_STATE) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + eObjectWorldState newState{}; + }; + + // Server -> client, to one client. The client looks both strings up in its locale (falling back to the text + // itself) and shows the announcement popup. Client Deserialize: 0x00f23c50. + struct LocalizedAnnouncementServerToSingleClient : public NetGameMsg { + LocalizedAnnouncementServerToSingleClient() : NetGameMsg(MessageType::Game::LOCALIZED_ANNOUNCEMENT_SERVER_TO_SINGLE_CLIENT) {} + void Serialize(RakNet::BitStream& bitStream) const override; + bool Deserialize(RakNet::BitStream& bitStream) override; + + // Name-value (LDF) text: u32 character count, then that many characters plus a null terminator when not empty. + std::u16string bodyParams{}; + bool bForceOpenChatBox{ false }; + bool bShowAnnouncement{ true }; + bool bShowInChat{ true }; + std::u16string body{}; + std::u16string title{}; + std::u16string titleParams{}; // name-value (LDF) text, as bodyParams + }; +} + +#endif // ZONEMESSAGES_H diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 69c6593f6..8ac8a4adf 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -12,6 +12,7 @@ #include "Game.h" #include "GameMessages.h" #include "MissionMessages.h" +#include "PlayerMessages.h" #include "Mail.h" #include "MissionComponent.h" #include "eRacingTaskParam.h" @@ -483,7 +484,11 @@ void Mission::YieldRewards() { } else { const auto uscore = LiveEvents::ScaleUScore(info.LegoScore); // a live event's U-score bonus, if one is running here characterComponent->SetUScore(characterComponent->GetUScore() + uscore, static_cast(lootSource)); - GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootSource); + GameMessages::ModifyLEGOScore modifyScore; + modifyScore.target = entity->GetObjectID(); + modifyScore.score = uscore; + modifyScore.sourceType = lootSource; + modifyScore.SendToClient(entity->GetSystemAddress()); } } @@ -493,7 +498,10 @@ void Mission::YieldRewards() { auto* const character = entity->GetComponent(); if (character) { character->SetReputation(character->GetReputation() + info.reward_reputation); - GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress()); + GameMessages::UpdateReputation updateReputation; + updateReputation.target = entity->GetObjectID(); + updateReputation.reputation = character->GetReputation(); + updateReputation.SendToClient(entity->GetSystemAddress()); } } diff --git a/dGame/dPropertyBehaviors/PropertyBehavior.cpp b/dGame/dPropertyBehaviors/PropertyBehavior.cpp index c19c4d2fe..8153c2f06 100644 --- a/dGame/dPropertyBehaviors/PropertyBehavior.cpp +++ b/dGame/dPropertyBehaviors/PropertyBehavior.cpp @@ -8,6 +8,7 @@ #include "StringifiedEnum.h" #include +#include "ObjectMessages.h" PropertyBehavior::PropertyBehavior(bool _isTemplated) { m_LastEditedState = BehaviorState::HOME_STATE; diff --git a/dGame/dPropertyBehaviors/State.cpp b/dGame/dPropertyBehaviors/State.cpp index 82d7ae0ba..acb6fa3d5 100644 --- a/dGame/dPropertyBehaviors/State.cpp +++ b/dGame/dPropertyBehaviors/State.cpp @@ -3,6 +3,7 @@ #include "Amf3.h" #include "ControlBehaviorMsgs.h" #include "tinyxml2.h" +#include "ObjectMessages.h" template <> void State::HandleMsg(AddStripMessage& msg) { diff --git a/dGame/dPropertyBehaviors/Strip.cpp b/dGame/dPropertyBehaviors/Strip.cpp index da1958b02..8d94c6c5e 100644 --- a/dGame/dPropertyBehaviors/Strip.cpp +++ b/dGame/dPropertyBehaviors/Strip.cpp @@ -16,6 +16,9 @@ #include "DluAssert.h" #include "Loot.h" #include "PropertyBehaviorActions.h" +#include "ObjectMessages.h" +#include "InventoryMessages.h" +#include "PropertyMessages.h" template <> void Strip::HandleMsg(AddStripMessage& msg) { diff --git a/dGame/dUtilities/DashboardActions.cpp b/dGame/dUtilities/DashboardActions.cpp index 27f9e29b7..408c407e3 100644 --- a/dGame/dUtilities/DashboardActions.cpp +++ b/dGame/dUtilities/DashboardActions.cpp @@ -12,6 +12,8 @@ #include "ChatPackets.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "PlayerMessages.h" #include "PlayerManager.h" #include "User.h" #include "UserManager.h" @@ -66,7 +68,10 @@ namespace { response.previousLevel = entity->GetGMLevel(); response.newLevel = info->maxGmLevel; response.Send(entity->GetSystemAddress()); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), info->maxGmLevel); + GameMessages::UpdateChatMode chatMode; + chatMode.target = entity->GetObjectID(); + chatMode.level = info->maxGmLevel; + chatMode.Send(UNASSIGNED_SYSTEM_ADDRESS); entity->SetGMLevel(info->maxGmLevel); if (info->maxGmLevel == eGameMasterLevel::CIVILIAN) { GameMessages::ToggleGMInvisEvent msg; @@ -115,7 +120,7 @@ namespace { auto* target = PlayerManager::GetPlayer(targetId); if (!entity || !target || entity == target) return 0; const auto position = target->GetPosition(); - GameMessages::SendTeleport(entity->GetObjectID(), position, entity->GetRotation(), entity->GetSystemAddress()); + GameMessages::Teleport(entity->GetObjectID(), position, entity->GetRotation()).SendToClient(entity->GetSystemAddress()); ChatPackets::SendSystemMessage(entity->GetSystemAddress(), u"A moderator moved you to " + GeneralUtils::ASCIIToUTF16(target->GetCharacter() ? target->GetCharacter()->GetName() : "another player") + u"."); LOG("Dashboard teleport of %llu to %llu", characterId, targetId); return 1; diff --git a/dGame/dUtilities/Loot.cpp b/dGame/dUtilities/Loot.cpp index 08c8436ff..b9a421b84 100644 --- a/dGame/dUtilities/Loot.cpp +++ b/dGame/dUtilities/Loot.cpp @@ -25,6 +25,7 @@ #include "ObjectIDManager.h" #include "CDActivitiesTable.h" #include "ScriptedActivityComponent.h" +#include "InventoryMessages.h" namespace { std::unordered_set CachedMatrices; diff --git a/dGame/dUtilities/Preconditions.cpp b/dGame/dUtilities/Preconditions.cpp index 26f1f7bd8..d050f8aac 100644 --- a/dGame/dUtilities/Preconditions.cpp +++ b/dGame/dUtilities/Preconditions.cpp @@ -12,6 +12,7 @@ #include "LevelProgressionComponent.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "eMissionState.h" #include "PetComponent.h" @@ -292,7 +293,11 @@ bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const { const auto a = Preconditions::Check(player, condition, evaluateCosts); if (!a) { - GameMessages::SendNotifyClientFailedPrecondition(player->GetObjectID(), player->GetSystemAddress(), u"", condition); + GameMessages::NotifyClientFailedPrecondition failedPrecondition; + failedPrecondition.target = player->GetObjectID(); + failedPrecondition.failedReason = u""; + failedPrecondition.preconditionID = condition; + failedPrecondition.Send(player->GetSystemAddress()); } const auto b = next == nullptr ? true : next->Check(player, evaluateCosts); diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp index 5a1b67049..1416a8b8e 100644 --- a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -58,6 +58,9 @@ #include "StringifiedEnum.h" #include "BinaryPathFinder.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "PlayerMessages.h" +#include "ObjectMessages.h" namespace DEVGMCommands { void SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -88,7 +91,10 @@ namespace DEVGMCommands { response.previousLevel = entity->GetGMLevel(); response.newLevel = level; response.Send(entity->GetSystemAddress()); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), level); + GameMessages::UpdateChatMode chatMode; + chatMode.target = entity->GetObjectID(); + chatMode.level = level; + chatMode.Send(UNASSIGNED_SYSTEM_ADDRESS); entity->SetGMLevel(level); LOG("User %s (%i) has changed their GM level to %i for charID %llu", user->GetUsername().c_str(), user->GetAccountID(), level, entity->GetObjectID()); } @@ -101,7 +107,10 @@ namespace DEVGMCommands { response.previousLevel = entity->GetGMLevel(); response.newLevel = eGameMasterLevel::CIVILIAN; response.Send(entity->GetSystemAddress()); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN); + GameMessages::UpdateChatMode chatMode; + chatMode.target = entity->GetObjectID(); + chatMode.level = eGameMasterLevel::CIVILIAN; + chatMode.Send(UNASSIGNED_SYSTEM_ADDRESS); entity->SetGMLevel(eGameMasterLevel::CIVILIAN); GameMessages::ToggleGMInvisEvent msg; @@ -299,7 +308,10 @@ namespace DEVGMCommands { const auto state = !entity->GetVar(u"freecam"); entity->SetVar(u"freecam", state); - GameMessages::SendSetPlayerControlScheme(entity, static_cast(state ? 9 : 1)); + GameMessages::SetPlayerControlScheme controlScheme; + controlScheme.target = entity->GetObjectID(); + controlScheme.iScheme = static_cast(state ? 9 : 1); + controlScheme.SendToClient(entity->GetSystemAddress()); ChatPackets::SendSystemMessage(sysAddr, u"Toggled freecam."); } @@ -315,7 +327,10 @@ namespace DEVGMCommands { return; } - GameMessages::SendSetPlayerControlScheme(entity, static_cast(scheme.value())); + GameMessages::SetPlayerControlScheme controlScheme; + controlScheme.target = entity->GetObjectID(); + controlScheme.iScheme = static_cast(scheme.value()); + controlScheme.SendToClient(entity->GetSystemAddress()); ChatPackets::SendSystemMessage(sysAddr, u"Switched control scheme."); } @@ -674,7 +689,7 @@ namespace DEVGMCommands { } else { ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport () - if no Y given, will teleport to the height of the terrain (or any physics object)."); } - GameMessages::SendTeleport(sourceEntity->GetObjectID(), pos, sourceEntity->GetRotation(), sourceEntity->GetSystemAddress()); + GameMessages::Teleport(sourceEntity->GetObjectID(), pos, sourceEntity->GetRotation()).SendToClient(sourceEntity->GetSystemAddress()); auto* possessorComponent = sourceEntity->GetComponent(); if (possessorComponent) { @@ -685,7 +700,7 @@ namespace DEVGMCommands { if (havokVehiclePhysicsComponent) { havokVehiclePhysicsComponent->SetPosition(pos); Game::entityManager->SerializeEntity(possassableEntity); - } else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, QuatUtils::IDENTITY, sysAddr); + } else GameMessages::Teleport(possassableEntity->GetObjectID(), pos, QuatUtils::IDENTITY).SendToClient(sysAddr); } } } @@ -705,7 +720,7 @@ namespace DEVGMCommands { skipped++; continue; } - GameMessages::SendTeleport(character->GetObjectID(), pos, QuatUtils::IDENTITY, character->GetSystemAddress()); + GameMessages::Teleport(character->GetObjectID(), pos, QuatUtils::IDENTITY).SendToClient(character->GetSystemAddress()); } if (skipped > 0) { ChatPackets::SendSystemMessage(sysAddr, u"/tpall: left " + GeneralUtils::to_u16string(skipped) + @@ -934,7 +949,11 @@ namespace DEVGMCommands { lootType = type.value_or(lootType); } - GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); + GameMessages::ModifyLEGOScore modifyScore; + modifyScore.target = entity->GetObjectID(); + modifyScore.score = uscore; + modifyScore.sourceType = lootType; + modifyScore.SendToClient(entity->GetSystemAddress()); } void SetLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { diff --git a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp index e2d47184c..bb35b3563 100644 --- a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp @@ -22,6 +22,9 @@ #include "eServerDisconnectIdentifiers.h" #include "eObjectBits.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" +#include "PlayerMessages.h" namespace GMGreaterThanZeroCommands { @@ -199,7 +202,10 @@ namespace GMGreaterThanZeroCommands { bool isFlying = character->GetIsFlying(); if (isFlying) { - GameMessages::SendSetJetPackMode(entity, false); + GameMessages::SetJetPackMode jetPackMode; + jetPackMode.target = entity->GetObjectID(); + jetPackMode.bUse = false; + jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); character->SetIsFlying(false); } else { @@ -219,7 +225,16 @@ namespace GMGreaterThanZeroCommands { float maxAirSpeed = 30 * speedScale; float verticalVelocity = 1.5 * speedScale; - GameMessages::SendSetJetPackMode(entity, true, true, false, 167, airSpeed, maxAirSpeed, verticalVelocity); + GameMessages::SetJetPackMode jetPackMode; + jetPackMode.target = entity->GetObjectID(); + jetPackMode.bUse = true; + jetPackMode.bBypassChecks = true; + jetPackMode.bDoHover = false; + jetPackMode.effectID = 167; + jetPackMode.fAirspeed = airSpeed; + jetPackMode.fMaxAirspeed = maxAirSpeed; + jetPackMode.fVertVel = verticalVelocity; + jetPackMode.Send(UNASSIGNED_SYSTEM_ADDRESS); character->SetIsFlying(true); } @@ -264,12 +279,18 @@ namespace GMGreaterThanZeroCommands { } void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args) { - GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(args), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SetName setName; + setName.target = entity->GetObjectID(); + setName.name = GeneralUtils::UTF8ToUTF16(args); + setName.Send(UNASSIGNED_SYSTEM_ADDRESS); } void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args) { std::string name = entity->GetCharacter()->GetName() + " - " + args; - GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SetName setName; + setName.target = entity->GetObjectID(); + setName.name = GeneralUtils::UTF8ToUTF16(name); + setName.Send(UNASSIGNED_SYSTEM_ADDRESS); } void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args) { @@ -301,7 +322,12 @@ namespace GMGreaterThanZeroCommands { void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { if (args.empty()) { - GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, entity->GetObjectID()); + GameMessages::ForceCameraTargetCycle cameraCycle; + cameraCycle.target = entity->GetObjectID(); + cameraCycle.bForceCycling = false; + cameraCycle.cyclingMode = eCameraTargetCyclingMode::DISALLOW_CYCLING; + cameraCycle.optionalTargetID = entity->GetObjectID(); + cameraCycle.SendToClient(entity->GetSystemAddress()); return; } @@ -311,6 +337,11 @@ namespace GMGreaterThanZeroCommands { return; } GameMessages::SlashCommandTextFeedback(entity->GetObjectID(), u"Spectating Player").SendToClient(entity->GetSystemAddress()); - GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, player->GetObjectID()); + GameMessages::ForceCameraTargetCycle cameraCycle; + cameraCycle.target = entity->GetObjectID(); + cameraCycle.bForceCycling = false; + cameraCycle.cyclingMode = eCameraTargetCyclingMode::DISALLOW_CYCLING; + cameraCycle.optionalTargetID = player->GetObjectID(); + cameraCycle.SendToClient(entity->GetSystemAddress()); } } diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index 521e68da4..6cc32940f 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -3,6 +3,7 @@ #include "DestroyableComponent.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "InventoryComponent.h" #include "PhantomPhysicsComponent.h" #include "ProximityMonitorComponent.h" @@ -349,8 +350,7 @@ void NPCTalk(Entity* npc) { const auto& selected = chats[GeneralUtils::GenerateRandomNumber(0, static_cast(chats.size() - 1))]; - GameMessages::SendNotifyClientZoneObject( - npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientZoneObject(npc->GetObjectID(), u"sendToclient_bubble", 0, 0, npc->GetObjectID(), selected).Send(UNASSIGNED_SYSTEM_ADDRESS); Game::entityManager->SerializeEntity(npc); diff --git a/dGame/dUtilities/WorldMigration.cpp b/dGame/dUtilities/WorldMigration.cpp index 0bd19b828..b9c80af08 100644 --- a/dGame/dUtilities/WorldMigration.cpp +++ b/dGame/dUtilities/WorldMigration.cpp @@ -1,4 +1,5 @@ #include "WorldMigration.h" +#include "ZoneMessages.h" #include "MasterPackets.h" #include @@ -82,27 +83,14 @@ namespace { if (g_Active) SendStatus(g_Active->order.migrationId, g_Active->order.targetInstance, state, g_Active->moved, g_Active->failed, remaining, message); } - void WriteWString(RakNet::BitStream& bitStream, const std::u16string& text) { - bitStream.Write(text.size()); - for (const auto character : text) bitStream.Write(character); - } - // LocalizedAnnouncementServerToSingleClient: the client looks both strings up in its locale (falling back to // the text itself) and shows the announcement popup, like its own instance-lock warning did in live void SendLocalizedAnnouncement(Entity* player, const std::u16string& body, const std::u16string& title) { - const auto& sysAddr = player->GetSystemAddress(); - CBITSTREAM; - CMSGHEADER; - bitStream.Write(player->GetObjectID()); - bitStream.Write(MessageType::Game::LOCALIZED_ANNOUNCEMENT_SERVER_TO_SINGLE_CLIENT); - bitStream.Write(0); // body parameters (LDF), none - bitStream.Write(false); // force open chat box - bitStream.Write(true); // show the announcement - bitStream.Write(true); // and put the text in chat - WriteWString(bitStream, body); - WriteWString(bitStream, title); - bitStream.Write(0); // title parameters (LDF), none - SEND_PACKET; + GameMessages::LocalizedAnnouncementServerToSingleClient announcement; + announcement.target = player->GetObjectID(); + announcement.body = body; + announcement.title = title; + announcement.SendToClient(player->GetSystemAddress()); } uint16_t Remaining() { diff --git a/dNet/BitStreamUtils.h b/dNet/BitStreamUtils.h index a1e62b782..fa4afa219 100644 --- a/dNet/BitStreamUtils.h +++ b/dNet/BitStreamUtils.h @@ -75,6 +75,7 @@ struct LUBitStream { }; +#define BITSTREAMUTILS_HAS_WRITEHEADER namespace BitStreamUtils { template void WriteHeader(RakNet::BitStream& bitStream, ServiceType connectionType, T internalPacketID) { @@ -124,6 +125,20 @@ namespace BitStreamUtils { * Reads a string written by WriteLengthPrefixed. Fails (returns false) if the stream runs out of data or * if the length is negative or larger than maxLength characters. */ + /** + * Writes name-value (LDF) text the way the client reads it: a u32 character count, the characters, and a null + * terminator (not counted) when the text isn't empty. + */ + inline void WriteNameValueText(RakNet::BitStream& bitStream, const std::u16string& text) { + WriteLengthPrefixed(bitStream, text); + if (!text.empty()) bitStream.Write(0); + } + + /** + * Reads text written by WriteNameValueText (the null terminator is consumed and not kept). + */ + inline bool ReadNameValueText(RakNet::BitStream& bitStream, std::u16string& text, const uint32_t maxLength = 0x500000 /* MAX_MESSAGE_LENGTH */); + template bool ReadLengthPrefixed(RakNet::BitStream& bitStream, StringT& value, const uint32_t maxLength = 0x500000 /* MAX_MESSAGE_LENGTH */) { LenT length{}; @@ -136,6 +151,12 @@ namespace BitStreamUtils { if (length == 0) return true; return bitStream.ReadBits(reinterpret_cast(value.data()), BYTES_TO_BITS(value.size() * sizeof(typename StringT::value_type)), true); } + + inline bool ReadNameValueText(RakNet::BitStream& bitStream, std::u16string& text, const uint32_t maxLength) { + if (!ReadLengthPrefixed(bitStream, text, maxLength)) return false; + uint16_t terminator{}; + return text.empty() || bitStream.Read(terminator); + } } namespace RakNet { diff --git a/dNet/PacketUtils.cpp b/dNet/PacketUtils.cpp deleted file mode 100644 index 5394cff08..000000000 --- a/dNet/PacketUtils.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "PacketUtils.h" -#include -#include "Logger.h" -#include "Game.h" - -//! Saves a packet to the filesystem -void PacketUtils::SavePacket(const std::string& filename, const char* data, size_t length) { - //If we don't log to the console, don't save the bin files either. This takes up a lot of time. - if (!Game::logger->GetLogToConsole()) return; - - std::string path = "packets/" + filename; - - std::ofstream file(path, std::ios::binary); - if (!file.is_open()) return; - - file.write(data, length); - file.close(); -} diff --git a/dNet/PacketUtils.h b/dNet/PacketUtils.h deleted file mode 100644 index cf96bfc04..000000000 --- a/dNet/PacketUtils.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef PACKETUTILS_H -#define PACKETUTILS_H - -#include "MessageIdentifiers.h" -#include "BitStream.h" -#include - -enum class ServiceType : uint16_t; - -namespace PacketUtils { - void SavePacket(const std::string& filename, const char* data, size_t length); -}; - -#endif // PACKETUTILS_H diff --git a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp index 188098e80..879ae3c48 100644 --- a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp +++ b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp @@ -13,6 +13,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "SkillComponent.h" #include "eReplicaComponentType.h" #include "RenderComponent.h" @@ -88,7 +89,7 @@ void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) { // There is suppose to be a 0.1 second delay here but that may be admitted? auto* controller = Game::entityManager->GetZoneControlEntity(); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 10, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"SetColGroup", 10, 0, 0, "").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetPosition({ 10000, 0, 10000 }); @@ -108,7 +109,7 @@ void BossSpiderQueenEnemyServer::WithdrawSpider(Entity* self, const bool withdra if (withdraw) { //Move spider away from battle zone // Disabled because we cant option the reset collition group right now - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 10, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"SetColGroup", 10, 0, 0, "").Send(UNASSIGNED_SYSTEM_ADDRESS); //First rotate for anim NiQuaternion rot = QuatUtils::IDENTITY; @@ -536,7 +537,7 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim embeddedEffect.Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "AdvanceComplete") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 11, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"SetColGroup", 11, 0, 0, "").Send(UNASSIGNED_SYSTEM_ADDRESS); //Wind up, telegraphing next round float animTime = PlayAnimAndReturnTime(self, spiderJeerAnim); diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp index eb384ec27..58fd7832b 100644 --- a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "SkillComponent.h" #include "BaseCombatAIComponent.h" #include "EntityInfo.h" @@ -145,7 +146,7 @@ void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { 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); + GameMessages::NotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp index 88eb57a9c..c09f21336 100644 --- a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -7,6 +7,7 @@ #include "EntityInfo.h" #include "RenderComponent.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" void FvMaelstromDragon::OnStartup(Entity* self) { self->SetVar(u"weakspot", 0); @@ -164,7 +165,7 @@ void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) { idleFlags.Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"weakspot", -1); - GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive").Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp b/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp index dd51f5b46..07703cb7d 100644 --- a/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp +++ b/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp @@ -1,6 +1,7 @@ #include "AgCagedBricksServer.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Character.h" #include "EntityManager.h" #include "eReplicaComponentType.h" @@ -10,7 +11,7 @@ void AgCagedBricksServer::OnUse(Entity* self, Entity* user) { //Tell the client to spawn the baby spiderling: auto spooders = Game::entityManager->GetEntitiesInGroup("cagedSpider"); for (auto spodder : spooders) { - GameMessages::SendFireEventClientSide(spodder->GetObjectID(), user->GetSystemAddress(), u"toggle", LWOOBJID_EMPTY, 0, 0, user->GetObjectID()); + GameMessages::FireEventClientSide(spodder->GetObjectID(), u"toggle", LWOOBJID_EMPTY, user->GetObjectID()).SendToClient(user->GetSystemAddress()); } //Set the flag & mission status: diff --git a/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp index cd30b58fb..dd9b27a99 100644 --- a/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp +++ b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp @@ -3,6 +3,7 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "ActivityMessages.h" +#include "ObjectMessages.h" #include "LeaderboardManager.h" #include "dServer.h" #include "eMissionTaskType.h" @@ -21,9 +22,9 @@ void NpcAgCourseStarter::OnUse(Entity* self, Entity* user) { const auto& userSysAddr = user->GetSystemAddress(); if (scriptedActivityComponent->PlayerHasActivityData(userId)) { - GameMessages::SendNotifyClientObject(selfId, u"exit", 0, 0, LWOOBJID_EMPTY, "", userSysAddr); + GameMessages::NotifyClientObject(selfId, u"exit", 0, 0, LWOOBJID_EMPTY, "").Send(userSysAddr); } else { - GameMessages::SendNotifyClientObject(selfId, u"start", 0, 0, LWOOBJID_EMPTY, "", userSysAddr); + GameMessages::NotifyClientObject(selfId, u"start", 0, 0, LWOOBJID_EMPTY, "").Send(userSysAddr); } } @@ -36,14 +37,14 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 const auto& senderSysAddr = sender->GetSystemAddress(); if (identifier == u"player_dialog_cancel_course" && button == 1) { - GameMessages::SendNotifyClientObject(selfId, u"stop_timer", 0, 0, LWOOBJID_EMPTY, "", senderSysAddr); - GameMessages::SendNotifyClientObject(selfId, u"cancel_timer", 0, 0, LWOOBJID_EMPTY, "", senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"stop_timer", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"cancel_timer", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); scriptedActivityComponent->RemoveActivityPlayerData(senderId); Game::entityManager->SerializeEntity(self); } else if (identifier == u"player_dialog_start_course" && button == 1) { - GameMessages::SendNotifyClientObject(selfId, u"start_timer", 0, 0, LWOOBJID_EMPTY, "", senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"start_timer", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); GameMessages::ActivityStart activityStart; activityStart.target = selfId; activityStart.Send(senderSysAddr); @@ -57,12 +58,12 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 Game::entityManager->SerializeEntity(self); } else if (identifier == u"FootRaceCancel") { - GameMessages::SendNotifyClientObject(selfId, u"stop_timer", 0, 0, LWOOBJID_EMPTY, "", senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"stop_timer", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); if (scriptedActivityComponent->PlayerHasActivityData(senderId)) { - GameMessages::SendNotifyClientObject(selfId, u"exit", 0, 0, LWOOBJID_EMPTY, "", senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"exit", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); } else { - GameMessages::SendNotifyClientObject(selfId, u"start", 0, 0, LWOOBJID_EMPTY, "", senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"start", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); } scriptedActivityComponent->RemoveActivityPlayerData(senderId); @@ -80,8 +81,7 @@ void NpcAgCourseStarter::OnFireEventServerSide(Entity* self, Entity* sender, std if (!scriptedActivityComponent->PlayerHasActivityData(senderId)) return; if (args == "course_cancel") { - GameMessages::SendNotifyClientObject(selfId, u"cancel_timer", 0, 0, - LWOOBJID_EMPTY, "", senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"cancel_timer", 0, 0, LWOOBJID_EMPTY, "").Send(senderSysAddr); scriptedActivityComponent->RemoveActivityPlayerData(senderId); } else if (args == "course_finish") { const auto raceEndTime = Game::server->GetUptime(); @@ -102,11 +102,8 @@ void NpcAgCourseStarter::OnFireEventServerSide(Entity* self, Entity* sender, std Game::entityManager->SerializeEntity(self); LeaderboardManager::SaveScore(senderId, scriptedActivityComponent->GetActivityID(), raceTimeElapsed); - GameMessages::SendNotifyClientObject(selfId, u"ToggleLeaderBoard", - scriptedActivityComponent->GetActivityID(), 0, senderId, - "", senderSysAddr); - GameMessages::SendNotifyClientObject(selfId, u"stop_timer", 1, raceTimeElapsed, LWOOBJID_EMPTY, "", - senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"ToggleLeaderBoard", scriptedActivityComponent->GetActivityID(), 0, senderId, "").Send(senderSysAddr); + GameMessages::NotifyClientObject(selfId, u"stop_timer", 1, raceTimeElapsed, LWOOBJID_EMPTY, "").Send(senderSysAddr); scriptedActivityComponent->RemoveActivityPlayerData(senderId); } diff --git a/dScripts/02_server/Map/AG/NpcCowboyServer.cpp b/dScripts/02_server/Map/AG/NpcCowboyServer.cpp index 219110b76..32d0104c2 100644 --- a/dScripts/02_server/Map/AG/NpcCowboyServer.cpp +++ b/dScripts/02_server/Map/AG/NpcCowboyServer.cpp @@ -2,6 +2,7 @@ #include "eMissionState.h" #include "InventoryComponent.h" #include "dZoneManager.h" +#include "ObjectMessages.h" void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != 1880) { @@ -34,7 +35,6 @@ void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int miss auto spawners = Game::zoneManager->GetSpawnersByName("PlungerGunTargets"); for (auto* spawner : spawners) { for (const auto entity : spawner->GetSpawnedObjectIDs()) - GameMessages::SendNotifyClientObject(entity, u"SetVisibility", visible, 0, - target->GetObjectID(), "", target->GetSystemAddress()); + GameMessages::NotifyClientObject(entity, u"SetVisibility", visible, 0, target->GetObjectID(), "").Send(target->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp b/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp index 8ee2e9889..54a3952ba 100644 --- a/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp +++ b/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp @@ -1,5 +1,6 @@ #include "NpcNjAssistantServer.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "InventoryComponent.h" #include "MissionComponent.h" #include "Item.h" @@ -10,7 +11,7 @@ void NpcNjAssistantServer::OnMissionDialogueOK(Entity* self, Entity* target, int if (missionID != mailMission) return; if (missionState == eMissionState::COMPLETE || missionState == eMissionState::READY_TO_COMPLETE) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"switch", 0, 0, LWOOBJID_EMPTY, "", target->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"switch", 0, 0, LWOOBJID_EMPTY, "").Send(target->GetSystemAddress()); auto* inv = static_cast(target->GetComponent(eReplicaComponentType::INVENTORY)); diff --git a/dScripts/02_server/Map/AG/NpcWispServer.cpp b/dScripts/02_server/Map/AG/NpcWispServer.cpp index 0a6c9fda9..0e62a8ea9 100644 --- a/dScripts/02_server/Map/AG/NpcWispServer.cpp +++ b/dScripts/02_server/Map/AG/NpcWispServer.cpp @@ -3,6 +3,7 @@ #include "dZoneManager.h" #include "Entity.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "eMissionState.h" #include "Spawner.h" @@ -39,8 +40,7 @@ void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missio auto spawners = Game::zoneManager->GetSpawnersByName(group); for (const auto* spawner : spawners) { for (const auto objId : spawner->GetSpawnedObjectIDs()) - GameMessages::SendNotifyClientObject(objId, u"SetVisibility", visible, 0, - target->GetObjectID(), "", target->GetSystemAddress()); + GameMessages::NotifyClientObject(objId, u"SetVisibility", visible, 0, target->GetObjectID(), "").Send(target->GetSystemAddress()); } } } diff --git a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp index 2b367ed2b..a0f0a0e4e 100644 --- a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp +++ b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp @@ -1,5 +1,6 @@ #include "ZoneAgSpiderQueen.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "ZoneAgProperty.h" #include "DestroyableComponent.h" @@ -36,16 +37,14 @@ void ZoneAgSpiderQueen::BasePlayerLoaded(Entity* self, Entity* player) { } self->SetNetworkVar(u"unclaimed", true); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, - "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, "").Send(player->GetSystemAddress()); } void ZoneAgSpiderQueen::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == "ClearProperty") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, - LWOOBJID_EMPTY, destroyedCinematic, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, destroyedCinematic).Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("tornadoOff", 0.5f); } else { ZoneAgProperty::BaseOnFireEventServerSide(self, sender, args); diff --git a/dScripts/02_server/Map/AM/AmDrawBridge.cpp b/dScripts/02_server/Map/AM/AmDrawBridge.cpp index c356145b1..0d1039c38 100644 --- a/dScripts/02_server/Map/AM/AmDrawBridge.cpp +++ b/dScripts/02_server/Map/AM/AmDrawBridge.cpp @@ -1,6 +1,7 @@ #include "AmDrawBridge.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "SimplePhysicsComponent.h" #include "eTerminateType.h" @@ -26,7 +27,7 @@ void AmDrawBridge::OnUse(Entity* self, Entity* user) { auto* player = user; - GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } void AmDrawBridge::OnTimerDone(Entity* self, std::string timerName) { diff --git a/dScripts/02_server/Map/AM/AmTeapotServer.cpp b/dScripts/02_server/Map/AM/AmTeapotServer.cpp index 66c935ce8..7b68220c1 100644 --- a/dScripts/02_server/Map/AM/AmTeapotServer.cpp +++ b/dScripts/02_server/Map/AM/AmTeapotServer.cpp @@ -1,6 +1,7 @@ #include "AmTeapotServer.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Item.h" #include "eTerminateType.h" @@ -14,5 +15,5 @@ void AmTeapotServer::OnUse(Entity* self, Entity* user) { inventoryComponent->AddItem(WU_S_IMAGINATION_TEA, 1); } - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp index 8c35de312..01029c784 100644 --- a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp +++ b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "MissionComponent.h" #include "eMissionState.h" #include "InventoryComponent.h" @@ -89,7 +90,7 @@ void ImgBrickConsoleQB::OnUse(Entity* self, Entity* user) { self->SetNetworkVar(u"used", true); - GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp index 73f5ba3d4..a8ca6b646 100644 --- a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp +++ b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp @@ -2,6 +2,8 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "RenderComponent.h" @@ -39,7 +41,7 @@ void GfCaptainsCannon::OnUse(Entity* self, Entity* user) { auto rotation = self->GetRotation(); - GameMessages::SendTeleport(user->GetObjectID(), position, rotation, user->GetSystemAddress()); + GameMessages::Teleport(user->GetObjectID(), position, rotation).SendToClient(user->GetSystemAddress()); RenderComponent::PlayAnimation(user, u"cannon-strike-no-equip"); @@ -107,6 +109,6 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { missionComponent->ForceProgress(601, 910, 1); } - GameMessages::SendTerminateInteraction(playerId, eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(playerId, eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/02_server/Map/GF/GfTikiTorch.cpp b/dScripts/02_server/Map/GF/GfTikiTorch.cpp index da55a77fd..a33f451bf 100644 --- a/dScripts/02_server/Map/GF/GfTikiTorch.cpp +++ b/dScripts/02_server/Map/GF/GfTikiTorch.cpp @@ -1,5 +1,6 @@ #include "GfTikiTorch.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "RenderComponent.h" @@ -8,6 +9,7 @@ #include "RenderComponent.h" #include "eTerminateType.h" #include "Loot.h" +#include "InventoryMessages.h" void GfTikiTorch::OnStartup(Entity* self) { LightTorch(self); @@ -43,7 +45,7 @@ void GfTikiTorch::OnTimerDone(Entity* self, std::string timerName) { Entity* player = Game::entityManager->GetEntity(self->GetI64(u"userID")); if (player != nullptr && player->GetCharacter()) { - GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } self->SetBoolean(u"isInUse", false); diff --git a/dScripts/02_server/Map/GF/MastTeleport.cpp b/dScripts/02_server/Map/GF/MastTeleport.cpp index 34f97e1fa..25b7824c3 100644 --- a/dScripts/02_server/Map/GF/MastTeleport.cpp +++ b/dScripts/02_server/Map/GF/MastTeleport.cpp @@ -3,6 +3,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "MovementMessages.h" #include "Preconditions.h" #include "eEndBehavior.h" #include "DestroyableComponent.h" @@ -51,9 +52,9 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { auto position = self->GetPosition(); auto rotation = self->GetRotation(); - GameMessages::SendTeleport(playerId, position, rotation, player->GetSystemAddress(), true); + GameMessages::Teleport(playerId, position, rotation, true).SendToClient(player->GetSystemAddress()); - GameMessages::SendTeleport(playerId, position, rotation, player->GetSystemAddress(), true); + GameMessages::Teleport(playerId, position, rotation, true).SendToClient(player->GetSystemAddress()); const auto cinematic = GeneralUtils::UTF16ToWTF8(self->GetVar(u"Cinematic")); const auto leanIn = self->GetVar(u"LeanIn"); @@ -97,9 +98,13 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { position.y += 12; position.z += (forward.z * 20.5f); - GameMessages::SendOrientToAngle(playerId, true, rads, player->GetSystemAddress()); + GameMessages::OrientToAngle orientToAngle; + orientToAngle.target = playerId; + orientToAngle.bRelativeToCurrent = true; + orientToAngle.fAngle = rads; + orientToAngle.Send(player->GetSystemAddress()); - GameMessages::SendTeleport(playerId, position, QuatUtils::IDENTITY, player->GetSystemAddress()); + GameMessages::Teleport(playerId, position, QuatUtils::IDENTITY).SendToClient(player->GetSystemAddress()); GameMessages::SetStunned stun; stun.target = playerId; diff --git a/dScripts/02_server/Map/General/BankInteractServer.cpp b/dScripts/02_server/Map/General/BankInteractServer.cpp index e87185752..8567c7c2f 100644 --- a/dScripts/02_server/Map/General/BankInteractServer.cpp +++ b/dScripts/02_server/Map/General/BankInteractServer.cpp @@ -1,6 +1,7 @@ #include "BankInteractServer.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "Entity.h" #include "Amf3.h" @@ -29,6 +30,6 @@ void BankInteractServer::OnFireEventServerSide(Entity* self, Entity* sender, std uiMessage.args = std::move(args); uiMessage.SendToClient(sender->GetSystemAddress()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "").Send(sender->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/General/Binoculars.cpp b/dScripts/02_server/Map/General/Binoculars.cpp index 786c0faf6..b96a255d2 100644 --- a/dScripts/02_server/Map/General/Binoculars.cpp +++ b/dScripts/02_server/Map/General/Binoculars.cpp @@ -1,6 +1,7 @@ #include "Binoculars.h" #include "Character.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Game.h" #include "dServer.h" @@ -15,6 +16,6 @@ void Binoculars::OnUse(Entity* self, Entity* user) { if (!flagMsg.flag) { auto* const character = user->GetCharacter(); if (character) character->SetPlayerFlag(flag, true); - GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY); + GameMessages::FireEventClientSide(self->GetObjectID(), u"achieve", LWOOBJID_EMPTY, LWOOBJID_EMPTY).SendToClient(user->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp index 8b3da9fa7..4fa238983 100644 --- a/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp +++ b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp @@ -1,5 +1,6 @@ #include "ImaginationBackpackHealServer.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "MissionComponent.h" #include "eMissionTaskType.h" #include "eMissionState.h" @@ -15,8 +16,7 @@ void ImaginationBackpackHealServer::OnSkillEventFired(Entity* self, Entity* cast auto* missionComponent = caster->GetComponent(); if (missionComponent != nullptr && missionComponent->GetMissionState(healMission) == eMissionState::ACTIVE) { missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ClearMaelstrom", 0, 0, - caster->GetObjectID(), "", caster->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"ClearMaelstrom", 0, 0, caster->GetObjectID(), "").Send(caster->GetSystemAddress()); } } } diff --git a/dScripts/02_server/Map/General/PropertyPlatform.cpp b/dScripts/02_server/Map/General/PropertyPlatform.cpp index 4ea78314a..ac27bb46c 100644 --- a/dScripts/02_server/Map/General/PropertyPlatform.cpp +++ b/dScripts/02_server/Map/General/PropertyPlatform.cpp @@ -1,6 +1,7 @@ #include "PropertyPlatform.h" #include "QuickBuildComponent.h" #include "GameMessages.h" +#include "MovementMessages.h" #include "MovingPlatformComponent.h" void PropertyPlatform::OnQuickBuildComplete(Entity* self, Entity* target) { @@ -9,8 +10,7 @@ void PropertyPlatform::OnQuickBuildComplete(Entity* self, Entity* target) { // movingPlatform->StopPathing(); // movingPlatform->SetNoAutoStart(true); // } - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, eMovementPlatformState::Stationary); + GameMessages::PlatformResync(*self, true, 0, 0, 0, eMovementPlatformState::Stationary).Send(UNASSIGNED_SYSTEM_ADDRESS); } void PropertyPlatform::OnUse(Entity* self, Entity* user) { @@ -20,8 +20,7 @@ void PropertyPlatform::OnUse(Entity* self, Entity* user) { // if (movingPlatform != nullptr) { // movingPlatform->GotoWaypoint(1); // } - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, eMovementPlatformState::Moving); + GameMessages::PlatformResync(*self, true, 0, 1, 1, eMovementPlatformState::Moving).Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() { self->SetNetworkVar(u"startEffect", dieDelay); diff --git a/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp index 05aadf8f8..6a449fa19 100644 --- a/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp +++ b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "dServer.h" #include "Amf3.h" #include "Entity.h" @@ -54,7 +55,7 @@ void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { if (!flagMsg.flag) { auto* const character = user->GetCharacter(); if (character) character->SetPlayerFlag(boxFlag, true); - GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY); + GameMessages::FireEventClientSide(self->GetObjectID(), u"achieve", LWOOBJID_EMPTY, LWOOBJID_EMPTY).SendToClient(user->GetSystemAddress()); } } } diff --git a/dScripts/02_server/Map/General/TokenConsoleServer.cpp b/dScripts/02_server/Map/General/TokenConsoleServer.cpp index d8d5ba177..463cc0799 100644 --- a/dScripts/02_server/Map/General/TokenConsoleServer.cpp +++ b/dScripts/02_server/Map/General/TokenConsoleServer.cpp @@ -2,6 +2,7 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "Character.h" #include "eReplicaComponentType.h" #include "eTerminateType.h" @@ -38,5 +39,5 @@ void TokenConsoleServer::OnUse(Entity* self, Entity* user) { inv->AddItem(tokenLOT, tokensToGive, eLootSourceType::NONE); } - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Map/General/VisToggleNotifierServer.cpp b/dScripts/02_server/Map/General/VisToggleNotifierServer.cpp index 16d805eb7..3077412c9 100644 --- a/dScripts/02_server/Map/General/VisToggleNotifierServer.cpp +++ b/dScripts/02_server/Map/General/VisToggleNotifierServer.cpp @@ -2,6 +2,7 @@ #include "eMissionState.h" #include "Game.h" #include "dZoneManager.h" +#include "ObjectMessages.h" void VisToggleNotifierServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionId, eMissionState missionState) { auto itr = m_GameVariables.find(missionId); @@ -16,7 +17,7 @@ void VisToggleNotifierServer::OnMissionDialogueOK(Entity* self, Entity* target, for (const auto spawner : spawners) { const auto& spawnedObjIds = spawner->GetSpawnedObjectIDs(); for (const auto& objId : spawnedObjIds) { - GameMessages::SendNotifyClientObject(objId, u"SetVisibility", visible); + GameMessages::NotifyClientObject(objId, u"SetVisibility", visible).Send(UNASSIGNED_SYSTEM_ADDRESS); } } } diff --git a/dScripts/02_server/Map/General/WishingWellServer.cpp b/dScripts/02_server/Map/General/WishingWellServer.cpp index 2efa6ee21..38ba17be6 100644 --- a/dScripts/02_server/Map/General/WishingWellServer.cpp +++ b/dScripts/02_server/Map/General/WishingWellServer.cpp @@ -2,6 +2,7 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "Loot.h" #include "EntityManager.h" #include "eTerminateType.h" @@ -29,7 +30,7 @@ void WishingWellServer::OnUse(Entity* self, Entity* user) { GeneralUtils::GenerateRandomNumber(1, 1000) ); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StartCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"StartCooldown", 0, 0, LWOOBJID_EMPTY, "").Send(user->GetSystemAddress()); const auto userID = user->GetObjectID(); @@ -38,10 +39,10 @@ void WishingWellServer::OnUse(Entity* self, Entity* user) { if (user == nullptr) return; - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"StopCooldown", 0, 0, LWOOBJID_EMPTY, "", user->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"StopCooldown", 0, 0, LWOOBJID_EMPTY, "").Send(user->GetSystemAddress()); }); - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } void WishingWellServer::OnTimerDone(Entity* self, std::string timerName) { diff --git a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp index df0fe7b68..eb49368ae 100644 --- a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp +++ b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp @@ -2,6 +2,7 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "Character.h" #include "MissionComponent.h" #include "QuickBuildComponent.h" @@ -58,5 +59,5 @@ void NsTokenConsoleServer::OnUse(Entity* self, Entity* user) { missionComponent->ForceProgressTaskType(863, 1, 1, false); - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Map/NT/NTPipeVisibilityServer.cpp b/dScripts/02_server/Map/NT/NTPipeVisibilityServer.cpp index 7d39e9d90..2138b88c0 100644 --- a/dScripts/02_server/Map/NT/NTPipeVisibilityServer.cpp +++ b/dScripts/02_server/Map/NT/NTPipeVisibilityServer.cpp @@ -1,6 +1,7 @@ #include "NTPipeVisibilityServer.h" #include "Entity.h" #include "Character.h" +#include "ObjectMessages.h" void NTPipeVisibilityServer::OnQuickBuildComplete(Entity* self, Entity* target) { const auto flag = self->GetVar(u"flag"); @@ -11,5 +12,5 @@ void NTPipeVisibilityServer::OnQuickBuildComplete(Entity* self, Entity* target) character->SetPlayerFlag(flag, true); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PipeBuilt"); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PipeBuilt").Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp index debcaf054..081399bc9 100644 --- a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "MovementMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "eMissionTaskType.h" @@ -103,7 +104,7 @@ void NtAssemblyTubeServer::TeleportPlayer(Entity* self, Entity* player) { const auto destPosition = destination->GetPosition(); const auto destRotation = destination->GetRotation(); - GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); + GameMessages::Teleport(player->GetObjectID(), destPosition, destRotation, true).SendToClient(player->GetSystemAddress()); RenderComponent::PlayAnimation(player, u"tube-resurrect", 4.0f); diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp index 51d7ebd8d..a49d5e6ff 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp @@ -2,13 +2,14 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "ActivityMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "EntityInfo.h" #include "InventoryComponent.h" #include "MissionComponent.h" void NtCombatChallengeServer::OnUse(Entity* self, Entity* user) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Open", 0, 0, user->GetObjectID(), "", user->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"UI_Open", 0, 0, user->GetObjectID(), "").Send(user->GetSystemAddress()); } void NtCombatChallengeServer::OnDie(Entity* self, Entity* killer) { @@ -40,7 +41,7 @@ void NtCombatChallengeServer::OnHitOrHealResult(Entity* self, Entity* attacker, void NtCombatChallengeServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Close", 0, 0, sender->GetObjectID(), "", sender->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"UI_Close", 0, 0, sender->GetObjectID(), "").Send(sender->GetSystemAddress()); } @@ -66,7 +67,7 @@ void NtCombatChallengeServer::OnMessageBoxResponse(Entity* self, Entity* sender, self->SetNetworkVar(u"toggle", true); } else if (identifier == u"CloseButton") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Close", 1, 0, sender->GetObjectID(), "", sender->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"UI_Close", 1, 0, sender->GetObjectID(), "").Send(sender->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp b/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp index 8003f4df2..31278fd90 100644 --- a/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp +++ b/dScripts/02_server/Map/NT/NtImagimeterVisibility.cpp @@ -1,5 +1,6 @@ #include "NtImagimeterVisibility.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Entity.h" #include "Character.h" #include "ePlayerFlag.h" @@ -8,5 +9,5 @@ void NTImagimeterVisibility::OnQuickBuildComplete(Entity* self, Entity* target) auto* character = target->GetCharacter(); if (character) character->SetPlayerFlag(ePlayerFlag::NT_PLINTH_REBUILD, true); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlinthBuilt", 0, 0, LWOOBJID_EMPTY, "", target->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PlinthBuilt", 0, 0, LWOOBJID_EMPTY, "").Send(target->GetSystemAddress()); } diff --git a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp index 9b65168dd..b2592235e 100644 --- a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "ObjectMessages.h" #include "MissionComponent.h" #include "EntityManager.h" #include "Character.h" @@ -11,9 +12,9 @@ #include "eStateChangeType.h" void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"bActive", 1, 0, user->GetObjectID(), "", user->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"bActive", 1, 0, user->GetObjectID(), "").Send(user->GetSystemAddress()); - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"bActive", true); @@ -40,7 +41,7 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { RenderComponent::PlayAnimation(player, u"rebuild-celebrate"); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "").Send(player->GetSystemAddress()); GameMessages::SetStunned stun; stun.target = player->GetObjectID(); stun.StateChangeType = eStateChangeType::POP; @@ -81,7 +82,7 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { return; } - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"bActive", 0, 0, player->GetObjectID(), "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"bActive", 0, 0, player->GetObjectID(), "").Send(player->GetSystemAddress()); GameMessages::StopFXEffect(self->GetObjectID(), true, "console_sparks").Send(UNASSIGNED_SYSTEM_ADDRESS); diff --git a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp index 7e63bb5e9..ec2cb3f80 100644 --- a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "MovementMessages.h" #include "EntityManager.h" #include "MissionComponent.h" #include "eMissionTaskType.h" @@ -85,7 +86,7 @@ void NtParadoxTeleServer::TeleportPlayer(Entity* self, Entity* player) { cinematic.Send(player->GetSystemAddress()); } - GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); + GameMessages::Teleport(player->GetObjectID(), destPosition, destRotation, true).SendToClient(player->GetSystemAddress()); RenderComponent::PlayAnimation(player, u"paradox-teleport-in", 4.0f); diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp index ebf7beaea..d20f34ade 100644 --- a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp @@ -2,6 +2,8 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "Entity.h" #include "GeneralUtils.h" @@ -40,7 +42,7 @@ void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { auto destRotation = self->GetRotation(); - GameMessages::SendTeleport(playerID, destPosition, destRotation, player->GetSystemAddress(), true); + GameMessages::Teleport(playerID, destPosition, destRotation, true).SendToClient(player->GetSystemAddress()); RenderComponent::PlayAnimation(player, u"scale-down", 4.0f); @@ -140,7 +142,7 @@ void NtVentureCannonServer::UnlockCannonPlayer(Entity* self, Entity* player) { self->SetNetworkVar(u"bIsInUse", false); - GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } void NtVentureCannonServer::FirePlayer(Entity* self, Entity* player) { @@ -158,7 +160,7 @@ void NtVentureCannonServer::FirePlayer(Entity* self, Entity* player) { const auto destPosition = destination->GetPosition(); const auto destRotation = destination->GetRotation(); - GameMessages::SendTeleport(player->GetObjectID(), destPosition, destRotation, player->GetSystemAddress(), true); + GameMessages::Teleport(player->GetObjectID(), destPosition, destRotation, true).SendToClient(player->GetSystemAddress()); RenderComponent::PlayAnimation(player, u"venture-cannon-out", 4.0f); } diff --git a/dScripts/02_server/Map/PR/HydrantBroken.cpp b/dScripts/02_server/Map/PR/HydrantBroken.cpp index daaee04b7..ef5ecc4c2 100644 --- a/dScripts/02_server/Map/PR/HydrantBroken.cpp +++ b/dScripts/02_server/Map/PR/HydrantBroken.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" void HydrantBroken::OnStartup(Entity* self) { self->AddTimer("playEffect", 1); @@ -19,7 +20,7 @@ void HydrantBroken::OnStartup(Entity* self) { msg.bActive = true; msg.Send(UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"enableCollision", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"enableCollision").Send(UNASSIGNED_SYSTEM_ADDRESS); } self->AddTimer("KillBroken", 25); @@ -35,7 +36,7 @@ void HydrantBroken::OnTimerDone(Entity* self, std::string timerName) { msg.bActive = false; msg.Send(UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision").Send(UNASSIGNED_SYSTEM_ADDRESS); } self->Kill(); diff --git a/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp b/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp index 9e22efbfb..efc988b2e 100644 --- a/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp +++ b/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp @@ -1,6 +1,7 @@ #include "SpawnGryphonServer.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "MissionComponent.h" #include "eMissionState.h" #include "eTerminateType.h" @@ -21,7 +22,7 @@ void SpawnGryphonServer::OnUse(Entity* self, Entity* user) { if (missionComponent != nullptr && inventoryComponent != nullptr && missionComponent->GetMissionState(1391) == eMissionState::ACTIVE) { inventoryComponent->RemoveItem(12483, inventoryComponent->GetLotCount(12483), eInventoryType::ALL); - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); return; } diff --git a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp index dc260c7c8..fb89b36c4 100644 --- a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp @@ -4,6 +4,7 @@ #include "Entity.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "dZoneManager.h" #include "RenderComponent.h" #include "MissionComponent.h" @@ -67,8 +68,7 @@ void ZoneAgProperty::OnPlayerLoaded(Entity* self, Entity* player) { ambientSound.target = player->GetObjectID(); ambientSound.audioGUID = GUIDMaelstrom; ambientSound.SendToClient(player->GetSystemAddress()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, - LWOOBJID_EMPTY, "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, "").Send(player->GetSystemAddress()); self->SetNetworkVar(u"unclaimed", true); @@ -176,8 +176,7 @@ void ZoneAgProperty::StartMaelstrom(Entity* self, Entity* player) { StartTornadoFx(self); if (player != nullptr) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, - "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, "").Send(player->GetSystemAddress()); } } @@ -205,7 +204,7 @@ void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) { auto* entity = entities[0]; - GameMessages::SendNotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), u"GuardChat", 0, 0, entity->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), u"GuardChat", 0, 0, entity->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); LoadProperty(self); self->AddTimer("KillGuard", 5); @@ -235,8 +234,7 @@ void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) { self->AddTimer("turnSkyOff", 1.5f); self->AddTimer("killFXObject", 8); } else if (timerName == "turnSkyOff") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SkyOff", 0, 0, LWOOBJID_EMPTY, - "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"SkyOff", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "killSpider") { for (auto* entity : Game::entityManager->GetEntitiesInGroup(self->GetVar(EnemiesGroup))) { entity->Kill(); @@ -271,13 +269,12 @@ void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) { ambientSound.SendToClient(player->GetSystemAddress()); } } else if (timerName == "ShowVendor") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); for (const auto& ambient : self->GetVar>(AmbientFXSpawner)) { ActivateSpawner(ambient); } } else if (timerName == "BoundsVisOn") { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "runPlayerLoadedAgain") { CheckForOwner(self); } else if (timerName == "pollTornadoFX") { @@ -424,8 +421,7 @@ void ZoneAgProperty::BaseOnFireEventServerSide(Entity* self, Entity* sender, std auto* const character = player->GetCharacter(); if (character) character->SetPlayerFlag(self->GetVar(defeatedProperyFlag), true); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, - LWOOBJID_EMPTY, destroyedCinematic, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, destroyedCinematic).Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("tornadoOff", 0.5f); } diff --git a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp index 16ee02fd1..be59d966b 100644 --- a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp +++ b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "Amf3.h" #include "Entity.h" @@ -31,8 +32,7 @@ void PropertyBankInteract::OnUse(Entity* self, Entity* user) { uiMessage.args = std::move(args); uiMessage.SendToClient(user->GetSystemAddress()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY, - "", user->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"OpenBank", 0, 0, LWOOBJID_EMPTY, "").Send(user->GetSystemAddress()); } void PropertyBankInteract::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, @@ -48,7 +48,6 @@ void PropertyBankInteract::OnFireEventServerSide(Entity* self, Entity* sender, s uiMessage.args = std::move(amfArgs); uiMessage.SendToClient(sender->GetSystemAddress()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, - "", sender->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"CloseBank", 0, 0, LWOOBJID_EMPTY, "").Send(sender->GetSystemAddress()); } } diff --git a/dScripts/02_server/Map/VE/VeBricksampleServer.cpp b/dScripts/02_server/Map/VE/VeBricksampleServer.cpp index 382ce751b..9e48a2ba4 100644 --- a/dScripts/02_server/Map/VE/VeBricksampleServer.cpp +++ b/dScripts/02_server/Map/VE/VeBricksampleServer.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "MissionComponent.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "eMissionState.h" void VeBricksampleServer::OnUse(Entity* self, Entity* user) { @@ -15,7 +16,7 @@ void VeBricksampleServer::OnUse(Entity* self, Entity* user) { inventoryComponent->AddItem(loot, 1, eLootSourceType::NONE); for (auto* brickEntity : Game::entityManager->GetEntitiesInGroup("Bricks")) { - GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup"); + GameMessages::NotifyClientObject(brickEntity->GetObjectID(), u"Pickedup").Send(UNASSIGNED_SYSTEM_ADDRESS); } } } diff --git a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp index 4e8cb4e9a..79023bf18 100644 --- a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp +++ b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "eMissionState.h" #include "Entity.h" @@ -22,7 +23,7 @@ void VeEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int miss // Notify the client that all objects have updated self->AddCallbackTimer(3.0f, [this]() { for (const auto* console : Game::entityManager->GetEntitiesInGroup(m_ConsoleGroup)) { - GameMessages::SendNotifyClientObject(console->GetObjectID(), u""); + GameMessages::NotifyClientObject(console->GetObjectID(), u"").Send(UNASSIGNED_SYSTEM_ADDRESS); } }); } diff --git a/dScripts/02_server/Map/VE/VeMissionConsole.cpp b/dScripts/02_server/Map/VE/VeMissionConsole.cpp index aa7035eb2..443c9a570 100644 --- a/dScripts/02_server/Map/VE/VeMissionConsole.cpp +++ b/dScripts/02_server/Map/VE/VeMissionConsole.cpp @@ -2,6 +2,7 @@ #include "InventoryComponent.h" #include "Character.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Loot.h" #include "eTerminateType.h" @@ -22,6 +23,6 @@ void VeMissionConsole::OnUse(Entity* self, Entity* user) { character->SetPlayerFlag(flag, true); } - GameMessages::SendNotifyClientObject(self->GetObjectID(), u""); - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp b/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp index 033da0e86..a0dc3580e 100644 --- a/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp +++ b/dScripts/02_server/Map/njhub/CatapultBaseServer.cpp @@ -2,6 +2,7 @@ #include "PetMessages.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "Entity.h" #include "RenderComponent.h" @@ -65,7 +66,7 @@ void CatapultBaseServer::OnTimerDone(Entity* self, std::string timerName) { if (bouncer == nullptr) return; // kill the bouncer - GameMessages::SendNotifyClientObject(bouncer->GetObjectID(), u"TimeToDie"); + GameMessages::NotifyClientObject(bouncer->GetObjectID(), u"TimeToDie").Send(UNASSIGNED_SYSTEM_ADDRESS); bouncer->Smash(self->GetObjectID(), eKillType::VIOLENT); } } diff --git a/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp b/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp index 28ed9f804..6b6246a0a 100644 --- a/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp +++ b/dScripts/02_server/Map/njhub/CatapultBouncerServer.cpp @@ -1,9 +1,10 @@ #include "CatapultBouncerServer.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" void CatapultBouncerServer::OnQuickBuildComplete(Entity* self, Entity* target) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"Built", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"Built", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); self->SetNetworkVar(u"Built", true); diff --git a/dScripts/02_server/Map/njhub/CavePrisonCage.cpp b/dScripts/02_server/Map/njhub/CavePrisonCage.cpp index 591c29d56..884271165 100644 --- a/dScripts/02_server/Map/njhub/CavePrisonCage.cpp +++ b/dScripts/02_server/Map/njhub/CavePrisonCage.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "QuickBuildComponent.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Character.h" #include "dZoneManager.h" #include "RenderComponent.h" @@ -158,7 +159,7 @@ void CavePrisonCage::OnTimerDone(Entity* self, std::string timerName) { return; } - GameMessages::SendNotifyClientObject(villager->GetObjectID(), u"TimeToChat", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(villager->GetObjectID(), u"TimeToChat", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); // Get the builder and make sure it still exists auto* builder = Game::entityManager->GetEntity(self->GetVar(u"Builder")); diff --git a/dScripts/02_server/Map/njhub/NjWuNPC.cpp b/dScripts/02_server/Map/njhub/NjWuNPC.cpp index 53658aa4a..6540cd357 100644 --- a/dScripts/02_server/Map/njhub/NjWuNPC.cpp +++ b/dScripts/02_server/Map/njhub/NjWuNPC.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "eMissionState.h" #include "ePlayerFlag.h" @@ -30,8 +31,7 @@ void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, e // Hide the chest for (auto* chest : Game::entityManager->GetEntitiesInGroup(m_DragonChestGroup)) { - GameMessages::SendNotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 0, -1, - target->GetObjectID(), "", target->GetSystemAddress()); + GameMessages::NotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 0, -1, target->GetObjectID(), "").Send(target->GetSystemAddress()); } return; @@ -43,8 +43,7 @@ void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, e // Show the chest for (auto* chest : Game::entityManager->GetEntitiesInGroup(m_DragonChestGroup)) { - GameMessages::SendNotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 1, -1, - target->GetObjectID(), "", target->GetSystemAddress()); + GameMessages::NotifyClientObject(chest->GetObjectID(), m_ShowChestNotification, 1, -1, target->GetObjectID(), "").Send(target->GetSystemAddress()); } auto playerID = target->GetObjectID(); diff --git a/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp index 9e20078ff..965662b75 100644 --- a/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp +++ b/dScripts/02_server/Map/njhub/boss_instance/NjMonastryBossInstance.cpp @@ -5,6 +5,8 @@ #include "dZoneManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" #include "BaseCombatAIComponent.h" #include "BuffComponent.h" #include "SkillComponent.h" @@ -84,8 +86,7 @@ void NjMonastryBossInstance::OnPlayerLoaded(Entity* self, Entity* player) { self->AddCallbackTimer(0.0f, [self, player]() { if (player != nullptr) { // If we don't have enough players yet, wait for the others to load and notify the client to play a cool cinematic - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLoaded", 0, 0, - player->GetObjectID(), "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PlayerLoaded", 0, 0, player->GetObjectID(), "").Send(player->GetSystemAddress()); } }); @@ -114,7 +115,7 @@ void NjMonastryBossInstance::OnPlayerExit(Entity* self, Entity* player) { // resize the instance to account for such. if (totalPlayersLoaded.size() <= 2) self->SetVar(LargeTeamVariable, false); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0, player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0, player->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); } void NjMonastryBossInstance::OnActivityTimerDone(Entity* self, const std::string& name) { @@ -173,8 +174,7 @@ void NjMonastryBossInstance::OnActivityTimerDone(Entity* self, const std::string } ActivityTimerStart(self, SpawnLowerFrakjawTimer, 1.0f, 1.0f); - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, BottomFrakSpawn, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, BottomFrakSpawn).Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == SpawnLowerFrakjawTimer) { auto spawners = Game::zoneManager->GetSpawnersByName(LowerFrakjawSpawner); if (!spawners.empty()) { @@ -182,8 +182,7 @@ void NjMonastryBossInstance::OnActivityTimerDone(Entity* self, const std::string spawner->Activate(); } } else if (timerName == SpawnRailTimer) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, FireRailSpawn, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, FireRailSpawn).Send(UNASSIGNED_SYSTEM_ADDRESS); auto spawners = Game::zoneManager->GetSpawnersByName(FireRailSpawner); if (!spawners.empty()) { @@ -230,15 +229,10 @@ void NjMonastryBossInstance::HandleCounterWeightSpawned(Entity* self, Entity* co switch (state) { case eQuickBuildState::BUILDING: - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, - 0, 0, counterWeight->GetObjectID(), - BaseCounterweightQB + std::to_string(self->GetVar(WaveNumberVariable)), - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, counterWeight->GetObjectID(), BaseCounterweightQB + std::to_string(self->GetVar(WaveNumberVariable))).Send(UNASSIGNED_SYSTEM_ADDRESS); return; case eQuickBuildState::INCOMPLETE: - GameMessages::SendNotifyClientObject(self->GetObjectID(), EndCinematicNotification, - 0, 0, LWOOBJID_EMPTY, "", - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), EndCinematicNotification, 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); return; case eQuickBuildState::RESETTING: ActivityTimerStart(self, SpawnCounterWeightTimer, 0.0f, 0.0f); @@ -255,8 +249,7 @@ void NjMonastryBossInstance::HandleCounterWeightSpawned(Entity* self, Entity* co auto* frakjaw = Game::entityManager->GetEntity(self->GetVar(LedgeFrakjawVariable)); if (frakjaw == nullptr) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, - 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); return; } @@ -304,8 +297,7 @@ void NjMonastryBossInstance::HandleLowerFrakjawSpawned(Entity* self, Entity* low NjMonastryBossInstance::HandleLowerFrakjawDied(self, lowerFrakjaw); }); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"LedgeFrakjawDead", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); if (self->GetVar(LargeTeamVariable)) { // Double frakjaws health for large teams @@ -397,37 +389,30 @@ void NjMonastryBossInstance::HandleWaveEnemyDied(Entity* self, Entity* waveEnemy void NjMonastryBossInstance::TeleportPlayer(Entity* player, uint32_t position) { for (const auto* spawnPoint : Game::entityManager->GetEntitiesInGroup("SpawnPoint" + std::to_string(position))) { - GameMessages::SendTeleport(player->GetObjectID(), spawnPoint->GetPosition(), spawnPoint->GetRotation(), - player->GetSystemAddress(), true); + GameMessages::Teleport(player->GetObjectID(), spawnPoint->GetPosition(), spawnPoint->GetRotation(), true).SendToClient(player->GetSystemAddress()); } } void NjMonastryBossInstance::SummonWave(Entity* self, Entity* frakjaw) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, - LedgeFrakSummon, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, LedgeFrakSummon).Send(UNASSIGNED_SYSTEM_ADDRESS); RenderComponent::PlayAnimation(frakjaw, SummonAnimation); // Stop the music for the first, fourth and fifth wave const auto wave = self->GetVar(WaveNumberVariable); if (wave >= 1 && wave < (m_Waves.size() - 1)) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave - 1), - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave - 1)).Send(UNASSIGNED_SYSTEM_ADDRESS); } // After frakjaw moves down the music stays the same if (wave < (m_Waves.size() - 1)) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), StartMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave), - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), StartMusicNotification, 0, 0, LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(wave)).Send(UNASSIGNED_SYSTEM_ADDRESS); } ActivityTimerStart(self, SpawnWaveTimer, 4.0f, 4.0f); } void NjMonastryBossInstance::LowerFrakjawSummon(Entity* self, Entity* frakjaw) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, BottomFrakSummon, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, BottomFrakSummon).Send(UNASSIGNED_SYSTEM_ADDRESS); ActivityTimerStart(self, SpawnWaveTimer, 2.0f, 2.0f); RenderComponent::PlayAnimation(frakjaw, SummonAnimation); } @@ -451,10 +436,8 @@ void NjMonastryBossInstance::LowerFrakjaw(Entity* self, Entity* frakjaw) { RenderComponent::PlayAnimation(frakjaw, TeleportOutAnimation); ActivityTimerStart(self, LowerFrakjawCamTimer, 2.0f, 2.0f); - GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StopMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 3), UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyClientObject(frakjaw->GetObjectID(), StartMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(frakjaw->GetObjectID(), StopMusicNotification, 0, 0, LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 3)).Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(frakjaw->GetObjectID(), StartMusicNotification, 0, 0, LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2)).Send(UNASSIGNED_SYSTEM_ADDRESS); } void NjMonastryBossInstance::SpawnOnNetwork(Entity* self, const LOT& toSpawn, const uint32_t& numberToSpawn, const std::string& spawnerName) { @@ -475,16 +458,13 @@ void NjMonastryBossInstance::WaveOver(Entity* self) { if (wave >= m_Waves.size() - 1) return; - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, BaseCounterweightSpawn + std::to_string(wave), - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, BaseCounterweightSpawn + std::to_string(wave)).Send(UNASSIGNED_SYSTEM_ADDRESS); ActivityTimerStart(self, SpawnCounterWeightTimer, 1.5f, 1.5f); RemovePoison(self); } void NjMonastryBossInstance::FightOver(Entity* self) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"GroundFrakjawDead", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"GroundFrakjawDead", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); // Remove all the enemies from the battlefield for (auto i = 1; i < 5; i++) { @@ -500,13 +480,9 @@ void NjMonastryBossInstance::FightOver(Entity* self) { ActivityTimerStart(self, SpawnRailTimer, 1.5f, 1.5f); // Set the music to play the victory music - GameMessages::SendNotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, - LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2), - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyClientObject(self->GetObjectID(), FlashMusicNotification, 0, 0, - LWOOBJID_EMPTY, "Monastery_Frakjaw_Battle_Win", UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, - LWOOBJID_EMPTY, TreasureChestSpawning, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), StopMusicNotification, 0, 0, LWOOBJID_EMPTY, AudioWaveAudio + std::to_string(m_Waves.size() - 2)).Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), FlashMusicNotification, 0, 0, LWOOBJID_EMPTY, "Monastery_Frakjaw_Battle_Win").Send(UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), PlayCinematicNotification, 0, 0, LWOOBJID_EMPTY, TreasureChestSpawning).Send(UNASSIGNED_SYSTEM_ADDRESS); auto treasureChests = Game::entityManager->GetEntitiesInGroup(ChestSpawnpointGroup); for (auto* treasureChest : treasureChests) { diff --git a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp index 16395a4e1..3f36abb5e 100644 --- a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp +++ b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp @@ -5,6 +5,7 @@ #include "SkillComponent.h" #include "TeamManager.h" #include "Loot.h" +#include "InventoryMessages.h" void AgSurvivalBuffStation::OnQuickBuildComplete(Entity* self, Entity* target) { auto destroyableComponent = self->GetComponent(); diff --git a/dScripts/02_server/Pets/PetFromObjectServer.cpp b/dScripts/02_server/Pets/PetFromObjectServer.cpp index 0a78d7ecd..2d3ae3418 100644 --- a/dScripts/02_server/Pets/PetFromObjectServer.cpp +++ b/dScripts/02_server/Pets/PetFromObjectServer.cpp @@ -1,6 +1,7 @@ #include "PetFromObjectServer.h" #include "PetComponent.h" #include "ePetTamingNotifyType.h" +#include "ObjectMessages.h" void PetFromObjectServer::OnStartup(Entity* self) { self->SetNetworkVar(u"pettamer", std::to_string(self->GetVar(u"tamer"))); @@ -27,8 +28,7 @@ void PetFromObjectServer::OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, break; case ePetTamingNotifyType::SUCCESS: // TODO: Remove from groups? - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UpdateSuccessPicking", 0, - 0, tamer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"UpdateSuccessPicking", 0, 0, tamer->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); default: break; } diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index 35459538c..49d47e40d 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -3,6 +3,7 @@ #include "ScriptedActivityComponent.h" #include "LeaderboardManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include #include "Logger.h" #include "Loot.h" @@ -91,7 +92,7 @@ void ActivityManager::SaveScore(Entity* self, const LWOOBJID playerID, const flo LeaderboardManager::SaveScore(playerID, gameID, primaryScore, secondaryScore, tertiaryScore); // Makes the leaderboard show up for the player - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", gameID, 0, playerID, "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"ToggleLeaderBoard", gameID, 0, playerID, "").Send(player->GetSystemAddress()); } bool ActivityManager::TakeActivityCost(const Entity* self, const LWOOBJID playerID) { diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index c64b8a569..3b2978441 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -2,6 +2,8 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "ObjectMessages.h" +#include "ZoneMessages.h" #include "CharacterComponent.h" #include "RenderComponent.h" #include "EntityManager.h" @@ -69,10 +71,15 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s return; } - GameMessages::SendDisplayZoneSummary(playerID, player->GetSystemAddress(), false, false, self->GetObjectID()); + GameMessages::DisplayZoneSummary zoneSummary; + zoneSummary.target = playerID; + zoneSummary.isPropertyMap = false; + zoneSummary.isZoneStart = false; + zoneSummary.sender = self->GetObjectID(); + zoneSummary.Send(player->GetSystemAddress()); }); } else if (button == -1 || button == 0) { - GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, player->GetObjectID()); + GameMessages::TerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, player->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } } @@ -116,7 +123,7 @@ void BaseConsoleTeleportServer::TransferPlayer(Entity* self, Entity* player, int stun.bCantUseItem = true; stun.Send(player->GetSystemAddress()); - GameMessages::SendTerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, player->GetObjectID()); + GameMessages::TerminateInteraction(player->GetObjectID(), eTerminateType::FROM_INTERACTION, player->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); const auto& teleportZone = self->GetVar(u"transferZoneID"); diff --git a/dScripts/BasePropertyServer.cpp b/dScripts/BasePropertyServer.cpp index ddd5bdda2..2a3cd88fa 100644 --- a/dScripts/BasePropertyServer.cpp +++ b/dScripts/BasePropertyServer.cpp @@ -1,6 +1,7 @@ #include "BasePropertyServer.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "Character.h" @@ -179,8 +180,7 @@ void BasePropertyServer::PropGuardCheck(Entity* self, Entity* player) { } void BasePropertyServer::BaseZonePropertyRented(Entity* self, Entity* player) const { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, "ShowProperty", - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, "ShowProperty").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer(BoundsVisOnTimer, 2); self->SetVar(PropertyOwnerVariable, player->GetObjectID()); @@ -247,8 +247,7 @@ void BasePropertyServer::StartMaelstrom(Entity* self, Entity* player) { StartTornadoFx(self); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, - "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, "").Send(player->GetSystemAddress()); self->AddTimer(StartGeneratorTimer, 0.0f); self->AddTimer(StartOrbTimer, 0.0f); @@ -354,9 +353,7 @@ void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerNam return; auto* guard = entities[0]; - GameMessages::SendNotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), - u"GuardChat", 0, 0, guard->GetObjectID(), - "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), u"GuardChat", 0, 0, guard->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer(KillGuardTimer, 5.0f); } else if (timerName == KillGuardTimer) { @@ -388,8 +385,7 @@ void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerNam self->AddTimer(KillFXObjectTimer, 8.0f); } else if (timerName == TurnSkyOffTimer) { auto* controller = Game::zoneManager->GetZoneControlObject(); - GameMessages::SendNotifyClientObject(controller->GetObjectID(), u"SkyOff", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(controller->GetObjectID(), u"SkyOff", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == KillStrombiesTimer) { const auto enemies = Game::entityManager->GetEntitiesInGroup(self->GetVar(EnemiesGroup)); for (auto* enemy : enemies) { @@ -429,16 +425,13 @@ void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerNam self->AddTimer(ShowVendorTimer, 1.0f); } else if (timerName == ShowVendorTimer) { - GameMessages::SendNotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), - u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", - UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); for (const auto& ambientFXSpawner : self->GetVar>(AmbientFXSpawner)) { ActivateSpawner(ambientFXSpawner); } } else if (timerName == BoundsVisOnTimer) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, - LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == RunPlayerLoadedAgainTimer) { CheckForOwner(self); } else if (timerName == PollTornadoFXTimer) { @@ -483,9 +476,7 @@ void BasePropertyServer::HandleOrbsTimer(Entity* self) { } DestroySpawner(self->GetVar(GeneratorFXSpawner)); - GameMessages::SendNotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), - u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, - "DestroyMaelstrom", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(Game::entityManager->GetZoneControlEntity()->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, "DestroyMaelstrom").Send(UNASSIGNED_SYSTEM_ADDRESS); // Notifies the client that the property has been claimed with a flag, completes missions too auto* player = Game::entityManager->GetEntity(self->GetVar(PlayerIDVariable)); diff --git a/dScripts/BaseSurvivalServer.cpp b/dScripts/BaseSurvivalServer.cpp index 2a41b6e98..b7f545213 100644 --- a/dScripts/BaseSurvivalServer.cpp +++ b/dScripts/BaseSurvivalServer.cpp @@ -2,6 +2,8 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "ActivityMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" #include "DestroyableComponent.h" #include "EntityManager.h" #include "dZoneManager.h" @@ -140,8 +142,7 @@ void BaseSurvivalServer::BasePlayerDied(Entity* self, Entity* player) { SetActivityValue(self, player->GetObjectID(), 1, finalTime); auto paramString = CheckAllPlayersDead() ? "true" : "false"; - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, 0, - player->GetObjectID(), paramString, player->GetSystemAddress()); + GameMessages::NotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, 0, player->GetObjectID(), paramString).Send(player->GetSystemAddress()); GameOver(self); } else { player->Resurrect(); @@ -303,7 +304,9 @@ void BaseSurvivalServer::StartWaves(Entity* self) { TakeActivityCost(self, playerID); } - GameMessages::SendPlayerSetCameraCyclingMode(playerID, player->GetSystemAddress()); + GameMessages::PlayerSetCameraCyclingMode cameraCyclingMode; + cameraCyclingMode.target = playerID; + cameraCyclingMode.SendToClient(player->GetSystemAddress()); } } @@ -336,7 +339,7 @@ void BaseSurvivalServer::SetPlayerSpawnPoints() { auto possibleSpawners = Game::entityManager->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn"); if (!possibleSpawners.empty()) { auto* spawner = possibleSpawners.at(0); - GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true); + GameMessages::Teleport(playerID, spawner->GetPosition(), spawner->GetRotation(), true).SendToClient(player->GetSystemAddress()); } } @@ -364,8 +367,7 @@ void BaseSurvivalServer::GameOver(Entity* self) { const auto time = GetActivityValue(self, playerID, 1); SaveScore(self, playerID, score, time); - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, - playerID, std::to_string(score), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, playerID, std::to_string(score)).Send(UNASSIGNED_SYSTEM_ADDRESS); player->Resurrect(); // Update all mission progression diff --git a/dScripts/BaseWavesServer.cpp b/dScripts/BaseWavesServer.cpp index 1ff875800..e92f976be 100644 --- a/dScripts/BaseWavesServer.cpp +++ b/dScripts/BaseWavesServer.cpp @@ -3,6 +3,8 @@ #include "EffectsMessages.h" #include "CombatMessages.h" #include "ActivityMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" #include "DestroyableComponent.h" #include "EntityManager.h" #include "dZoneManager.h" @@ -22,7 +24,9 @@ void BaseWavesServer::SetGameVariables(Entity* self) { // Done void BaseWavesServer::BasePlayerLoaded(Entity* self, Entity* player) { - GameMessages::SendPlayerSetCameraCyclingMode(player->GetObjectID(), player->GetSystemAddress()); + GameMessages::PlayerSetCameraCyclingMode cameraCyclingMode; + cameraCyclingMode.target = player->GetObjectID(); + cameraCyclingMode.SendToClient(player->GetSystemAddress()); GameMessages::SetPlayerAllowedRespawn allowedRespawn; allowedRespawn.target = player->GetObjectID(); allowedRespawn.dontPromptForRespawn = true; @@ -132,8 +136,7 @@ void BaseWavesServer::BasePlayerDied(Entity* self, Entity* player) { auto paramString = CheckAllPlayersDead() ? "true" : "false"; - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, finalWave, - player->GetObjectID(), paramString, player->GetSystemAddress()); + GameMessages::NotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, finalWave, player->GetObjectID(), paramString).Send(player->GetSystemAddress()); if (!self->GetNetworkVar(WavesStartedVariable)) { player->Resurrect(); @@ -145,8 +148,7 @@ void BaseWavesServer::BasePlayerDied(Entity* self, Entity* player) { // Done void BaseWavesServer::BasePlayerResurrected(Entity* self, Entity* player) { - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Res", 0, 0, - player->GetObjectID(), "", player->GetSystemAddress()); + GameMessages::NotifyClientZoneObject(self->GetObjectID(), u"Player_Res", 0, 0, player->GetObjectID(), "").Send(player->GetSystemAddress()); if (self->GetNetworkVar(WavesStartedVariable)) return; @@ -335,7 +337,7 @@ void BaseWavesServer::SetPlayerSpawnPoints(const LWOOBJID& specificPlayerID) { auto possibleSpawners = Game::entityManager->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn"); if (!possibleSpawners.empty()) { auto* spawner = possibleSpawners.at(0); - GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true); + GameMessages::Teleport(playerID, spawner->GetPosition(), spawner->GetRotation(), true).SendToClient(player->GetSystemAddress()); } } @@ -369,8 +371,7 @@ void BaseWavesServer::GameOver(Entity* self, bool won) { const auto time = GetActivityValue(self, playerID, 1); const auto wave = GetActivityValue(self, playerID, 2); - GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, - playerID, std::to_string(wave), UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0, playerID, std::to_string(wave)).Send(UNASSIGNED_SYSTEM_ADDRESS); if (won) { SetPlayerSpawnPoints(); diff --git a/dScripts/ChooseYourDestinationNsToNt.cpp b/dScripts/ChooseYourDestinationNsToNt.cpp index 47a70578f..e8edde0ec 100644 --- a/dScripts/ChooseYourDestinationNsToNt.cpp +++ b/dScripts/ChooseYourDestinationNsToNt.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "eTerminateType.h" bool ChooseYourDestinationNsToNt::CheckChoice(Entity* self, Entity* player) { @@ -67,6 +68,6 @@ void ChooseYourDestinationNsToNt::BaseChoiceBoxRespond(Entity* self, Entity* sen messageBox.userData = u""; messageBox.Send(sender->GetSystemAddress()); } else { - GameMessages::SendTerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } } diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index 5ba4cee2f..b45e5d730 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -11,6 +11,10 @@ enum class eMissionState : int32_t; enum class ePetTamingNotifyType : uint32_t; enum class eQuickBuildState : uint32_t; +namespace GameMessages { + struct ShootingGalleryFire; +}; + namespace CppScripts { /** * Base class for all scripts. Includes virtual methods to be overridden to handle LUA equivelent events. diff --git a/dScripts/Darkitect.cpp b/dScripts/Darkitect.cpp index 2881bde89..08fa15676 100644 --- a/dScripts/Darkitect.cpp +++ b/dScripts/Darkitect.cpp @@ -3,13 +3,14 @@ #include "DestroyableComponent.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Character.h" #include "eMissionState.h" void Darkitect::Reveal(Entity* self, Entity* player) { const auto playerID = player->GetObjectID(); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"reveal", 0, 0, playerID, "", player->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), u"reveal", 0, 0, playerID, "").Send(player->GetSystemAddress()); self->AddCallbackTimer(20, [this, self, playerID]() { auto* player = Game::entityManager->GetEntity(playerID); diff --git a/dScripts/NtFactionSpyServer.cpp b/dScripts/NtFactionSpyServer.cpp index ab2f85a41..5772e2be6 100644 --- a/dScripts/NtFactionSpyServer.cpp +++ b/dScripts/NtFactionSpyServer.cpp @@ -4,6 +4,7 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "MissionComponent.h" #include "eMissionState.h" #include "eReplicaComponentType.h" @@ -87,9 +88,7 @@ void NtFactionSpyServer::OnCinematicUpdate(Entity* self, Entity* sender, eCinema if (event == eCinematicEvent::STARTED && pathIndex >= 0 && pathIndex < dialogueTable.size()) { // If the cinematic started, show part of the conversation - GameMessages::SendNotifyClientObject(self->GetObjectID(), m_SpyDialogueNotification, 0, - 0, ParamObjectForConversationID(self, dialogueTable.at(pathIndex).conversationID), - dialogueTable.at(pathIndex).token, sender->GetSystemAddress()); + GameMessages::NotifyClientObject(self->GetObjectID(), m_SpyDialogueNotification, 0, 0, ParamObjectForConversationID(self, dialogueTable.at(pathIndex).conversationID), dialogueTable.at(pathIndex).token).Send(sender->GetSystemAddress()); } else if (event == eCinematicEvent::ENDED && pathIndex >= dialogueTable.size() - 1) { auto spyData = self->GetVar(m_SpyDataVariable); diff --git a/dScripts/ScriptedPowerupSpawner.cpp b/dScripts/ScriptedPowerupSpawner.cpp index 8539b3632..9af6c4262 100644 --- a/dScripts/ScriptedPowerupSpawner.cpp +++ b/dScripts/ScriptedPowerupSpawner.cpp @@ -2,6 +2,7 @@ #include "RenderComponent.h" #include "EntityManager.h" #include "Loot.h" +#include "InventoryMessages.h" void ScriptedPowerupSpawner::OnTemplateStartup(Entity* self) { self->SetVar(u"currentCycle", 1); diff --git a/dScripts/SpawnPetBaseServer.cpp b/dScripts/SpawnPetBaseServer.cpp index 345727e43..a86226583 100644 --- a/dScripts/SpawnPetBaseServer.cpp +++ b/dScripts/SpawnPetBaseServer.cpp @@ -1,6 +1,7 @@ #include "SpawnPetBaseServer.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "PetComponent.h" #include "EntityInfo.h" @@ -46,7 +47,7 @@ void SpawnPetBaseServer::OnUse(Entity* self, Entity* user) { cinematic.Send(UNASSIGNED_SYSTEM_ADDRESS); } - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } bool SpawnPetBaseServer::CheckNumberOfPets(Entity* self, Entity* user) { diff --git a/dScripts/ai/AG/AgBusDoor.cpp b/dScripts/ai/AG/AgBusDoor.cpp index e74e8af88..69c9c3e8c 100644 --- a/dScripts/ai/AG/AgBusDoor.cpp +++ b/dScripts/ai/AG/AgBusDoor.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "MovementMessages.h" #include "ProximityMonitorComponent.h" void AgBusDoor::OnStartup(Entity* self) { @@ -49,9 +50,9 @@ void AgBusDoor::OnProximityUpdate(Entity* self, Entity* entering, std::string na void AgBusDoor::MoveDoor(Entity* self, bool bOpen) { if (bOpen) { - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 1, 0); + GameMessages::PlatformResync(*self, true, 1, 0).Send(UNASSIGNED_SYSTEM_ADDRESS); } else { - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, 1); + GameMessages::PlatformResync(*self, true, 0, 1).Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer("dustTimer", 2.0f); } diff --git a/dScripts/ai/AG/AgImagSmashable.cpp b/dScripts/ai/AG/AgImagSmashable.cpp index 7d67cc299..52918b9b5 100644 --- a/dScripts/ai/AG/AgImagSmashable.cpp +++ b/dScripts/ai/AG/AgImagSmashable.cpp @@ -6,6 +6,7 @@ #include "DestroyableComponent.h" #include "eReplicaComponentType.h" #include "Loot.h" +#include "InventoryMessages.h" void AgImagSmashable::OnDie(Entity* self, Entity* killer) { bool maxImagGreaterThanZero = false; diff --git a/dScripts/ai/AG/AgJetEffectServer.cpp b/dScripts/ai/AG/AgJetEffectServer.cpp index 0344a2f49..52d0d7e18 100644 --- a/dScripts/ai/AG/AgJetEffectServer.cpp +++ b/dScripts/ai/AG/AgJetEffectServer.cpp @@ -1,6 +1,7 @@ #include "AgJetEffectServer.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "SkillComponent.h" #include "eReplicaComponentType.h" @@ -8,9 +9,7 @@ void AgJetEffectServer::OnUse(Entity* self, Entity* user) { if (inUse || self->GetLOT() != 6859) return; - GameMessages::SendNotifyClientObject( - self->GetObjectID(), u"toggleInUse", 1, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS - ); + GameMessages::NotifyClientObject(self->GetObjectID(), u"toggleInUse", 1, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); inUse = true; auto entities = Game::entityManager->GetEntitiesInGroup("Jet_FX"); @@ -53,9 +52,7 @@ void AgJetEffectServer::OnTimerDone(Entity* self, std::string timerName) { auto* skillComponent = mortar->GetComponent(); if (skillComponent) skillComponent->CastSkill(318); } else if (timerName == "CineDone") { - GameMessages::SendNotifyClientObject( - self->GetObjectID(), u"toggleInUse", -1, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS - ); + GameMessages::NotifyClientObject(self->GetObjectID(), u"toggleInUse", -1, 0, LWOOBJID_EMPTY, "").Send(UNASSIGNED_SYSTEM_ADDRESS); inUse = false; } } diff --git a/dScripts/ai/AG/AgPicnicBlanket.cpp b/dScripts/ai/AG/AgPicnicBlanket.cpp index fd3ced79b..3361b4257 100644 --- a/dScripts/ai/AG/AgPicnicBlanket.cpp +++ b/dScripts/ai/AG/AgPicnicBlanket.cpp @@ -1,11 +1,13 @@ #include "AgPicnicBlanket.h" #include "Loot.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "Entity.h" #include "eTerminateType.h" +#include "InventoryMessages.h" void AgPicnicBlanket::OnUse(Entity* self, Entity* user) { - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); if (self->GetVar(u"active")) return; self->SetVar(u"active", true); diff --git a/dScripts/ai/AG/AgQbElevator.cpp b/dScripts/ai/AG/AgQbElevator.cpp index 07cd7e614..d7d127773 100644 --- a/dScripts/ai/AG/AgQbElevator.cpp +++ b/dScripts/ai/AG/AgQbElevator.cpp @@ -1,6 +1,7 @@ #include "AgQbElevator.h" #include "EntityManager.h" #include "GameMessages.h" +#include "MovementMessages.h" void AgQbElevator::OnStartup(Entity* self) { @@ -14,8 +15,7 @@ void AgQbElevator::OnQuickBuildComplete(Entity* self, Entity* target) { float delayTime = killTime - endTime; if (delayTime < 1) delayTime = 1; - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, eMovementPlatformState::Stationary); + GameMessages::PlatformResync(*self, true, 0, 0, 0, eMovementPlatformState::Stationary).Send(UNASSIGNED_SYSTEM_ADDRESS); //add a timer that will kill the QB if no players get on in the killTime self->AddTimer("startKillTimer", killTime); @@ -32,8 +32,7 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string self->SetBoolean(u"qbPlayerRdy", true); self->CancelTimer("StartElevator"); - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, eMovementPlatformState::Moving); + GameMessages::PlatformResync(*self, true, 0, 1, 1, eMovementPlatformState::Moving).Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (!self->GetBoolean(u"StartTimer")) { self->SetBoolean(u"StartTimer", true); self->AddTimer("StartElevator", startTime); @@ -44,8 +43,7 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string void AgQbElevator::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "StartElevator") { - GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, eMovementPlatformState::Moving); + GameMessages::PlatformResync(*self, true, 0, 1, 1, eMovementPlatformState::Moving).Send(UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == "startKillTimer") { killTimerStartup(self); } else if (timerName == "KillTimer") { diff --git a/dScripts/ai/AG/AgShipPlayerShockServer.cpp b/dScripts/ai/AG/AgShipPlayerShockServer.cpp index a439f0bde..44f2220fc 100644 --- a/dScripts/ai/AG/AgShipPlayerShockServer.cpp +++ b/dScripts/ai/AG/AgShipPlayerShockServer.cpp @@ -2,12 +2,13 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "CombatMessages.h" +#include "ObjectMessages.h" #include "RenderComponent.h" #include "Entity.h" #include "eTerminateType.h" void AgShipPlayerShockServer::OnUse(Entity* self, Entity* user) { - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); if (active) { return; } diff --git a/dScripts/ai/AG/AgTurret.cpp b/dScripts/ai/AG/AgTurret.cpp index 823ab96b2..c5dba4a80 100644 --- a/dScripts/ai/AG/AgTurret.cpp +++ b/dScripts/ai/AG/AgTurret.cpp @@ -1,5 +1,6 @@ #include "AgTurret.h" #include "GameMessages.h" +#include "MovementMessages.h" void AgTurret::OnStartup(Entity* self) { // TODO: do this legit way @@ -13,5 +14,8 @@ void AgTurret::OnTimerDone(Entity* self, std::string timerName) { } void AgTurret::OnQuickBuildStart(Entity* self, Entity* user) { - GameMessages::SendLockNodeRotation(self, "base"); + GameMessages::LockNodeRotation lockNodeRotation; + lockNodeRotation.target = self->GetObjectID(); + lockNodeRotation.nodeName = "base"; + lockNodeRotation.Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp b/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp index 64bf5c968..9c7470f12 100644 --- a/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp +++ b/dScripts/ai/FV/FvConsoleLeftQuickbuild.cpp @@ -1,6 +1,7 @@ #include "FvConsoleLeftQuickbuild.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "eTerminateType.h" #include "eQuickBuildState.h" @@ -45,5 +46,5 @@ void FvConsoleLeftQuickbuild::OnUse(Entity* self, Entity* user) { } } - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp b/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp index 9703c3c42..f369ca995 100644 --- a/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp +++ b/dScripts/ai/FV/FvConsoleRightQuickbuild.cpp @@ -1,6 +1,7 @@ #include "FvConsoleRightQuickbuild.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "eTerminateType.h" #include "eQuickBuildState.h" @@ -45,5 +46,5 @@ void FvConsoleRightQuickbuild::OnUse(Entity* self, Entity* user) { } } - GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/FV/FvPandaSpawnerServer.cpp b/dScripts/ai/FV/FvPandaSpawnerServer.cpp index e02bcb553..f61890df6 100644 --- a/dScripts/ai/FV/FvPandaSpawnerServer.cpp +++ b/dScripts/ai/FV/FvPandaSpawnerServer.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "ObjectMessages.h" #include "EntityInfo.h" #include "ScriptedActivityComponent.h" @@ -21,16 +22,14 @@ void FvPandaSpawnerServer::OnCollisionPhantom(Entity* self, Entity* target) { // If the player already spawned a panda auto playerPandas = Game::entityManager->GetEntitiesInGroup("panda" + std::to_string(target->GetObjectID())); if (!playerPandas.empty()) { - GameMessages::SendFireEventClientSide(self->GetObjectID(), target->GetSystemAddress(), u"playerPanda", - target->GetObjectID(), 0, 0, target->GetObjectID()); + GameMessages::FireEventClientSide(self->GetObjectID(), u"playerPanda", target->GetObjectID(), target->GetObjectID()).SendToClient(target->GetSystemAddress()); return; } // If there's already too many spawned pandas auto pandas = Game::entityManager->GetEntitiesInGroup("pandas"); if (pandas.size() > 4) { - GameMessages::SendFireEventClientSide(self->GetObjectID(), target->GetSystemAddress(), u"tooManyPandas", - target->GetObjectID(), 0, 0, target->GetObjectID()); + GameMessages::FireEventClientSide(self->GetObjectID(), u"tooManyPandas", target->GetObjectID(), target->GetObjectID()).SendToClient(target->GetSystemAddress()); return; } diff --git a/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp index 00792dcfd..6d7c4bb2d 100644 --- a/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp +++ b/dScripts/ai/GENERAL/InstanceExitTransferPlayerToLastNonInstance.cpp @@ -1,6 +1,7 @@ #include "InstanceExitTransferPlayerToLastNonInstance.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "CharacterComponent.h" #include "Character.h" #include "dServer.h" @@ -50,7 +51,7 @@ void InstanceExitTransferPlayerToLastNonInstance::OnMessageBoxResponse(Entity* s } } - GameMessages::SendTerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()); + GameMessages::TerminateInteraction(sender->GetObjectID(), eTerminateType::FROM_INTERACTION, self->GetObjectID()).Send(UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 93a61eb93..2a889eb86 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -3,6 +3,7 @@ #include "GameMessages.h" #include "EffectsMessages.h" #include "ActivityMessages.h" +#include "MovementMessages.h" #include "dZoneManager.h" #include "Character.h" #include "ShootingGalleryComponent.h" @@ -19,6 +20,7 @@ #include "eGameActivity.h" #include "Item.h" #include +#include "BuildingMessages.h" void SGCannon::OnStartup(Entity* self) { LOG("OnStartup"); @@ -314,7 +316,7 @@ void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) { // Save the enemy and tell it to start pathing if (enemy != nullptr) { const_cast&>(self->GetVar>(SpawnedObjects)).push_back(enemy->GetObjectID()); - GameMessages::SendPlatformResync(enemy, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::PlatformResync(*enemy).Send(UNASSIGNED_SYSTEM_ADDRESS); } } } @@ -713,12 +715,13 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time UpdateStreak(self); - GameMessages::SendNotifyClientShootingGalleryScore(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS, - 0.0f, - score, - target->GetObjectID(), - target->GetPosition() - ); + GameMessages::NotifyClientShootingGalleryScore galleryScore; + galleryScore.target = self->GetObjectID(); + galleryScore.addTime = 0.0f; + galleryScore.score = score; + galleryScore.targetID = target->GetObjectID(); + galleryScore.targetPos = target->GetPosition(); + galleryScore.Send(UNASSIGNED_SYSTEM_ADDRESS); auto newScore = self->GetVar(TotalScoreVariable) + score; diff --git a/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp b/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp index 8f8906d38..39f7b7cea 100644 --- a/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp +++ b/dScripts/ai/NS/NS_PP_01/PropertyDeathPlane.cpp @@ -1,6 +1,7 @@ #include "PropertyDeathPlane.h" #include "Entity.h" #include "GameMessages.h" +#include "MovementMessages.h" #include "EntityManager.h" void PropertyDeathPlane::OnCollisionPhantom(Entity* self, Entity* target) { @@ -12,5 +13,5 @@ void PropertyDeathPlane::OnCollisionPhantom(Entity* self, Entity* target) { auto* teleport = teleportGroup[0]; - GameMessages::SendTeleport(target->GetObjectID(), teleport->GetPosition(), teleport->GetRotation(), target->GetSystemAddress()); + GameMessages::Teleport(target->GetObjectID(), teleport->GetPosition(), teleport->GetRotation()).SendToClient(target->GetSystemAddress()); } diff --git a/dScripts/ai/NS/NsConcertInstrument.cpp b/dScripts/ai/NS/NsConcertInstrument.cpp index 3f910ef37..2189fbd78 100644 --- a/dScripts/ai/NS/NsConcertInstrument.cpp +++ b/dScripts/ai/NS/NsConcertInstrument.cpp @@ -1,6 +1,8 @@ #include "NsConcertInstrument.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" #include "Item.h" #include "DestroyableComponent.h" #include "EntityManager.h" @@ -71,8 +73,7 @@ void NsConcertInstrument::OnTimerDone(Entity* self, std::string name) { } if (activePlayer != nullptr && name == "checkPlayer" && self->GetVar(u"beingPlayed")) { - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"checkMovement", 0, 0, - activePlayer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"checkMovement", 0, 0, activePlayer->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); auto* stats = activePlayer->GetComponent(); if (stats) { if (stats->GetImagination() > 0) { @@ -90,8 +91,7 @@ void NsConcertInstrument::OnTimerDone(Entity* self, std::string name) { } else if (name == "cleanupAfterStop") { if (activePlayer != nullptr) { UnEquipInstruments(self, activePlayer); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stopPlaying", 0, 0, - activePlayer->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"stopPlaying", 0, 0, activePlayer->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); } auto* quickBuildComponent = self->GetComponent(); @@ -120,8 +120,7 @@ void NsConcertInstrument::StartPlayingInstrument(Entity* self, Entity* player) { // Stuff to notify the player EquipInstruments(self, player); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"startPlaying", 0, 0, - player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(self->GetObjectID(), u"startPlaying", 0, 0, player->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); GameMessages::PlayCinematic cinematic; cinematic.target = player->GetObjectID(); cinematic.pathName = cinematics.at(instrumentLot); @@ -163,8 +162,7 @@ void NsConcertInstrument::StopPlayingInstrument(Entity* self, Entity* player) { 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); + GameMessages::NotifyClientObject(self->GetObjectID(), u"stopCheckingMovement", 0, 0, player->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); } self->SetVar(u"beingPlayed", false); @@ -288,7 +286,7 @@ void NsConcertInstrument::RepositionPlayer(Entity* self, Entity* player) { break; } - GameMessages::SendTeleport(player->GetObjectID(), position, rotation, player->GetSystemAddress()); + GameMessages::Teleport(player->GetObjectID(), position, rotation).SendToClient(player->GetSystemAddress()); } InstrumentLot NsConcertInstrument::GetInstrumentLot(Entity* self) { diff --git a/dScripts/ai/NS/NsQbImaginationStatue.cpp b/dScripts/ai/NS/NsQbImaginationStatue.cpp index 2a0b21077..35b79000e 100644 --- a/dScripts/ai/NS/NsQbImaginationStatue.cpp +++ b/dScripts/ai/NS/NsQbImaginationStatue.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "Loot.h" +#include "InventoryMessages.h" void NsQbImaginationStatue::OnStartup(Entity* self) { diff --git a/dScripts/ai/NS/WH/RockHydrantBroken.cpp b/dScripts/ai/NS/WH/RockHydrantBroken.cpp index 887254219..4eb435940 100644 --- a/dScripts/ai/NS/WH/RockHydrantBroken.cpp +++ b/dScripts/ai/NS/WH/RockHydrantBroken.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" void RockHydrantBroken::OnStartup(Entity* self) { self->AddTimer("playEffect", 1); @@ -20,7 +21,7 @@ void RockHydrantBroken::OnStartup(Entity* self) { msg.bActive = true; msg.Send(UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"enableCollision", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"enableCollision").Send(UNASSIGNED_SYSTEM_ADDRESS); } self->AddTimer("KillBroken", 10); @@ -36,7 +37,7 @@ void RockHydrantBroken::OnTimerDone(Entity* self, std::string timerName) { msg.bActive = false; msg.Send(UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendNotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyObject(bouncer->GetObjectID(), self->GetObjectID(), u"disableCollision").Send(UNASSIGNED_SYSTEM_ADDRESS); } self->Kill(); diff --git a/dScripts/ai/PROPERTY/AgPropguards.cpp b/dScripts/ai/PROPERTY/AgPropguards.cpp index 7d88c3790..bd69ead18 100644 --- a/dScripts/ai/PROPERTY/AgPropguards.cpp +++ b/dScripts/ai/PROPERTY/AgPropguards.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "GameMessages.h" #include "EffectsMessages.h" +#include "ObjectMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "eMissionState.h" @@ -25,8 +26,7 @@ void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int mission } else if (missionState == eMissionState::READY_TO_COMPLETE) { // Makes the guard disappear once the mission has been completed const auto zoneControlID = Game::entityManager->GetZoneControlEntity()->GetObjectID(); - GameMessages::SendNotifyClientObject(zoneControlID, u"GuardChat", 0, 0, self->GetObjectID(), - "", UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::NotifyClientObject(zoneControlID, u"GuardChat", 0, 0, self->GetObjectID(), "").Send(UNASSIGNED_SYSTEM_ADDRESS); self->AddCallbackTimer(5.0f, [self]() { auto spawnerName = self->GetVar(u"spawner_name"); diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 5be9e2885..86b6df697 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -103,6 +103,8 @@ #include "eFunnessTypes.h" #include "WorldMigration.h" #include "EffectsMessages.h" +#include "MovementMessages.h" +#include "ZoneMessages.h" namespace Game { Logger* logger = nullptr; @@ -990,7 +992,11 @@ void LoadPlayer(const SystemAddress& sysAddr) { Game::entityManager->ConstructEntity(player, UNASSIGNED_SYSTEM_ADDRESS); if (respawnPoint != NiPoint3Constant::ZERO) { - GameMessages::SendPlayerReachedRespawnCheckpoint(player, respawnPoint, QuatUtils::IDENTITY); + GameMessages::PlayerReachedRespawnCheckpoint respawnCheckpoint; + respawnCheckpoint.target = player->GetObjectID(); + respawnCheckpoint.pos = respawnPoint; + respawnCheckpoint.rot = QuatUtils::IDENTITY; + respawnCheckpoint.SendToClient(player->GetSystemAddress()); } Game::entityManager->ConstructAllEntities(sysAddr); @@ -1046,8 +1052,16 @@ void LoadPlayer(const SystemAddress& sysAddr) { noBBB: // Tell the client it's done loading: - GameMessages::SendInvalidZoneTransferList(player, sysAddr, GeneralUtils::ASCIIToUTF16(Game::config->GetValue("source")), u"", false, false); - GameMessages::SendServerDoneLoadingAllObjects(player, sysAddr); + GameMessages::InvalidZoneTransferList invalidTransferList; + invalidTransferList.target = player->GetObjectID(); + invalidTransferList.customerFeedbackURL = GeneralUtils::ASCIIToUTF16(Game::config->GetValue("source")); + invalidTransferList.invalidMapTransferList = u""; + invalidTransferList.bCustomerFeedbackOnExit = false; + invalidTransferList.bCustomerFeedbackOnInvalidMapTransfer = false; + invalidTransferList.SendToClient(sysAddr); + GameMessages::ServerDoneLoadingAllObjects doneLoading; + doneLoading.target = player->GetObjectID(); + doneLoading.SendToClient(sysAddr); //Send the player it's mail count: //update: this might not be needed so im going to try disabling this here. diff --git a/tests/dCommonTests/HeaderSkipTest.cpp b/tests/dCommonTests/HeaderSkipTest.cpp deleted file mode 100644 index a8f78078c..000000000 --- a/tests/dCommonTests/HeaderSkipTest.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#include "dCommonDependencies.h" -#include "dCommonVars.h" -#include "BitStream.h" - -#define PacketUniquePtr std::unique_ptr - -TEST(dCommonTests, HeaderSkipExcessTest) { - PacketUniquePtr packet = std::make_unique(); - unsigned char headerAndData[] = { 0x53, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 }; // positive - packet->data = headerAndData; - packet->length = sizeof(headerAndData); - CINSTREAM_SKIP_HEADER; - ASSERT_EQ(inStream.GetNumberOfUnreadBits(), 64); - ASSERT_EQ(inStream.GetNumberOfBitsAllocated(), 128); -} - -TEST(dCommonTests, HeaderSkipExactDataTest) { - PacketUniquePtr packet = std::make_unique(); - unsigned char header[] = { 0x53, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00 }; // positive - packet->data = header; - packet->length = sizeof(header); - CINSTREAM_SKIP_HEADER; - ASSERT_EQ(inStream.GetNumberOfUnreadBits(), 0); - ASSERT_EQ(inStream.GetNumberOfBitsAllocated(), 64); -} - -TEST(dCommonTests, HeaderSkipNotEnoughDataTest) { - PacketUniquePtr packet = std::make_unique(); - unsigned char notEnoughData[] = { 0x53, 0x02, 0x00, 0x07, 0x00, 0x00 }; // negative - packet->data = notEnoughData; - packet->length = sizeof(notEnoughData); - CINSTREAM_SKIP_HEADER; - ASSERT_EQ(inStream.GetNumberOfUnreadBits(), 0); - ASSERT_EQ(inStream.GetNumberOfBitsAllocated(), 48); -} diff --git a/tests/dGameTests/LegacyPacketMacros.h b/tests/dGameTests/LegacyPacketMacros.h new file mode 100644 index 000000000..6c1d89670 --- /dev/null +++ b/tests/dGameTests/LegacyPacketMacros.h @@ -0,0 +1,41 @@ +#ifndef LEGACYPACKETMACROS_H +#define LEGACYPACKETMACROS_H + +// FROZEN - DO NOT EDIT. +// The packet macros and the free BitStreamUtils::WriteHeader the hand written packet code used (dCommonVars.h and +// dNet/BitStreamUtils.h before the struct conversion). They were removed from the server once every packet became a +// struct; the frozen oracles in the Legacy/ folders still use them, verbatim. + +#include "BitStream.h" +#include "BitStreamUtils.h" +#include "Game.h" +#include "MessageIdentifiers.h" +#include "MessageType/Client.h" +#include "ServiceType.h" +#include "dServer.h" + +#ifndef HEADER_SIZE +#define HEADER_SIZE 8 +#endif +#ifndef CBITSTREAM +#define CBITSTREAM RakNet::BitStream bitStream; +#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); +#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits()); +#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, ServiceType::CLIENT, MessageType::Client::GAME_MSG); +#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false); +#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); +#endif + +#ifndef BITSTREAMUTILS_HAS_WRITEHEADER +namespace BitStreamUtils { + template + void WriteHeader(RakNet::BitStream& bitStream, ServiceType connectionType, T internalPacketID) { + bitStream.Write(ID_USER_PACKET_ENUM); + bitStream.Write(connectionType); + bitStream.Write(static_cast(internalPacketID)); + bitStream.Write(0); + } +} +#endif + +#endif // LEGACYPACKETMACROS_H diff --git a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt index 551dc0637..561531b2a 100644 --- a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt +++ b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt @@ -10,6 +10,7 @@ SET(DGAMEMESSAGES_TESTS "PetMessagesTests.cpp" "PropertyMessagesTests.cpp" "RacingMessagesTests.cpp" + "RemainingMessagesTests.cpp" "SkillMessagesTests.cpp" "UnSmashTests.cpp" "VendorMessagesTests.cpp" diff --git a/tests/dGameTests/dGameMessagesTests/GameMsgSplitTests.cpp b/tests/dGameTests/dGameMessagesTests/GameMsgSplitTests.cpp index e4fc00a39..51d0a6bb6 100644 --- a/tests/dGameTests/dGameMessagesTests/GameMsgSplitTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/GameMsgSplitTests.cpp @@ -1,4 +1,5 @@ #include "GameMessages.h" +#include "InventoryMessages.h" #include "GameDependencies.h" #include "PacketTestUtils.h" #include "Entity.h" diff --git a/tests/dGameTests/dGameMessagesTests/Legacy/RemainingMessagesLegacy.h b/tests/dGameTests/dGameMessagesTests/Legacy/RemainingMessagesLegacy.h new file mode 100644 index 000000000..e80c009ce --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/Legacy/RemainingMessagesLegacy.h @@ -0,0 +1,1230 @@ +#ifndef REMAININGMESSAGESLEGACY_H +#define REMAININGMESSAGESLEGACY_H + +// FROZEN ORACLE - DO NOT EDIT. +// Verbatim copies of the last hand written GameMessages::Send* functions (dGame/dGameMessages/GameMessages.cpp) +// and WorldMigration's SendLocalizedAnnouncement, replaced by the Movement, Zone, Player, Script and QuickBuild +// message files and the rest of ActivityMessages. Only the namespace changed. The Read* functions are the read +// sequences of the replaced GameMessages::Handle* functions, verbatim up to the point where the handler starts +// using what it read. + +#include "LegacyPacketMacros.h" +#include "dCommonVars.h" +#include "dServer.h" +#include "Entity.h" +#include "Game.h" +#include "GameMessages.h" +#include "GeneralUtils.h" +#include "LeaderboardManager.h" +#include "MovementMessages.h" +#include "MessageType/Client.h" +#include "MessageType/Game.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" +#include "ServiceType.h" +#include "eControlScheme.h" +#include "eCyclingMode.h" +#include "eLootSourceType.h" +#include "eMatchUpdate.h" +#include "eMovementPlatformState.h" +#include "eObjectWorldState.h" +#include "eQuickBuildFailReason.h" +#include "eQuickBuildState.h" +#include "eTerminateType.h" +#include "eGameMasterLevel.h" + +#include + +namespace LegacyGameMessages { + inline void SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::FIRE_EVENT_CLIENT_SIDE); + + //bitStream.Write(args); + uint32_t argSize = args.size(); + bitStream.Write(argSize); + for (uint32_t k = 0; k < argSize; k++) { + bitStream.Write(args[k]); + } + bitStream.Write(object); + bitStream.Write0(); + //bitStream.Write(param1); + bitStream.Write0(); + //bitStream.Write(param2); + bitStream.Write(sender); + + SEND_PACKET; + } + + inline void SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::TELEPORT); + + bool bIgnoreY = (pos.y == 0.0f); + bool bUseNavmesh = false; + bool bSkipAllChecks = false; + //float w = 1.0f; + //float x = 0.0f; + //float y = 0.0f; + //float z = 0.0f; + + bitStream.Write(bIgnoreY); + bitStream.Write(bSetRotation); + bitStream.Write(bSkipAllChecks); + bitStream.Write(pos.x); + bitStream.Write(pos.y); + bitStream.Write(pos.z); + bitStream.Write(bUseNavmesh); + + bitStream.Write(rot.w != 1.0f); + if (rot.w != 1.0f) bitStream.Write(rot.w); + + bitStream.Write(rot.x); + bitStream.Write(rot.y); + bitStream.Write(rot.z); + + SEND_PACKET; + } + + inline void SendPlayerReady(Entity* entity, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLAYER_READY); + SEND_PACKET; + } + + inline void SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::INVALID_ZONE_TRANSFER_LIST); + + uint32_t CustomerFeedbackURLLength = feedbackURL.size(); + bitStream.Write(CustomerFeedbackURLLength); + for (uint32_t k = 0; k < CustomerFeedbackURLLength; k++) { + bitStream.Write(feedbackURL[k]); + } + + uint32_t InvalidMapTransferListLength = invalidMapTransferList.size(); + bitStream.Write(InvalidMapTransferListLength); + for (uint32_t k = 0; k < InvalidMapTransferListLength; k++) { + bitStream.Write(invalidMapTransferList[k]); + } + + bitStream.Write(feedbackOnExit); + bitStream.Write(feedbackOnInvalidTransfer); + + SEND_PACKET; + } + + inline void SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, const SystemAddress& sysAddr, + bool bAllowCyclingWhileDeadOnly, eCyclingMode cyclingMode) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::PLAYER_SET_CAMERA_CYCLING_MODE); + + bitStream.Write(bAllowCyclingWhileDeadOnly); + + bitStream.Write(cyclingMode != eCyclingMode::ALLOW_CYCLE_TEAMMATES); + if (cyclingMode != eCyclingMode::ALLOW_CYCLE_TEAMMATES) { + bitStream.Write(cyclingMode); + } + + SEND_PACKET; + } + + inline void SendStartPathing(Entity* entity) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::START_PATHING); + + SEND_PACKET_BROADCAST; + } + + inline void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint, + int iIndex, int iDesiredWaypointIndex, int nextIndex, + eMovementPlatformState movementState, bool special) { + CBITSTREAM; + CMSGHEADER; + + const auto objID = entity->GetObjectID(); + const auto lot = entity->GetLOT(); + + if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449 || lot == 11306 || lot == 11308 || lot == 9483) { + iDesiredWaypointIndex = (lot == 11306 || lot == 11308) ? 1 : 0; + iIndex = lot == 9483 ? 1 : 0; + nextIndex = lot == 9483 && !special ? 1 : 0; + bStopAtDesiredWaypoint = true; + movementState = lot == 9483 && !special ? eMovementPlatformState::Stopped : eMovementPlatformState::Stationary; + } + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLATFORM_RESYNC); + + bool bReverse = false; + int eCommand = 0; + int eUnexpectedCommand = 0; + float fIdleTimeElapsed = 0.0f; + float fMoveTimeElapsed = 0.0f; + float fPercentBetweenPoints = 0.0f; + NiPoint3 ptUnexpectedLocation = NiPoint3Constant::ZERO; + NiQuaternion qUnexpectedRotation = QuatUtils::IDENTITY; + + bitStream.Write(bReverse); + bitStream.Write(bStopAtDesiredWaypoint); + bitStream.Write(eCommand); + bitStream.Write(static_cast(movementState)); + bitStream.Write(eUnexpectedCommand); + bitStream.Write(fIdleTimeElapsed); + bitStream.Write(fMoveTimeElapsed); + bitStream.Write(fPercentBetweenPoints); + bitStream.Write(iDesiredWaypointIndex); + bitStream.Write(iIndex); + bitStream.Write(nextIndex); + bitStream.Write(ptUnexpectedLocation.x); + bitStream.Write(ptUnexpectedLocation.y); + bitStream.Write(ptUnexpectedLocation.z); + + bitStream.Write(qUnexpectedRotation != QuatUtils::IDENTITY); + if (qUnexpectedRotation != QuatUtils::IDENTITY) { + bitStream.Write(qUnexpectedRotation.x); + bitStream.Write(qUnexpectedRotation.y); + bitStream.Write(qUnexpectedRotation.z); + bitStream.Write(qUnexpectedRotation.w); + } + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::RESTORE_TO_POST_LOAD_STATS); + SEND_PACKET; + } + + inline void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SERVER_DONE_LOADING_ALL_OBJECTS); + SEND_PACKET; + } + + inline void SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::UPDATE_CHAT_MODE); + bitStream.Write(level); + SEND_PACKET_BROADCAST; + } + + inline void SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::SET_GM_LEVEL); + bitStream.Write1(); + bitStream.Write(level); + SEND_PACKET_BROADCAST; + } + + inline void SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectWorldState state, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::CHANGE_OBJECT_WORLD_STATE); + bitStream.Write(state); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + SEND_PACKET; + } + + inline void SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::MODIFY_LEGO_SCORE); + bitStream.Write(score); + + bitStream.Write(sourceType != eLootSourceType::NONE); + if (sourceType != eLootSourceType::NONE) bitStream.Write(sourceType); + + SEND_PACKET; + } + + inline void SendSetCurrency(Entity* entity, int64_t currency, int lootType, const LWOOBJID& sourceID, const LOT& sourceLOT, int sourceTradeID, bool overrideCurrent, eLootSourceType sourceType) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SET_CURRENCY); + + bitStream.Write(currency); + + bitStream.Write(lootType != LOOTTYPE_NONE); + if (lootType != LOOTTYPE_NONE) bitStream.Write(lootType); + + bitStream.Write(NiPoint3Constant::ZERO); + + bitStream.Write(sourceLOT != LOT_NULL); + if (sourceLOT != LOT_NULL) bitStream.Write(sourceLOT); + + bitStream.Write(sourceID != LWOOBJID_EMPTY); + if (sourceID != LWOOBJID_EMPTY) bitStream.Write(sourceID); + + bitStream.Write(sourceTradeID != LWOOBJID_EMPTY); + if (sourceTradeID != LWOOBJID_EMPTY) bitStream.Write(sourceTradeID); + + bitStream.Write(sourceType != eLootSourceType::NONE); + if (sourceType != eLootSourceType::NONE) bitStream.Write(sourceType); + + SystemAddress sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + inline void SendQuickBuildNotifyState(Entity* entity, eQuickBuildState prevState, eQuickBuildState state, const LWOOBJID& playerID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::REBUILD_NOTIFY_STATE); + + bitStream.Write(prevState); + bitStream.Write(state); + bitStream.Write(playerID); + + SEND_PACKET_BROADCAST; + } + + inline void SendEnableQuickBuild(Entity* entity, bool enable, bool fail, bool success, eQuickBuildFailReason failReason, float duration, const LWOOBJID& playerID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::ENABLE_REBUILD); + + bitStream.Write(enable); + bitStream.Write(fail); + bitStream.Write(success); + + bitStream.Write(failReason != eQuickBuildFailReason::NOT_GIVEN); + if (failReason != eQuickBuildFailReason::NOT_GIVEN) bitStream.Write(failReason); + + bitStream.Write(duration); + bitStream.Write(playerID); + + SEND_PACKET_BROADCAST; + } + + inline void SendTerminateInteraction(const LWOOBJID& objectID, eTerminateType type, const LWOOBJID& terminator) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::TERMINATE_INTERACTION); + + bitStream.Write(terminator); + bitStream.Write(type); + + SEND_PACKET_BROADCAST; + } + + inline void 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) { + fAirspeed = 75; + fMaxAirspeed = 75; + fVertVel = 15; + } + */ + + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SET_JET_PACK_MODE); + + bitStream.Write(bypassChecks); + bitStream.Write(doHover); + bitStream.Write(use); + + bitStream.Write(effectID != -1); + if (effectID != -1) bitStream.Write(effectID); + + bitStream.Write(airspeed != 10); + if (airspeed != 10) bitStream.Write(airspeed); + + bitStream.Write(maxAirspeed != 15); + if (maxAirspeed != 15) bitStream.Write(maxAirspeed); + + bitStream.Write(verticalVelocity != 1); + if (verticalVelocity != 1) bitStream.Write(verticalVelocity); + + bitStream.Write(warningEffectID != -1); + if (warningEffectID != -1) bitStream.Write(warningEffectID); + + SEND_PACKET_BROADCAST; + } + + inline void SendSetNetworkScriptVar(Entity* entity, const SystemAddress& sysAddr, std::string data) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SCRIPT_NETWORK_VAR_UPDATE); + + // FIXME: this is a bad place to need to do a conversion because we have no clue whether data is utf8 or plain ascii + // an this has performance implications + const auto u16Data = GeneralUtils::ASCIIToUTF16(data); + uint32_t dataSize = static_cast(u16Data.size()); + + bitStream.Write(dataSize); + for (auto value : u16Data) { + bitStream.Write(value); + } + if (dataSize > 0) bitStream.Write(0); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendSetPlayerControlScheme(Entity* entity, eControlScheme controlScheme) { + CBITSTREAM; + CMSGHEADER; + + bool bDelayCamSwitchIfInCinematic = true; + bool bSwitchCam = true; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SET_PLAYER_CONTROL_SCHEME); + + bitStream.Write(bDelayCamSwitchIfInCinematic); + bitStream.Write(bSwitchCam); + + bitStream.Write(controlScheme != eControlScheme::SCHEME_A); + if (controlScheme != eControlScheme::SCHEME_A) bitStream.Write(controlScheme); + + SystemAddress sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + inline void SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPoint3& position, const NiQuaternion& rotation) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::PLAYER_REACHED_RESPAWN_CHECKPOINT); + + bitStream.Write(position.x); + bitStream.Write(position.y); + bitStream.Write(position.z); + + const bool bIsNotIdentity = rotation != QuatUtils::IDENTITY; + bitStream.Write(bIsNotIdentity); + + if (bIsNotIdentity) { + bitStream.Write(rotation.w); + bitStream.Write(rotation.x); + bitStream.Write(rotation.y); + bitStream.Write(rotation.z); + } + + SystemAddress sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + inline void SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::MATCH_RESPONSE); + bitStream.Write(response); + + SEND_PACKET; + } + + inline void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::MATCH_UPDATE); + bitStream.Write(data.size()); + for (char character : data) { + bitStream.Write(character); + } + if (data.size() > 0) bitStream.Write(0); + bitStream.Write(type); + + SEND_PACKET; + } + + inline void SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, + const SystemAddress& sysAddr, const int32_t& gameID, + const int32_t& queryType, const int32_t& resultsEnd, + const int32_t& resultsStart, bool weekly) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA); + + bitStream.Write(gameID != 0); + if (gameID != 0) { + bitStream.Write(gameID); + } + + bitStream.Write(queryType != 1); + if (queryType != 1) { + bitStream.Write(queryType); + } + + bitStream.Write(resultsEnd != 10); + if (resultsEnd != 10) { + bitStream.Write(resultsEnd); + } + + bitStream.Write(resultsStart != 0); + if (resultsStart != 0) { + bitStream.Write(resultsStart); + } + + bitStream.Write(targetID); + bitStream.Write(weekly); + + SEND_PACKET; + } + + inline void SendSetShootingGalleryParams(LWOOBJID objectId, const SystemAddress& sysAddr, + float cameraFOV, + float cooldown, + float minDistance, + NiPoint3 muzzlePosOffset, + NiPoint3 playerPosOffset, + float projectileVelocity, + float timeLimit, + bool bUseLeaderboards) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::SET_SHOOTING_GALLERY_PARAMS); + /* + bitStream.Write(cameraFOV); + bitStream.Write(cooldown); + bitStream.Write(minDistance); + bitStream.Write(muzzlePosOffset); + bitStream.Write(playerPosOffset); + bitStream.Write(projectileVelocity); + bitStream.Write(timeLimit); + bitStream.Write(bUseLeaderboards); + */ + // No clue about the order here + bitStream.Write(playerPosOffset); + bitStream.Write(projectileVelocity); + bitStream.Write(cooldown); + bitStream.Write(muzzlePosOffset); + bitStream.Write(minDistance); + bitStream.Write(cameraFOV); + bitStream.Write(bUseLeaderboards); + bitStream.Write(timeLimit); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const SystemAddress& sysAddr, + float addTime, + int32_t score, + LWOOBJID target, + NiPoint3 targetPos) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE); + bitStream.Write(addTime); + bitStream.Write(score); + bitStream.Write(target); + bitStream.Write(targetPos); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); + + leaderboard->Serialize(bitStream); + SEND_PACKET; + } + + inline void SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, + uint32_t pathStart, const SystemAddress& sysAddr, int32_t railActivatorComponentID, + LWOOBJID railActivatorObjectID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::SET_RAIL_MOVEMENT); + + bitStream.Write(pathGoForward); + + bitStream.Write(pathName.size()); + for (auto character : pathName) { + bitStream.Write(character); + } + + bitStream.Write(pathStart); + + const auto componentIDIsDefault = railActivatorComponentID == -1; + bitStream.Write(!componentIDIsDefault); + if (!componentIDIsDefault) + bitStream.Write(railActivatorComponentID); + + const auto activatorObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; + bitStream.Write(!activatorObjectIDIsDefault); + if (!activatorObjectIDIsDefault) + bitStream.Write(railActivatorObjectID); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendStartRailMovement(const LWOOBJID& objectID, std::u16string pathName, std::u16string startSound, + std::u16string loopSound, std::u16string stopSound, const SystemAddress& sysAddr, + uint32_t pathStart, bool goForward, bool damageImmune, bool noAggro, bool notifyActor, + bool showNameBillboard, bool cameraLocked, bool collisionEnabled, bool useDB, + int32_t railComponentID, LWOOBJID railActivatorObjectID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::START_RAIL_MOVEMENT); + + bitStream.Write(damageImmune); + bitStream.Write(noAggro); + bitStream.Write(notifyActor); + bitStream.Write(showNameBillboard); + bitStream.Write(cameraLocked); + bitStream.Write(collisionEnabled); + + bitStream.Write(loopSound.size()); + for (auto character : loopSound) { + bitStream.Write(character); + } + + bitStream.Write(goForward); + + bitStream.Write(pathName.size()); + for (auto character : pathName) { + bitStream.Write(character); + } + + const auto pathStartIsDefault = pathStart == 0; + bitStream.Write(!pathStartIsDefault); + if (!pathStartIsDefault) { + bitStream.Write(pathStart); + } + + const auto railComponentIDIsDefault = railComponentID == -1; + bitStream.Write(!railComponentIDIsDefault); + if (!railComponentIDIsDefault) { + bitStream.Write(railComponentID); + } + + const auto railObjectIDIsDefault = railActivatorObjectID == LWOOBJID_EMPTY; + bitStream.Write(!railObjectIDIsDefault); + if (!railObjectIDIsDefault) { + bitStream.Write(railActivatorObjectID); + } + + bitStream.Write(startSound.size()); + for (auto character : startSound) { + bitStream.Write(character); + } + + bitStream.Write(stopSound.size()); + for (auto character : stopSound) { + bitStream.Write(character); + } + + bitStream.Write(useDB); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendNotifyClientObject(const LWOOBJID& objectID, std::u16string name, int param1, int param2, const LWOOBJID& paramObj, std::string paramStr, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_OBJECT); + + bitStream.Write(name.size()); + for (auto character : name) { + bitStream.Write(character); + } + + bitStream.Write(param1); + + bitStream.Write(param2); + + bitStream.Write(paramObj); + + bitStream.Write(paramStr.size()); + for (auto character : paramStr) { + bitStream.Write(character); + } + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendNotifyClientZoneObject(const LWOOBJID& objectID, const std::u16string& name, int param1, + int param2, const LWOOBJID& paramObj, const std::string& paramStr, + const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_ZONE_OBJECT); + + bitStream.Write(name.size()); + for (const auto& character : name) { + bitStream.Write(character); + } + + bitStream.Write(param1); + bitStream.Write(param2); + bitStream.Write(paramObj); + + bitStream.Write(paramStr.size()); + for (const auto& character : paramStr) { + bitStream.Write(character); + } + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendNotifyClientFailedPrecondition(LWOOBJID objectId, const SystemAddress& sysAddr, + const std::u16string& failedReason, int preconditionID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_FAILED_PRECONDITION); + + bitStream.Write(failedReason.size()); + for (uint16_t character : failedReason) { + bitStream.Write(character); + } + + bitStream.Write(preconditionID); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendSetName(LWOOBJID objectID, std::u16string name, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectID); + bitStream.Write(MessageType::Game::SET_NAME); + + bitStream.Write(name.size()); + + for (size_t i = 0; i < name.size(); ++i) + bitStream.Write(name[i]); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendLockNodeRotation(Entity* entity, std::string nodeName) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::LOCK_NODE_ROTATION); + + bitStream.Write(nodeName.size()); + for (char character : nodeName) { + bitStream.Write(character); + } + + SEND_PACKET_BROADCAST; + } + + inline void SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::ORIENT_TO_ANGLE); + + bitStream.Write(bRelativeToCurrent); + bitStream.Write(fAngle); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1, int param2) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::NOTIFY_OBJECT); + + bitStream.Write(objIDSender); + bitStream.Write(name.size()); + for (const auto character : name) { + bitStream.Write(character); + } + + bitStream.Write(param1); + bitStream.Write(param2); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::TEAM_PICKUP_ITEM); + + bitStream.Write(lootID); + bitStream.Write(lootOwnerID); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::DISPLAY_ZONE_SUMMARY); + + bitStream.Write(isPropertyMap); + bitStream.Write(isZoneStart); + bitStream.Write(sender != LWOOBJID_EMPTY); + if (sender != LWOOBJID_EMPTY) bitStream.Write(sender); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; + } + + inline void SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SET_MOUNT_INVENTORY_ID); + bitStream.Write(objectID != LWOOBJID_EMPTY); + if (objectID != LWOOBJID_EMPTY) bitStream.Write(objectID); + + SEND_PACKET_BROADCAST; + } + + inline void SendUpdateReputation(const LWOOBJID objectId, const int64_t reputation, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::UPDATE_REPUTATION); + + bitStream.Write(reputation); + + SEND_PACKET; + } + + inline void SendSetGravityScale(const LWOOBJID& target, const float effectScale, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(target); + bitStream.Write(MessageType::Game::SET_GRAVITY_SCALE); + + bitStream.Write(effectScale); + + SEND_PACKET; + } + + inline void SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::FORCE_CAMERA_TARGET_CYCLE); + bitStream.Write(bForceCycling); + bitStream.Write(cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES); + if (cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES) bitStream.Write(cyclingMode); + bitStream.Write(optionalTargetID); + + auto sysAddr = entity->GetSystemAddress(); + SEND_PACKET; + } + + inline void WriteWString(RakNet::BitStream& bitStream, const std::u16string& text) { + bitStream.Write(text.size()); + for (const auto character : text) bitStream.Write(character); + } + + // LocalizedAnnouncementServerToSingleClient: the client looks both strings up in its locale (falling back to + // the text itself) and shows the announcement popup, like its own instance-lock warning did in live + inline void SendLocalizedAnnouncement(Entity* player, const std::u16string& body, const std::u16string& title) { + const auto& sysAddr = player->GetSystemAddress(); + CBITSTREAM; + CMSGHEADER; + bitStream.Write(player->GetObjectID()); + bitStream.Write(MessageType::Game::LOCALIZED_ANNOUNCEMENT_SERVER_TO_SINGLE_CLIENT); + bitStream.Write(0); // body parameters (LDF), none + bitStream.Write(false); // force open chat box + bitStream.Write(true); // show the announcement + bitStream.Write(true); // and put the text in chat + WriteWString(bitStream, body); + WriteWString(bitStream, title); + bitStream.Write(0); // title parameters (LDF), none + SEND_PACKET; + } + // Read sequences of the replaced GameMessages::Handle* functions. + struct LegacyLeaderboardRequest { int32_t gameID; Leaderboard::InfoType queryType; int32_t resultsEnd; int32_t resultsStart; LWOOBJID target; bool weekly; }; + inline LegacyLeaderboardRequest ReadRequestActivitySummaryLeaderboardData(RakNet::BitStream& inStream) { + int32_t gameID = 0; + if (inStream.ReadBit()) inStream.Read(gameID); + + Leaderboard::InfoType queryType = Leaderboard::InfoType::MyStanding; + if (inStream.ReadBit()) inStream.Read(queryType); + + int32_t resultsEnd = 10; + if (inStream.ReadBit()) inStream.Read(resultsEnd); + + int32_t resultsStart = 0; + if (inStream.ReadBit()) inStream.Read(resultsStart); + + LWOOBJID target{}; + inStream.Read(target); + + bool weekly = inStream.ReadBit(); + return { gameID, queryType, resultsEnd, resultsStart, target, weekly }; + } + + struct LegacyActivityStateChangeRequest { LWOOBJID objectID; int32_t value1; int32_t value2; std::u16string stringValue; }; + inline LegacyActivityStateChangeRequest ReadActivityStateChangeRequest(RakNet::BitStream& inStream) { + LWOOBJID objectID; + inStream.Read(objectID); + + int32_t value1; + inStream.Read(value1); + + int32_t value2; + inStream.Read(value2); + + uint32_t stringValueLength; + inStream.Read(stringValueLength); + + std::u16string stringValue; + for (uint32_t i = 0; i < stringValueLength; ++i) { + uint16_t character; + inStream.Read(character); + stringValue.push_back(character); + } + return { objectID, value1, value2, stringValue }; + } + + struct LegacyShootingGalleryRotation { float angle; NiPoint3 facing; NiPoint3 muzzlePos; }; + inline LegacyShootingGalleryRotation ReadUpdateShootingGalleryRotation(RakNet::BitStream& inStream) { + float angle = 0.0f; + NiPoint3 facing = NiPoint3Constant::ZERO; + NiPoint3 muzzlePos = NiPoint3Constant::ZERO; + inStream.Read(angle); + inStream.Read(facing); + inStream.Read(muzzlePos); + return { angle, facing, muzzlePos }; + } + + struct LegacyVerifyAck { bool bDifferent; std::string sBitStream; uint32_t uiHandle; }; + inline LegacyVerifyAck ReadVerifyAck(RakNet::BitStream& inStream) { + bool bDifferent; + std::string sBitStream; + uint32_t uiHandle = 0; + + bDifferent = inStream.ReadBit(); + + uint32_t sBitStreamLength = 0; + inStream.Read(sBitStreamLength); + if (sBitStreamLength > MAX_MESSAGE_LENGTH) return {}; + for (uint64_t k = 0; k < sBitStreamLength; k++) { + uint8_t character; + inStream.Read(character); + sBitStream.push_back(character); + } + + if (inStream.ReadBit()) { + inStream.Read(uiHandle); + } + return { bDifferent, sBitStream, uiHandle }; + } + + inline LWOOBJID ReadDismountComplete(RakNet::BitStream& inStream) { + // Get the objectID from the bitstream + LWOOBJID objectId{}; + inStream.Read(objectId); + return objectId; + } + + inline LWOOBJID ReadAcknowledgePossession(RakNet::BitStream& inStream) { + bool hasObjectId{}; + inStream.Read(hasObjectId); + LWOOBJID objectId{}; + if (hasObjectId) { + inStream.Read(objectId); + } + return objectId; + } + + inline bool ReadToggleGhostReferenceOverride(RakNet::BitStream& inStream) { + bool bOverride = false; + + inStream.Read(bOverride); + return bOverride; + } + + inline NiPoint3 ReadSetGhostReferencePosition(RakNet::BitStream& inStream) { + NiPoint3 position; + + inStream.Read(position); + return position; + } + + struct LegacyParseChatMessage { int iClientState; std::u16string wsString; }; + inline LegacyParseChatMessage ReadParseChatMessage(RakNet::BitStream& inStream) { + std::u16string wsString; + int iClientState; + inStream.Read(iClientState); + + uint32_t wsStringLength; + inStream.Read(wsStringLength); + + if (wsStringLength > MAX_MESSAGE_LENGTH) { + wsStringLength = MAX_MESSAGE_LENGTH; + } + + for (uint32_t i = 0; i < wsStringLength; ++i) { + uint16_t character; + inStream.Read(character); + wsString.push_back(character); + } + return { iClientState, wsString }; + } + + struct LegacyFireEventServerSide { std::u16string args; int param1; int param2; int param3; LWOOBJID senderID; }; + inline LegacyFireEventServerSide ReadFireEventServerSide(RakNet::BitStream& inStream) { + uint32_t argsLength{}; + std::u16string args{}; + bool param1IsDefault{}; + int param1 = -1; + bool param2IsDefault{}; + int param2 = -1; + bool param3IsDefault{}; + int param3 = -1; + LWOOBJID senderID{}; + + inStream.Read(argsLength); + if (argsLength > MAX_MESSAGE_LENGTH) return {}; + for (uint32_t i = 0; i < argsLength; ++i) { + uint16_t character; + inStream.Read(character); + args.push_back(character); + } + inStream.Read(param1IsDefault); + if (param1IsDefault) inStream.Read(param1); + inStream.Read(param2IsDefault); + if (param2IsDefault) inStream.Read(param2); + inStream.Read(param3IsDefault); + if (param3IsDefault) inStream.Read(param3); + inStream.Read(senderID); + return { args, param1, param2, param3, senderID }; + } + + struct LegacyQuickBuildCancel { bool bEarlyRelease; LWOOBJID userID; }; + inline LegacyQuickBuildCancel ReadQuickBuildCancel(RakNet::BitStream& inStream) { + bool bEarlyRelease; + LWOOBJID userID; + + inStream.Read(bEarlyRelease); + inStream.Read(userID); + return { bEarlyRelease, userID }; + } + + inline unsigned int ReadPickupCurrency(RakNet::BitStream& inStream) { + unsigned int currency; + inStream.Read(currency); + return currency; + } + + struct LegacyMatchRequest { LWOOBJID activator; std::string playerChoices; int type; int value; }; + inline LegacyMatchRequest ReadMatchRequest(RakNet::BitStream& inStream) { + LWOOBJID activator; + uint32_t playerChoicesLen; + std::string playerChoices; + int type; + int value; + + inStream.Read(activator); + inStream.Read(playerChoicesLen); + if (playerChoicesLen > MAX_MESSAGE_LENGTH) return {}; + for (uint32_t i = 0; i < playerChoicesLen; ++i) { + uint16_t character; + inStream.Read(character); + playerChoices.push_back(character); + } + if (playerChoicesLen > 0) { + uint16_t nullTerm; + inStream.Read(nullTerm); + } + inStream.Read(type); + inStream.Read(value); + return { activator, playerChoices, type, value }; + } + + struct LegacyBugReport { std::string body; std::string clientVersion; std::string otherPlayer; std::string selection; }; + inline LegacyBugReport ReadReportBug(RakNet::BitStream& inStream) { + LegacyBugReport reportInfo; + + //Reading: + uint32_t messageLength; + inStream.Read(messageLength); + + if (messageLength > MAX_MESSAGE_LENGTH) return {}; + + for (uint32_t i = 0; i < (messageLength); ++i) { + uint16_t character; + inStream.Read(character); + reportInfo.body.push_back(static_cast(character)); + } + + uint32_t clientVersionLength; + inStream.Read(clientVersionLength); + if (clientVersionLength > MAX_MESSAGE_LENGTH) return {}; + for (unsigned int k = 0; k < clientVersionLength; k++) { + unsigned char character; + inStream.Read(character); + reportInfo.clientVersion.push_back(character); + } + + uint32_t nOtherPlayerIDLength; + inStream.Read(nOtherPlayerIDLength); + if (nOtherPlayerIDLength > MAX_MESSAGE_LENGTH) return {}; + for (unsigned int k = 0; k < nOtherPlayerIDLength; k++) { + unsigned char character; + inStream.Read(character); + reportInfo.otherPlayer.push_back(character); + } + + uint32_t selectionLength; + inStream.Read(selectionLength); + if (selectionLength > MAX_MESSAGE_LENGTH) return {}; + for (unsigned int k = 0; k < selectionLength; k++) { + unsigned char character; + inStream.Read(character); + reportInfo.selection.push_back(character); + } + return reportInfo; + } + + inline bool ReadCancelRailMovement(RakNet::BitStream& inStream) { + const auto immediate = inStream.ReadBit(); + return immediate; + } + + struct LegacyRailArrived { std::u16string pathName; int32_t waypointNumber; }; + inline LegacyRailArrived ReadPlayerRailArrivedNotification(RakNet::BitStream& inStream) { + uint32_t pathNameLength; + inStream.Read(pathNameLength); + if (pathNameLength > MAX_MESSAGE_LENGTH) return {}; + std::u16string pathName; + for (auto k = 0; k < pathNameLength; k++) { + uint16_t c; + inStream.Read(c); + pathName.push_back(c); + } + + int32_t waypointNumber; + inStream.Read(waypointNumber); + return { pathName, waypointNumber }; + } + + struct LegacyZoneStatistic { bool set; std::u16string statisticsName; int32_t value; LWOMAPID zone; }; + inline LegacyZoneStatistic ReadModifyPlayerZoneStatistic(RakNet::BitStream& inStream) { + const auto set = inStream.ReadBit(); + const auto statisticsName = GeneralUtils::ReadWString(inStream); + + int32_t value; + if (inStream.ReadBit()) { + inStream.Read(value); + } else { + value = 0; + } + + LWOMAPID zone; + if (inStream.ReadBit()) { + inStream.Read(zone); + } else { + zone = LWOMAPID_INVALID; + } + return { set, statisticsName, value, zone }; + } + + struct LegacyPlayerStatistic { int32_t updateID; int64_t updateValue; }; + inline LegacyPlayerStatistic ReadUpdatePlayerStatistic(RakNet::BitStream& inStream) { + int32_t updateID; + inStream.Read(updateID); + + int64_t updateValue; + if (inStream.ReadBit()) { + inStream.Read(updateValue); + } else { + updateValue = 1; + } + return { updateID, updateValue }; + } + + inline LWOOBJID ReadZoneSummaryDismissed(RakNet::BitStream& inStream) { + LWOOBJID player_id; + inStream.Read(player_id); + return player_id; + } +} + +#endif // REMAININGMESSAGESLEGACY_H diff --git a/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp b/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp new file mode 100644 index 000000000..425073e74 --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp @@ -0,0 +1,724 @@ +#include "ActivityMessages.h" +#include "GameDependencies.h" +#include "GameMessageTestUtils.h" +#include "Legacy/RemainingMessagesLegacy.h" +#include "MovementMessages.h" +#include "ObjectMessages.h" +#include "PlayerMessages.h" +#include "QuickBuildMessages.h" +#include "ZoneMessages.h" + +#include +#include +#include +#include +#include + +#include + +// Byte equality of the movement, zone, player, object, quickbuild and remaining activity game messages with the +// frozen hand written functions they replaced (Legacy/RemainingMessagesLegacy.h). +using namespace GameMessageTestUtils; + +namespace { + const std::vector g_WStrings = { u"", u"ZonePlayer", u"é中", std::u16string(300, u'x') }; + const std::vector g_Strings = { "", "base", "\xff\x80z", std::string(300, 'y') }; + const std::vector g_Ids = { LWOOBJID_EMPTY, 0x1000000000000001LL, 0x0102030405060708LL }; + const std::vector g_Ints = { 0, -1, 1, 10, std::numeric_limits::max(), std::numeric_limits::min() }; + const std::vector g_Floats = { 0.0f, 1.0f, 10.0f, 15.0f, -2.5f }; + const std::vector g_Points = { NiPoint3Constant::ZERO, NiPoint3(1.0f, 0.0f, -3.5f), NiPoint3(-100.0f, 25.0f, 1e6f) }; + const std::vector g_Rotations = { QuatUtils::IDENTITY, NiQuaternion(0.5f, 0.5f, -0.5f, 0.5f), NiQuaternion(1.0f, 0.0f, 1.0f, 0.0f) }; + + bool Bit(uint32_t mask, int i) { return (mask >> i) & 1; } + + // Compares every packet (bytes, destination, broadcast flag) the legacy call and the struct send. + void ExpectSameSends(const std::function& legacySend, const std::function& structSend) { + const auto legacyPackets = Capture(legacySend); + const auto newPackets = Capture(structSend); + ASSERT_FALSE(legacyPackets.empty()); + ASSERT_EQ(newPackets.size(), 1); + for (const auto& legacyPacket : legacyPackets) EXPECT_PACKET_EQ(FromCapture(legacyPacket), FromCapture(newPackets[0])); + EXPECT_EQ(legacyPackets[0].broadcast, newPackets[0].broadcast); + EXPECT_EQ(legacyPackets[0].sysAddr, newPackets[0].sysAddr); + } + + // The broadcast-only legacy functions compared with Send(UNASSIGNED). + void ExpectSameAsLegacyBroadcast(const std::function& legacySend, const GameMessages::NetGameMsg& msg) { + ExpectSameSends(legacySend, [&] { msg.Send(UNASSIGNED_SYSTEM_ADDRESS); }); + } + + // Reads msg's payload with a legacy read sequence and checks it consumed every bit. + 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; + } +} + +class RemainingMessagesTests : public GameDependenciesTest { +protected: + void SetUp() override { SetUpDependencies(); } + void TearDown() override { TearDownDependencies(); } +}; + +// ---------------------------------------------------------------- Movement + +TEST_F(RemainingMessagesTests, TeleportMatchesLegacy) { + for (const auto target : g_Targets) { + for (const auto& pos : g_Points) { + for (const auto& rot : g_Rotations) { + for (const bool setRotation : { false, true }) { + GameMessages::Teleport msg(target, pos, rot, setRotation); + for (const auto& address : g_Addresses) { + ExpectSameSends([&] { LegacyGameMessages::SendTeleport(target, pos, rot, address, setRotation); }, [&] { msg.SendToClient(address); }); + } + const auto copy = RoundTrip(msg); + EXPECT_EQ(copy.pos, pos); + EXPECT_EQ(copy.bIgnoreY, pos.y == 0.0f); + } + } + } + } +} + +TEST_F(RemainingMessagesTests, StartPathingAndPlatformResyncMatchLegacy) { + for (const LOT lot : { 999, 12341, 9483, 11306, 6267 }) { + info.lot = lot; + Entity entity(0x1000000000000001LL, info); + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendStartPathing(&entity); }, [&] { GameMessages::StartPathing msg; msg.target = entity.GetObjectID(); return msg; }()); + for (uint32_t mask = 0; mask < 4; mask++) { + for (const auto state : { eMovementPlatformState::Moving, eMovementPlatformState::Stationary, eMovementPlatformState::Stopped }) { + for (const int32_t index : { 0, 1, 5 }) { + GameMessages::PlatformResync msg(entity, Bit(mask, 0), index, index + 1, index + 2, state, Bit(mask, 1)); + ExpectSameAsLegacy([&](const SystemAddress& address) { + LegacyGameMessages::SendPlatformResync(&entity, address, Bit(mask, 0), index, index + 1, index + 2, state, Bit(mask, 1)); + }, msg); + RoundTrip(msg); + } + } + } + } + GameMessages::PlatformResync rotated; + rotated.qUnexpectedRotation = NiQuaternion(0.5f, 0.5f, -0.5f, 0.5f); + const auto copy = RoundTrip(rotated); + EXPECT_EQ(copy.qUnexpectedRotation, rotated.qUnexpectedRotation); +} + +TEST_F(RemainingMessagesTests, SmallMovementMessagesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const float value : g_Floats) { + for (const bool relative : { false, true }) { + GameMessages::OrientToAngle orient; + orient.target = target; + orient.bRelativeToCurrent = relative; + orient.fAngle = value; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendOrientToAngle(target, relative, value, address); }, orient); + RoundTrip(orient); + } + GameMessages::SetGravityScale gravity; + gravity.target = target; + gravity.scale = value; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetGravityScale(target, value, address); }, gravity, SendMode::SendToClient); + RoundTrip(gravity); + } + for (const auto& name : g_Strings) { + GameMessages::LockNodeRotation lock; + lock.target = target; + lock.nodeName = name; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendLockNodeRotation(&entity, name); }, lock); + EXPECT_EQ(RoundTrip(lock).nodeName, name); + } + for (const auto id : g_Ids) { + GameMessages::SetMountInventoryID mount; + mount.target = target; + mount.inventoryMountID = id; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendSetMountInventoryID(&entity, id, UNASSIGNED_SYSTEM_ADDRESS); }, mount); + RoundTrip(mount); + } + for (const auto scheme : { eControlScheme::SCHEME_A, eControlScheme::SCHEME_D, static_cast(9) }) { + GameMessages::SetPlayerControlScheme msg; + msg.target = target; + msg.iScheme = scheme; + ExpectSameSends([&] { LegacyGameMessages::SendSetPlayerControlScheme(&entity, scheme); }, [&] { msg.SendToClient(entity.GetSystemAddress()); }); + RoundTrip(msg); + } + for (const auto& pos : g_Points) { + for (const auto& rot : g_Rotations) { + GameMessages::PlayerReachedRespawnCheckpoint msg; + msg.target = target; + msg.pos = pos; + msg.rot = rot; + ExpectSameSends([&] { LegacyGameMessages::SendPlayerReachedRespawnCheckpoint(&entity, pos, rot); }, [&] { msg.SendToClient(entity.GetSystemAddress()); }); + EXPECT_EQ(RoundTrip(msg).rot, rot); + } + } + for (const auto mode : { eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES, eCameraTargetCyclingMode::DISALLOW_CYCLING }) { + for (const auto id : g_Ids) { + for (const bool force : { false, true }) { + GameMessages::ForceCameraTargetCycle msg; + msg.target = target; + msg.bForceCycling = force; + msg.cyclingMode = mode; + msg.optionalTargetID = id; + ExpectSameSends([&] { LegacyGameMessages::SendForceCameraTargetCycle(&entity, force, mode, id); }, [&] { msg.SendToClient(entity.GetSystemAddress()); }); + RoundTrip(msg); + } + } + } + for (const auto mode : { eCyclingMode::ALLOW_CYCLE_TEAMMATES, eCyclingMode::DISALLOW_CYCLING }) { + for (const bool deadOnly : { false, true }) { + GameMessages::PlayerSetCameraCyclingMode msg; + msg.target = target; + msg.bAllowCyclingWhileDeadOnly = deadOnly; + msg.cyclingMode = mode; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendPlayerSetCameraCyclingMode(target, address, deadOnly, mode); }, msg, SendMode::SendToClient); + RoundTrip(msg); + } + } + } +} + +TEST_F(RemainingMessagesTests, SetJetPackModeMatchesLegacy) { + Entity entity(0x0102030405060708LL, info); + for (uint32_t mask = 0; mask < 8; mask++) { + for (const int32_t effect : { -1, 167 }) { + for (const float speed : g_Floats) { + for (const int32_t warning : { -1, 5 }) { + GameMessages::SetJetPackMode msg; + msg.target = entity.GetObjectID(); + msg.bUse = Bit(mask, 0); + msg.bBypassChecks = Bit(mask, 1); + msg.bDoHover = Bit(mask, 2); + msg.effectID = effect; + msg.fAirspeed = speed; + msg.fMaxAirspeed = speed; + msg.fVertVel = speed; + msg.iWarningEffectID = warning; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendSetJetPackMode(&entity, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2), effect, speed, speed, speed, warning); }, msg); + RoundTrip(msg); + } + } + } + } +} + +TEST_F(RemainingMessagesTests, RailMovementMatchesLegacy) { + for (const auto target : g_Targets) { + for (const auto& path : g_WStrings) { + for (const uint32_t start : { 0u, 3u }) { + for (const int32_t component : { -1, 0, 42 }) { + for (const auto activator : g_Ids) { + for (uint32_t mask = 0; mask < 2; mask++) { + GameMessages::SetRailMovement set; + set.target = target; + set.pathGoForward = Bit(mask, 0); + set.pathName = path; + set.pathStart = start; + set.railActivatorComponentID = component; + set.railActivatorObjectID = activator; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetRailMovement(target, Bit(mask, 0), path, start, address, component, activator); }, set); + EXPECT_EQ(RoundTrip(set).pathName, path); + } + for (uint32_t mask = 0; mask < 256; mask += 37) { + GameMessages::StartRailMovement msg; + msg.target = target; + msg.pathName = path; + msg.startSound = u"start"; + msg.loopSound = path; + msg.stopSound = u""; + msg.pathStart = start; + msg.goForward = Bit(mask, 0); + msg.bDamageImmune = Bit(mask, 1); + msg.bNoAggro = Bit(mask, 2); + msg.bNotifyActor = Bit(mask, 3); + msg.bShowNameBillboard = Bit(mask, 4); + msg.bCameraLocked = Bit(mask, 5); + msg.bCollisionEnabled = Bit(mask, 6); + msg.bUseDB = Bit(mask, 7); + msg.railActivatorComponentID = component; + msg.railActivatorObjectID = activator; + ExpectSameAsLegacy([&](const SystemAddress& address) { + LegacyGameMessages::SendStartRailMovement(target, path, u"start", path, u"", address, start, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2), + Bit(mask, 3), Bit(mask, 4), Bit(mask, 5), Bit(mask, 6), Bit(mask, 7), component, activator); + }, msg); + RoundTrip(msg); + } + } + } + } + } + } +} + +TEST_F(RemainingMessagesTests, InboundMovementMatchesLegacy) { + for (const auto id : g_Ids) { + GameMessages::DismountComplete dismount; + dismount.mountID = id; + EXPECT_EQ(ReadWithLegacy(dismount, LegacyGameMessages::ReadDismountComplete), id); + EXPECT_EQ(RoundTrip(dismount).mountID, id); + ExpectTruncatedFails(dismount); + + GameMessages::AcknowledgePossession ack; + ack.possessedObjID = id; + EXPECT_EQ(ReadWithLegacy(ack, LegacyGameMessages::ReadAcknowledgePossession), id); + EXPECT_EQ(RoundTrip(ack).possessedObjID, id); + ExpectTruncatedFails(ack); + } + for (const bool value : { false, true }) { + GameMessages::ToggleGhostReferenceOverride toggle; + toggle.bOverride = value; + EXPECT_EQ(ReadWithLegacy(toggle, LegacyGameMessages::ReadToggleGhostReferenceOverride), value); + ExpectTruncatedFails(toggle); + + GameMessages::CancelRailMovement cancel; + cancel.bImmediate = value; + EXPECT_EQ(ReadWithLegacy(cancel, LegacyGameMessages::ReadCancelRailMovement), value); + ExpectTruncatedFails(cancel); + } + for (const auto& pos : g_Points) { + GameMessages::SetGhostReferencePosition ghost; + ghost.pos = pos; + EXPECT_EQ(ReadWithLegacy(ghost, LegacyGameMessages::ReadSetGhostReferencePosition), pos); + ExpectTruncatedFails(ghost); + } + for (const auto& path : g_WStrings) { + for (const int32_t waypoint : g_Ints) { + GameMessages::PlayerRailArrivedNotification arrived; + arrived.pathName = path; + arrived.waypointNumber = waypoint; + const auto legacy = ReadWithLegacy(arrived, LegacyGameMessages::ReadPlayerRailArrivedNotification); + EXPECT_EQ(legacy.pathName, path); + EXPECT_EQ(legacy.waypointNumber, waypoint); + RoundTrip(arrived); + } + } +} + +// ---------------------------------------------------------------- Zone + +TEST_F(RemainingMessagesTests, ZoneMessagesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + GameMessages::PlayerReady ready; + ready.target = target; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendPlayerReady(&entity, address); }, ready, SendMode::SendToClient); + GameMessages::RestoreToPostLoadStats restore; + restore.target = target; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendRestoreToPostLoadStats(&entity, address); }, restore, SendMode::SendToClient); + GameMessages::ServerDoneLoadingAllObjects done; + done.target = target; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendServerDoneLoadingAllObjects(&entity, address); }, done, SendMode::SendToClient); + + for (const auto& url : g_WStrings) { + for (uint32_t mask = 0; mask < 4; mask++) { + GameMessages::InvalidZoneTransferList list; + list.target = target; + list.customerFeedbackURL = url; + list.invalidMapTransferList = u"1000,1001"; + list.bCustomerFeedbackOnExit = Bit(mask, 0); + list.bCustomerFeedbackOnInvalidMapTransfer = Bit(mask, 1); + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendInvalidZoneTransferList(&entity, address, url, u"1000,1001", Bit(mask, 0), Bit(mask, 1)); }, list, SendMode::SendToClient); + RoundTrip(list); + } + GameMessages::LocalizedAnnouncementServerToSingleClient announcement; + announcement.target = target; + announcement.body = url; + announcement.title = u"UI_TITLE"; + ExpectSameSends([&] { LegacyGameMessages::SendLocalizedAnnouncement(&entity, url, u"UI_TITLE"); }, [&] { announcement.SendToClient(entity.GetSystemAddress()); }); + EXPECT_EQ(RoundTrip(announcement).body, url); + } + for (const auto sender : g_Ids) { + for (uint32_t mask = 0; mask < 4; mask++) { + GameMessages::DisplayZoneSummary summary; + summary.target = target; + summary.isPropertyMap = Bit(mask, 0); + summary.isZoneStart = Bit(mask, 1); + summary.sender = sender; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendDisplayZoneSummary(target, address, Bit(mask, 0), Bit(mask, 1), sender); }, summary); + RoundTrip(summary); + } + GameMessages::ZoneSummaryDismissed dismissed; + dismissed.playerID = sender; + EXPECT_EQ(ReadWithLegacy(dismissed, LegacyGameMessages::ReadZoneSummaryDismissed), sender); + ExpectTruncatedFails(dismissed); + } + for (const auto state : { eObjectWorldState::INWORLD, eObjectWorldState::ATTACHED, eObjectWorldState::INVENTORY }) { + GameMessages::ChangeObjectWorldState msg; + msg.target = target; + msg.newState = state; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendChangeObjectWorldState(target, state, address); }, msg); + RoundTrip(msg); + } + } + // Name-value text: a null terminator follows non-empty text and is not counted. + GameMessages::LocalizedAnnouncementServerToSingleClient withParams; + withParams.bodyParams = u"name=0:Bob"; + withParams.titleParams = u"x=1:2"; + const auto copy = RoundTrip(withParams); + EXPECT_EQ(copy.bodyParams, withParams.bodyParams); + EXPECT_EQ(copy.titleParams, withParams.titleParams); + ExpectTruncatedFails(withParams); +} + +TEST_F(RemainingMessagesTests, ZoneGoldenBytes) { + GameMessages::DisplayZoneSummary summary; + summary.target = 0x0102030405060708LL; + summary.isZoneStart = true; + summary.sender = 0x1122334455667788LL; + // header 53 05 00 0c 00 00 00 00, target, msgId 1043 (u16), bits 0 1 1 then the sender + EXPECT_PACKET_EQ(FromHex("5305000c00000000" "0807060504030201" "1304" "710eeccaa886644220", 211), StructPacket(summary)); +} + +// ---------------------------------------------------------------- Player + +TEST_F(RemainingMessagesTests, PlayerMessagesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto level : { eGameMasterLevel::CIVILIAN, eGameMasterLevel::DEVELOPER, eGameMasterLevel::OPERATOR }) { + GameMessages::UpdateChatMode chat; + chat.target = target; + chat.level = level; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendChatModeUpdate(target, level); }, chat); + RoundTrip(chat); + GameMessages::SetGMLevel gm; + gm.target = target; + gm.level = level; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendGMLevelBroadcast(target, level); }, gm); + RoundTrip(gm); + } + for (const int64_t value : { 0LL, -5LL, 123456789012LL }) { + for (const auto source : { eLootSourceType::NONE, eLootSourceType::MISSION, eLootSourceType::PICKUP }) { + GameMessages::ModifyLEGOScore score; + score.target = target; + score.score = value; + score.sourceType = source; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendModifyLEGOScore(&entity, address, value, source); }, score, SendMode::SendToClient); + RoundTrip(score); + for (const int32_t smallValue : { 0, 7 }) { + GameMessages::SetCurrency currency; + currency.target = target; + currency.currency = value; + currency.lootType = smallValue; + currency.sourceID = smallValue; + currency.sourceLOT = smallValue; + currency.sourceTradeID = smallValue; + currency.sourceType = source; + ExpectSameSends([&] { LegacyGameMessages::SendSetCurrency(&entity, value, smallValue, smallValue, smallValue, smallValue, true, source); }, [&] { currency.SendToClient(entity.GetSystemAddress()); }); + RoundTrip(currency); + } + } + GameMessages::UpdateReputation reputation; + reputation.target = target; + reputation.reputation = value; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendUpdateReputation(target, value, address); }, reputation, SendMode::SendToClient); + RoundTrip(reputation); + } + } +} + +TEST_F(RemainingMessagesTests, InboundPlayerMessagesMatchLegacy) { + for (const uint32_t amount : { 0u, 1u, 0xffffffffu }) { + GameMessages::PickupCurrency pickup; + pickup.currency = amount; + EXPECT_EQ(ReadWithLegacy(pickup, LegacyGameMessages::ReadPickupCurrency), amount); + ExpectTruncatedFails(pickup); + } + for (const auto& name : g_WStrings) { + for (const int32_t value : g_Ints) { + for (const LWOMAPID zone : { LWOMAPID_INVALID, LWOMAPID{ 1100 } }) { + GameMessages::ModifyPlayerZoneStatistic stat; + stat.bSet = value > 0; + stat.statName = name; + stat.statValue = value; + stat.zoneID = zone; + const auto legacy = ReadWithLegacy(stat, LegacyGameMessages::ReadModifyPlayerZoneStatistic); + EXPECT_EQ(legacy.set, stat.bSet); + EXPECT_EQ(legacy.statisticsName, name); + EXPECT_EQ(legacy.value, value); + EXPECT_EQ(legacy.zone, zone); + RoundTrip(stat); + } + } + GameMessages::ParseChatMessage chat; + chat.iClientState = 3; + chat.wsString = name; + const auto legacyChat = ReadWithLegacy(chat, LegacyGameMessages::ReadParseChatMessage); + EXPECT_EQ(legacyChat.iClientState, 3); + EXPECT_EQ(legacyChat.wsString, name); + RoundTrip(chat); + + GameMessages::ReportBug report; + report.body = name; + report.clientVersion = "1.10.64"; + report.otherPlayerID = "0"; + report.selection = "selection"; + const auto legacyReport = ReadWithLegacy(report, LegacyGameMessages::ReadReportBug); + std::string narrowed; + for (const auto character : name) narrowed.push_back(static_cast(character)); + EXPECT_EQ(legacyReport.body, narrowed); + EXPECT_EQ(legacyReport.clientVersion, "1.10.64"); + EXPECT_EQ(legacyReport.otherPlayer, "0"); + EXPECT_EQ(legacyReport.selection, "selection"); + RoundTrip(report); + } + for (const int32_t id : g_Ints) { + for (const int64_t value : { int64_t{ 1 }, int64_t{ 0 }, int64_t{ -7 }, int64_t{ 1 } << 40 }) { + GameMessages::UpdatePlayerStatistic stat; + stat.updateID = id; + stat.updateValue = value; + const auto legacy = ReadWithLegacy(stat, LegacyGameMessages::ReadUpdatePlayerStatistic); + EXPECT_EQ(legacy.updateID, id); + EXPECT_EQ(legacy.updateValue, value); + ExpectTruncatedFails(stat); + } + } + for (const auto& bytes : g_Strings) { + for (const uint32_t handle : { 0u, 9u }) { + GameMessages::VerifyAck ack; + ack.bDifferent = handle != 0; + ack.sBitStream = bytes; + ack.uiHandle = handle; + const auto legacy = ReadWithLegacy(ack, LegacyGameMessages::ReadVerifyAck); + EXPECT_EQ(legacy.bDifferent, ack.bDifferent); + EXPECT_EQ(legacy.sBitStream, bytes); + EXPECT_EQ(legacy.uiHandle, handle); + RoundTrip(ack); + } + } +} + +// ---------------------------------------------------------------- Objects and scripts + +TEST_F(RemainingMessagesTests, NotifyMessagesMatchLegacy) { + for (const auto target : g_Targets) { + for (const auto& name : g_WStrings) { + for (const int32_t param : g_Ints) { + for (const auto& paramStr : g_Strings) { + GameMessages::NotifyClientObject notify(target, name, param, -param, target, paramStr); + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientObject(target, name, param, -param, target, paramStr, address); }, notify); + EXPECT_EQ(RoundTrip(notify).paramStr, paramStr); + GameMessages::NotifyClientZoneObject zoneNotify(target, name, param, -param, target, paramStr); + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientZoneObject(target, name, param, -param, target, paramStr, address); }, zoneNotify); + RoundTrip(zoneNotify); + } + GameMessages::NotifyObject notifyObject(target, 0x1000000000000001LL, name, param, param / 2); + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyObject(target, 0x1000000000000001LL, name, address, param, param / 2); }, notifyObject); + RoundTrip(notifyObject); + GameMessages::NotifyClientFailedPrecondition precondition; + precondition.target = target; + precondition.failedReason = name; + precondition.preconditionID = param; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientFailedPrecondition(target, address, name, param); }, precondition); + RoundTrip(precondition); + } + for (const auto object : g_Ids) { + // The old function never wrote param1 or param2 (both flags always 0), whatever it was given. + GameMessages::FireEventClientSide fire(target, name, object, 0x0102030405060708LL); + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendFireEventClientSide(target, address, name, object, 5, 6, 0x0102030405060708LL); }, fire, SendMode::SendToClient); + RoundTrip(fire); + } + GameMessages::SetName setName; + setName.target = target; + setName.name = name; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetName(target, name, address); }, setName); + RoundTrip(setName); + } + Entity entity(target, info); + for (const auto& data : g_Strings) { + GameMessages::ScriptNetworkVarUpdate scriptVar; + scriptVar.target = target; + scriptVar.tableOfVars = GeneralUtils::ASCIIToUTF16(data); + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendSetNetworkScriptVar(&entity, address, data); }, scriptVar); + RoundTrip(scriptVar); + } + for (const auto type : { eTerminateType::RANGE, eTerminateType::USER, eTerminateType::FROM_INTERACTION }) { + for (const auto terminator : g_Ids) { + GameMessages::TerminateInteraction terminate(target, type, terminator); + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendTerminateInteraction(target, type, terminator); }, terminate); + RoundTrip(terminate); + } + } + } +} + +TEST_F(RemainingMessagesTests, FireEventServerSideMatchesLegacy) { + for (const auto& args : g_WStrings) { + for (const int32_t param : g_Ints) { + for (const auto sender : g_Ids) { + GameMessages::FireEventServerSide fire; + fire.args = args; + fire.param1 = param; + fire.param2 = -1; + fire.param3 = param / 3; + fire.senderID = sender; + const auto legacy = ReadWithLegacy(fire, LegacyGameMessages::ReadFireEventServerSide); + EXPECT_EQ(legacy.args, args); + EXPECT_EQ(legacy.param1, param); + EXPECT_EQ(legacy.param2, -1); + EXPECT_EQ(legacy.param3, param / 3); + EXPECT_EQ(legacy.senderID, sender); + RoundTrip(fire); + } + } + } + GameMessages::FireEventServerSide fire; + fire.args = u"ZonePlayer"; + fire.param3 = 1100; + ExpectTruncatedFails(fire); +} + +// ---------------------------------------------------------------- Quickbuild + +TEST_F(RemainingMessagesTests, QuickBuildMessagesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const auto player : g_Ids) { + for (const auto state : { eQuickBuildState::OPEN, eQuickBuildState::COMPLETED, eQuickBuildState::BUILDING }) { + GameMessages::RebuildNotifyState notify; + notify.target = target; + notify.prevState = eQuickBuildState::RESETTING; + notify.state = state; + notify.player = player; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendQuickBuildNotifyState(&entity, eQuickBuildState::RESETTING, state, player); }, notify); + RoundTrip(notify); + } + for (uint32_t mask = 0; mask < 8; mask++) { + for (const auto reason : { eQuickBuildFailReason::NOT_GIVEN, eQuickBuildFailReason::CANCELED_EARLY, eQuickBuildFailReason::OUT_OF_IMAGINATION }) { + for (const float duration : g_Floats) { + GameMessages::EnableRebuild enable; + enable.target = target; + enable.bEnable = Bit(mask, 0); + enable.bFail = Bit(mask, 1); + enable.bSuccess = Bit(mask, 2); + enable.eFailReason = reason; + enable.fDuration = duration; + enable.user = player; + ExpectSameAsLegacyBroadcast([&] { LegacyGameMessages::SendEnableQuickBuild(&entity, Bit(mask, 0), Bit(mask, 1), Bit(mask, 2), reason, duration, player); }, enable); + RoundTrip(enable); + } + } + } + for (const bool early : { false, true }) { + GameMessages::RebuildCancel cancel; + cancel.bEarlyRelease = early; + cancel.userID = player; + const auto legacy = ReadWithLegacy(cancel, LegacyGameMessages::ReadQuickBuildCancel); + EXPECT_EQ(legacy.bEarlyRelease, early); + EXPECT_EQ(legacy.userID, player); + ExpectTruncatedFails(cancel); + } + } + } +} + +// ---------------------------------------------------------------- Activities + +TEST_F(RemainingMessagesTests, ActivityMessagesMatchLegacy) { + for (const auto target : g_Targets) { + Entity entity(target, info); + for (const int32_t value : g_Ints) { + GameMessages::MatchResponse response; + response.target = target; + response.response = value; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendMatchResponse(&entity, address, value); }, response, SendMode::SendToClient); + RoundTrip(response); + } + for (const auto& data : g_Strings) { + for (const auto type : { eMatchUpdate::PLAYER_ADDED, eMatchUpdate::PHASE_WAIT_READY }) { + GameMessages::MatchUpdate update; + update.target = target; + update.data = data; + update.type = type; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendMatchUpdate(&entity, address, data, type); }, update, SendMode::SendToClient); + EXPECT_EQ(RoundTrip(update).data, data); + + GameMessages::MatchRequest request; + request.activator = target; + request.playerChoices = data; + request.type = 1; + request.value = static_cast(type); + const auto legacy = ReadWithLegacy(request, LegacyGameMessages::ReadMatchRequest); + EXPECT_EQ(legacy.activator, target); + EXPECT_EQ(legacy.playerChoices, data); + EXPECT_EQ(legacy.type, 1); + EXPECT_EQ(legacy.value, request.value); + RoundTrip(request); + } + } + for (const auto& pos : g_Points) { + for (const int32_t score : { 0, 1500, -1 }) { + GameMessages::NotifyClientShootingGalleryScore galleryScore; + galleryScore.target = target; + galleryScore.addTime = 2.5f; + galleryScore.score = score; + galleryScore.targetID = 0x1000000000000001LL; + galleryScore.targetPos = pos; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendNotifyClientShootingGalleryScore(target, address, 2.5f, score, 0x1000000000000001LL, pos); }, galleryScore); + RoundTrip(galleryScore); + } + GameMessages::UpdateShootingGalleryRotation rotation; + rotation.angle = 1.25f; + rotation.facing = pos; + rotation.muzzlePos = NiPoint3(1.0f, 2.0f, 3.0f); + const auto legacy = ReadWithLegacy(rotation, LegacyGameMessages::ReadUpdateShootingGalleryRotation); + EXPECT_EQ(legacy.angle, 1.25f); + EXPECT_EQ(legacy.facing, pos); + EXPECT_EQ(legacy.muzzlePos, rotation.muzzlePos); + ExpectTruncatedFails(rotation); + } + for (const auto& text : g_WStrings) { + GameMessages::ActivityStateChangeRequest change; + change.objectID = target; + change.value1 = 4; + change.value2 = -4; + change.stringValue = text; + const auto legacy = ReadWithLegacy(change, LegacyGameMessages::ReadActivityStateChangeRequest); + EXPECT_EQ(legacy.objectID, target); + EXPECT_EQ(legacy.value1, 4); + EXPECT_EQ(legacy.value2, -4); + EXPECT_EQ(legacy.stringValue, text); + RoundTrip(change); + } + } +} + +TEST_F(RemainingMessagesTests, LeaderboardMessagesMatchLegacy) { + for (const int32_t gameID : { 0, 1864 }) { + for (const int32_t queryType : { 0, 1, 2 }) { + for (const int32_t end : { 10, 0 }) { + for (const int32_t start : { 0, 5 }) { + for (const bool weekly : { false, true }) { + GameMessages::RequestActivitySummaryLeaderboardData msg; + msg.target = 0x0102030405060708LL; + msg.gameID = gameID; + msg.queryType = queryType; + msg.resultsEnd = end; + msg.resultsStart = start; + msg.weekly = weekly; + msg.targetID = 0x0102030405060708LL; + ExpectSameAsLegacy([&](const SystemAddress& address) { + LegacyGameMessages::SendRequestActivitySummaryLeaderboardData(0x0102030405060708LL, 0x0102030405060708LL, address, gameID, queryType, end, start, weekly); + }, msg, SendMode::SendToClient); + const auto legacy = ReadWithLegacy(msg, LegacyGameMessages::ReadRequestActivitySummaryLeaderboardData); + EXPECT_EQ(legacy.gameID, gameID); + EXPECT_EQ(static_cast(legacy.queryType), queryType); + EXPECT_EQ(legacy.resultsEnd, end); + EXPECT_EQ(legacy.resultsStart, start); + EXPECT_EQ(legacy.weekly, weekly); + RoundTrip(msg); + } + } + } + } + } + Leaderboard leaderboard(1864, Leaderboard::InfoType::Top, false, 0x1000000000000001LL, 10, Leaderboard::Type::ShootingGallery); + GameMessages::SendActivitySummaryLeaderboardData data; + data.target = 0x1000000000000001LL; + data.leaderboard = &leaderboard; + ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendActivitySummaryLeaderboardData(0x1000000000000001LL, &leaderboard, address); }, data, SendMode::SendToClient); +}