mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-15 08:17:13 +00:00
fix(moving platform): a simple mover without a quick build sets off when it is loaded
A simple mover is a LWOPlatform like a mover: made stopped at its waypoint (12) and, unless startPathingOnLoad is false, waiting there (9) for the shortest wait before it leaves for its other end (ResumeTravelling 0x00c86b90, SetWaitingTime 0x00bdc860, RunPlatform 0x00c86e10). Live showed it on the NJ counterweights, which wait for their quick build first; one without a quick build was left waiting for a script here. The client only reads startPathingOnLoad (LWOMovingPlatformComponent:: LoadConfigData 0x00d0f690) and never starts a platform by itself, so the rule is the server's, taken from what live did with movers (12 with the setting false, else 9 and off) and from the scripts: L_NJ_SPINNER_SERVER stops its platform when it starts up, simple movers included, and the simple movers that wait for an event without that script all have startPathingOnLoad 0 in the maps. The wait now runs in the component for both, in place of the timer a built counterweight got, and a simple mover with startPathingOnLoad false is constructed stopped (12). Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -157,6 +157,18 @@ void MovingPlatformComponent::LoadConfigData() {
|
||||
if (m_Parent->HasVar(u"platformMoveTime")) simpleMover->mMoveTime = m_Parent->GetVar<float>(u"platformMoveTime");
|
||||
}
|
||||
simpleMover->mCurrentWaypointIndex = simpleMover->mStartAtEnd ? 1 : 0;
|
||||
|
||||
// As a mover on its path (LWOPlatform::ResumeTravelling 0x00c86b90 and SetWaitingTime 0x00bdc860): unless
|
||||
// startPathingOnLoad is false it waits at its waypoint (9), for the shortest wait as its waypoints have none.
|
||||
// Live's scripts for the NJ spinners, which are simple movers that only move when used, stop them when they
|
||||
// start up (L_NJ_SPINNER_SERVER: StopPathing), and the simple movers that wait for an event without such a script
|
||||
// have startPathingOnLoad 0.
|
||||
const bool startOnLoad = !m_Parent->HasVar(u"startPathingOnLoad") || m_Parent->GetVar<bool>(u"startPathingOnLoad");
|
||||
if (startOnLoad) {
|
||||
simpleMover->mState = ePlatformStateFlag::Waiting | ePlatformStateFlag::ReachedDesiredWaypoint;
|
||||
simpleMover->mTimeToWait = 0.1f;
|
||||
simpleMover->mWaitSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto pathName = GeneralUtils::UTF16ToWTF8(m_PathName);
|
||||
@@ -313,17 +325,8 @@ void MovingPlatformComponent::OnCompleteQuickBuild() {
|
||||
// about 0.1 s later travelling (2) to its other end, where it stops without a serialization and
|
||||
// PlatformAtLastWaypoint tells the scripts. It is the client's LWOPlatform at work: active once its quick build
|
||||
// is complete (SendMessage 0x00bdc930), it waits the shortest wait (SetWaitingTime 0x00bdc860) and sets off
|
||||
// (RunPlatform 0x00c86e10).
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
simpleMover->mDirtyState = true;
|
||||
const bool startOnLoad = !m_Parent->HasVar(u"startPathingOnLoad") || m_Parent->GetVar<bool>(u"startPathingOnLoad");
|
||||
if (!startOnLoad || (simpleMover->mState & ePlatformStateFlag::Travelling) != 0) return;
|
||||
const auto generation = ++m_MoveGeneration;
|
||||
m_Parent->AddCallbackTimer(0.1f, [this, generation] {
|
||||
if (generation != m_MoveGeneration) return;
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
if (simpleMover) SimpleMoverGotoWaypoint(simpleMover->mCurrentWaypointIndex == 0 ? 1 : 0);
|
||||
});
|
||||
// (RunPlatform 0x00c86e10): RunSimpleMover.
|
||||
GetSimpleMoverSubComponent()->mDirtyState = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -694,6 +697,20 @@ NiPoint3 CalcRotatorAngularVelocity(const float rotX, const float rotY, const fl
|
||||
return NiPoint3(q[0] * scale, q[1] * scale, q[2] * scale);
|
||||
}
|
||||
|
||||
// LWOPlatform::RunPlatform 0x00c86e10 for a simple mover waiting at its waypoint: once the wait is over it sets off for
|
||||
// its other end (LWOPlatform::IncrementWaitingTime 0x00bd4370, StartTravelling 0x0058b170). A quick build's does not
|
||||
// run until it is built (LWOPlatform::SendMessage 0x00bdc930). Live: a built counterweight was serialized waiting (9)
|
||||
// and about 0.1 s later travelling (2).
|
||||
void MovingPlatformComponent::RunSimpleMover(const float deltaTime) {
|
||||
auto* const simpleMover = GetSimpleMoverSubComponent();
|
||||
if (!UpdateActive(*simpleMover)) return;
|
||||
if ((simpleMover->mState & ePlatformStateFlag::Waiting) == 0 || !simpleMover->mWaitSet) return;
|
||||
simpleMover->mIdleTimeElapsed += deltaTime;
|
||||
if (simpleMover->mIdleTimeElapsed < simpleMover->mTimeToWait) return;
|
||||
simpleMover->mIdleTimeElapsed = 0.0f;
|
||||
SimpleMoverGotoWaypoint(simpleMover->mCurrentWaypointIndex == 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
// LWOPlatform::RunPlatform 0x00c86e10 for a rotator: its wait never ends (IncrementWaitingTime 0x004a0390) and it never
|
||||
// arrives (HandleStoppedLogic 0x00bdc660 keeps the object's angular velocity at the rotator's); it has no linear
|
||||
// velocity (SetLinearVelocity 0x00bd1660). The client's physics turn the object at that velocity; the server turns its
|
||||
@@ -735,6 +752,10 @@ void MovingPlatformComponent::Run(const float deltaTime) {
|
||||
RunRotator(deltaTime);
|
||||
return;
|
||||
}
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
RunSimpleMover(deltaTime);
|
||||
return;
|
||||
}
|
||||
if (!IsMover()) return;
|
||||
auto* mover = GetMoverSubComponent();
|
||||
UpdateActive(*mover);
|
||||
|
||||
@@ -171,12 +171,12 @@ public:
|
||||
/**
|
||||
* A simple mover (5), as the client's LWOPlatformSimpleMover: between a start point and that point moved by
|
||||
* platformMove (in the start rotation), taking platformMoveTime seconds, as GenerateSimpleMoverPath builds its two
|
||||
* waypoint path. At an end it has stopped there (28), as any platform on a path run once.
|
||||
* waypoint path. At an end it has stopped there (28), as any platform on a path run once. Like a mover it is made
|
||||
* stopped at its waypoint (12) and, unless startPathingOnLoad is false, waits there (9, as live constructed the NJ
|
||||
* counterweights) the shortest wait before it sets off for its other end, a quick build's once it is built.
|
||||
*/
|
||||
class SimpleMoverSubComponent final : public PlatformSubComponent {
|
||||
public:
|
||||
// Live constructed the NJ counterweights waiting at their waypoint (9)
|
||||
SimpleMoverSubComponent() { mState = ePlatformStateFlag::Waiting | ePlatformStateFlag::ReachedDesiredWaypoint; }
|
||||
eMoverSubComponentType GetType() const override { return eMoverSubComponentType::simpleMover; }
|
||||
|
||||
// LWOPlatformSimpleMover::Deserialize: a dirty bit, then whether there is a starting point with its position and
|
||||
@@ -369,6 +369,8 @@ private:
|
||||
void SetupMoverPath();
|
||||
// Puts the object where the mover is, without a serialization of its physics
|
||||
void MoveObject();
|
||||
// A simple mover's wait at its waypoint before it sets off by itself
|
||||
void RunSimpleMover(float deltaTime);
|
||||
// A rotator's settings from the level config, and where it is on its path
|
||||
void SetupRotator();
|
||||
// Turns a travelling rotator's object by its angular velocity
|
||||
|
||||
@@ -575,3 +575,50 @@ TEST_F(MovingPlatformComponentTest, MoverKeepsItsVelocityThroughAWaitLikeLive) {
|
||||
EXPECT_EQ(mover->mPosition, NiPoint3(30.0f, 0.0f, 30.0f));
|
||||
EXPECT_EQ(entity.GetPosition(), NiPoint3(30.0f, 0.0f, 30.0f));
|
||||
}
|
||||
|
||||
// A simple mover without a quick build runs from when it is loaded, as a mover does: waiting at its waypoint (9) for the
|
||||
// shortest wait, then off to its other end, where it has stopped (28). With startPathingOnLoad false it stays as it was
|
||||
// made (12), and so does one its script stops when it starts up (live's NJ spinner script, L_NJ_SPINNER_SERVER).
|
||||
TEST_F(MovingPlatformComponentTest, SimpleMoverSetsOffOnLoadUnlessToldNotTo) {
|
||||
info.lot = 16141;
|
||||
info.pos = NiPoint3(10.0f, 20.0f, 30.0f);
|
||||
info.rot = QuatUtils::IDENTITY;
|
||||
{
|
||||
Entity entity(288300744895900115, info);
|
||||
entity.AddComponent<SimplePhysicsComponent>(-1);
|
||||
auto* const platform = entity.AddComponent<MovingPlatformComponent>(41, "");
|
||||
auto* const mover = platform->GetSimpleMoverSubComponent();
|
||||
EXPECT_EQ(mover->mState, 9u);
|
||||
entity.Update(0.05f);
|
||||
EXPECT_EQ(mover->mState, 9u);
|
||||
entity.Update(0.06f);
|
||||
EXPECT_EQ(mover->mState, 2u);
|
||||
entity.Update(0.0f);
|
||||
entity.Update(1.1f);
|
||||
EXPECT_EQ(mover->mState, 28u);
|
||||
EXPECT_EQ(mover->mCurrentWaypointIndex, 1u);
|
||||
// Stopped at its end it does not set off again by itself
|
||||
entity.Update(1.0f);
|
||||
EXPECT_EQ(mover->mState, 28u);
|
||||
}
|
||||
{
|
||||
Entity entity(288300744895900116, info);
|
||||
auto* const platform = entity.AddComponent<MovingPlatformComponent>(41, "");
|
||||
auto* const mover = platform->GetSimpleMoverSubComponent();
|
||||
platform->StopPathing();
|
||||
EXPECT_EQ(mover->mState, 12u);
|
||||
entity.Update(1.0f);
|
||||
EXPECT_EQ(mover->mState, 12u);
|
||||
EXPECT_EQ(mover->mCurrentWaypointIndex, 0u);
|
||||
}
|
||||
{
|
||||
info.settings.Insert<bool>(u"startPathingOnLoad", false);
|
||||
Entity entity(288300744895900117, info);
|
||||
info.settings.values.clear();
|
||||
auto* const platform = entity.AddComponent<MovingPlatformComponent>(41, "");
|
||||
auto* const mover = platform->GetSimpleMoverSubComponent();
|
||||
EXPECT_EQ(mover->mState, 12u);
|
||||
entity.Update(1.0f);
|
||||
EXPECT_EQ(mover->mState, 12u);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user