Implement clientless transports, Lua reload and same-map portals

Add native transport recording and execution with grid lifecycle handling, clientless teleport acknowledgements, and regression tests. Support targeted same-map portal imports and preserve disabled taxi nodes. Document live transport and portal verification and the remaining portal inventory.
This commit is contained in:
Nico committed 2026-10-26 11:27:56 +01:00
1 parent 01a9ba4b0b
commit 1164a72ea3
40 files changed
+4533 -163

No files matched your search

@@ -49,6 +49,7 @@
#include <G3D/Box.h>
#include <G3D/CoordinateFrame.h>
#include <G3D/Quat.h>
#include <limits>
bool QuaternionData::isUnit() const
{
@@ -330,6 +331,54 @@ public:
}
}
bool GetTransportDockState(TransportDockState& state) const override
{
state = {};
if (!_animationInfo || !_animationInfo->TotalTime)
return false;
state.Progress = _pathProgress;
state.Period = _animationInfo->TotalTime;
if (!_stopFrames.empty())
{
if (int32(GameTime::GetGameTimeMS() - _owner.GetUInt32Value(GAMEOBJECT_LEVEL)) >= 0)
{
state.Stopped = true;
state.RemainingPause = std::numeric_limits<uint32>::max();
}
return true;
}
auto current = _animationInfo->Path.upper_bound(_pathProgress);
if (current == _animationInfo->Path.begin())
return true;
--current;
auto next = std::next(current);
// Consecutive equal animation positions represent an actual dwell,
// unlike a GO state which may already denote a future destination.
auto samePosition = [](TransportAnimationEntry const* a, TransportAnimationEntry const* b)
{
return std::fabs(a->Pos.X - b->Pos.X) < 0.001f &&
std::fabs(a->Pos.Y - b->Pos.Y) < 0.001f && std::fabs(a->Pos.Z - b->Pos.Z) < 0.001f;
};
while (next != _animationInfo->Path.end() && samePosition(current->second, next->second))
++next;
uint32 end = next == std::next(current) ? _pathProgress :
std::prev(next)->first;
// A stationary origin with a rotating deck is not a boarding stop.
auto rotation = _animationInfo->Rotations.upper_bound(_pathProgress);
if (rotation != _animationInfo->Rotations.begin() && rotation != _animationInfo->Rotations.end())
{
auto before = std::prev(rotation)->second;
auto after = rotation->second;
if (std::fabs(before->X - after->X) + std::fabs(before->Y - after->Y) +
std::fabs(before->Z - after->Z) + std::fabs(before->W - after->W) > 0.001f)
return true;
end = std::min(end, rotation->first);
}
state.Stopped = end > _pathProgress;
state.RemainingPause = state.Stopped ? end - _pathProgress : 0;
return true;
}
uint32 GetTransportPeriod() const
{
if (_animationInfo)
@@ -2963,6 +3012,14 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t
data->append(fieldBuffer);
}
bool GameObject::GetTransportDockState(TransportDockState& state) const
{
state = {};
if (Transport const* transport = ToTransport())
return transport->GetDockState(state);
return m_goTypeImpl && m_goTypeImpl->GetTransportDockState(state);
}
std::vector<uint32> const* GameObject::GetPauseTimes() const
{
if (GameObjectType::Transport const* transport = dynamic_cast<GameObjectType::Transport const*>(m_goTypeImpl.get()))