diff --git a/dGame/dGameMessages/MovementMessages.cpp b/dGame/dGameMessages/MovementMessages.cpp index cede9c002..2056430fd 100644 --- a/dGame/dGameMessages/MovementMessages.cpp +++ b/dGame/dGameMessages/MovementMessages.cpp @@ -50,26 +50,6 @@ namespace GameMessages { 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); @@ -121,21 +101,18 @@ namespace GameMessages { } void RequestPlatformResync::Handle(Entity& entity, const SystemAddress& sysAddr) { - // A mover answers with where the server has it (live: travelling 2 with its percent and position, or 25 at a - // waypoint with the time waited) + // A mover answers with where the server has it (live: travelling 2 with its percent and position, or waiting at + // a waypoint with the time waited) auto* const platform = entity.GetComponent(); - if (platform && platform->IsMover()) { - PlatformResync resync; - resync.target = entity.GetObjectID(); - platform->FillResync(resync); - resync.Send(sysAddr); + if (!platform || !platform->IsMover()) { + // Nothing else has waypoints to resync to: the client's simple mover reads them from its own two point path + // (LWOPlatformSimpleMover::Resync 0x00bf9ec0, a crash without one) and would set off on a travelling state return; } - // A platform without a path has no waypoints to resync to; the client's simple mover reads them anyway and - // crashes (LWOPlatformSimpleMover::Resync 0x00bf9ec0 -> Path::GetWaypointAtIndex on a null path) - if (platform && !platform->HasPath()) return; - if (entity.GetLOT() == 6267 || entity.GetLOT() == 16141) return; - PlatformResync(entity).Send(sysAddr); + PlatformResync resync; + resync.target = entity.GetObjectID(); + platform->FillResync(resync); + resync.Send(sysAddr); } void OrientToAngle::Serialize(RakNet::BitStream& bitStream) const { diff --git a/dGame/dGameMessages/MovementMessages.h b/dGame/dGameMessages/MovementMessages.h index a1a8524e4..11ad03097 100644 --- a/dGame/dGameMessages/MovementMessages.h +++ b/dGame/dGameMessages/MovementMessages.h @@ -49,11 +49,6 @@ namespace GameMessages { // 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; diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 2a889eb86..b7172380d 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -11,6 +11,7 @@ #include "CharacterComponent.h" #include "SimplePhysicsComponent.h" #include "MovementAIComponent.h" +#include "MovingPlatformComponent.h" #include "MissionComponent.h" #include "Loot.h" #include "InventoryComponent.h" @@ -295,7 +296,17 @@ void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) { auto* enemy = Game::entityManager->CreateEntity(info, nullptr, self); - auto* movementAI = enemy->AddComponent(-1, MovementAIInfo{}); + // sg_cannon.lua (onChildLoaded): a moving platform target gets SetPathingSpeed, which nothing on a moving platform + // reads, and SetCurrentPath{ pathName, startPoint = 0 }: its mover runs the path at the waypoints' speeds, as the + // client's does. Live constructed these targets with the path and the mover waiting at waypoint 0 (9), and + // serialized the mover at each waypoint. The other targets follow their waypoints. + auto* const movingPlatform = toSpawn.isMovingPlatform ? enemy->GetComponent() : nullptr; + MovementAIComponent* movementAI = nullptr; + if (movingPlatform) { + movingPlatform->SetCurrentPath(path->pathName, 0); + } else { + movementAI = enemy->AddComponent(-1, MovementAIInfo{}); + } auto* simplePhysicsComponent = enemy->GetComponent(); if (simplePhysicsComponent) { simplePhysicsComponent->SetPhysicsMotionState(4); @@ -303,20 +314,21 @@ void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) { Game::entityManager->ConstructEntity(enemy); - movementAI->SetMaxSpeed(toSpawn.initialSpeed); - movementAI->SetCurrentSpeed(toSpawn.initialSpeed); - movementAI->SetHaltDistance(0.0f); + if (movementAI) { + movementAI->SetMaxSpeed(toSpawn.initialSpeed); + movementAI->SetCurrentSpeed(toSpawn.initialSpeed); + movementAI->SetHaltDistance(0.0f); - movementAI->SetPath(path->pathWaypoints); + movementAI->SetPath(path->pathWaypoints); + } enemy->AddDieCallback([this, self, enemy, name]() { RegisterHit(self, enemy, name); }); - // Save the enemy and tell it to start pathing + // Save the enemy if (enemy != nullptr) { const_cast&>(self->GetVar>(SpawnedObjects)).push_back(enemy->GetObjectID()); - GameMessages::PlatformResync(*enemy).Send(UNASSIGNED_SYSTEM_ADDRESS); } } } @@ -1104,22 +1116,14 @@ std::vector> SGCannon::GetWaves() { 1.0, false, true }, - // Ness temp fix for dlu where speeds are set to 7 to match a speed closer to live while we work on movingplatform components. + // Ness { std::vector { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" }, 2565, 10.0, 15.0, true, 10.0, 15.0, - 7.0, 10000, false, 0.0, 7.0, - 7.0, true, true + 2.0, 10000, false, 0.0, 1.0, + 1.0, true, true }, - // // Ness - // { - // std::vector { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" }, - // 2565, 10.0, 15.0, true, 10.0, 15.0, - // 2.0, 10000, false, 0.0, 1.0, - // 1.0, true, true - // }, - // Friendly 1 { std::vector { "Wave_3_FShip_1", "Wave_3_FShip_2" }, diff --git a/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp b/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp index accbdf551..307adb6c9 100644 --- a/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/RemainingMessagesTests.cpp @@ -89,14 +89,21 @@ TEST_F(RemainingMessagesTests, TeleportMatchesLegacy) { } TEST_F(RemainingMessagesTests, StartPathingAndPlatformResyncMatchLegacy) { - for (const LOT lot : { 999, 12341, 9483, 11306, 6267 }) { + // The legacy sender overrode its arguments for a few LOTs; the message has no such cases, so only others compare + for (const LOT lot : { 999, 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)); + GameMessages::PlatformResync msg; + msg.target = entity.GetObjectID(); + msg.bStopAtDesiredWaypoint = Bit(mask, 0); + msg.iIndex = index; + msg.iDesiredWaypointIndex = index + 1; + msg.iNextIndex = index + 2; + msg.eState = state; ExpectSameAsLegacy([&](const SystemAddress& address) { LegacyGameMessages::SendPlatformResync(&entity, address, Bit(mask, 0), index, index + 1, index + 2, state, Bit(mask, 1)); }, msg);