Core/Transports

* Fixed transport orientation
* Fixed transport position desynchronization for stoppable transports
* Ignore spawnMask errors for objects spawned on transports
This commit is contained in:
Shauren
2013-12-29 14:59:06 +01:00
parent 9af36d887b
commit 079905e29a
10 changed files with 124 additions and 99 deletions
@@ -397,6 +397,9 @@ bool BattlegroundIC::SetupBattleground()
return false;
}
gunshipHorde->EnableMovement(false);
gunshipAlliance->EnableMovement(false);
// setting correct factions for Keep Cannons
for (uint8 i = BG_IC_NPC_KEEP_CANNON_1; i < BG_IC_NPC_KEEP_CANNON_12; ++i)
GetBGCreature(i)->setFaction(BG_IC_Factions[0]);
@@ -90,8 +90,7 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa
SetPeriod(tInfo->pathTime);
SetEntry(goinfo->entry);
SetDisplayId(goinfo->displayId);
SetGoState(GO_STATE_READY);
_pendingStop = goinfo->moTransport.canBeStopped != 0;
SetGoState(!goinfo->moTransport.canBeStopped ? GO_STATE_READY : GO_STATE_ACTIVE);
SetGoType(GAMEOBJECT_TYPE_MO_TRANSPORT);
SetGoAnimProgress(animprogress);
SetName(goinfo->name);
@@ -111,7 +110,8 @@ void Transport::Update(uint32 diff)
if (GetKeyFrames().size() <= 1)
return;
m_goValue.Transport.PathProgress += diff;
if (IsMoving() || !_pendingStop)
m_goValue.Transport.PathProgress += diff;
uint32 timer = m_goValue.Transport.PathProgress % GetPeriod();
@@ -132,31 +132,23 @@ void Transport::Update(uint32 diff)
if (timer < _currentFrame->DepartureTime)
{
SetMoving(false);
if (_pendingStop)
if (_pendingStop && GetGoState() != GO_STATE_READY)
{
SetGoState(GO_STATE_READY);
m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod());
m_goValue.Transport.PathProgress *= GetPeriod();
m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
}
break; // its a stop frame and we are waiting
}
}
if (_pendingStop && timer >= _currentFrame->DepartureTime && GetGoState() == GO_STATE_READY)
{
m_goValue.Transport.PathProgress = (m_goValue.Transport.PathProgress / GetPeriod());
m_goValue.Transport.PathProgress *= GetPeriod();
m_goValue.Transport.PathProgress += _currentFrame->ArriveTime;
break;
}
if (timer >= _currentFrame->DepartureTime && !_triggeredDepartureEvent)
{
DoEventIfAny(*_currentFrame, true); // departure event
_triggeredDepartureEvent = true;
}
if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime)
break; // found current waypoint
MoveToNextWaypoint();
// not waiting anymore
SetMoving(true);
@@ -164,13 +156,18 @@ void Transport::Update(uint32 diff)
if (GetGOInfo()->moTransport.canBeStopped)
SetGoState(GO_STATE_ACTIVE);
if (timer >= _currentFrame->DepartureTime && timer < _currentFrame->NextArriveTime)
break; // found current waypoint
MoveToNextWaypoint();
sScriptMgr->OnRelocate(this, _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
TC_LOG_DEBUG("entities.transport", "Transport %u (%s) moved to node %u %u %f %f %f", GetEntry(), GetName().c_str(), _currentFrame->Node->index, _currentFrame->Node->mapid, _currentFrame->Node->x, _currentFrame->Node->y, _currentFrame->Node->z);
// Departure event
if (_currentFrame->IsTeleportFrame())
if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z))
if (TeleportTransport(_nextFrame->Node->mapid, _nextFrame->Node->x, _nextFrame->Node->y, _nextFrame->Node->z, _nextFrame->InitialOrientation))
return; // Update more in new map thread
}
@@ -185,7 +182,18 @@ void Transport::Update(uint32 diff)
G3D::Vector3 pos, dir;
_currentFrame->Spline->evaluate_percent(_currentFrame->Index, t, pos);
_currentFrame->Spline->evaluate_derivative(_currentFrame->Index, t, dir);
UpdatePosition(pos.x, pos.y, pos.z, atan2(dir.x, dir.y));
UpdatePosition(pos.x, pos.y, pos.z, atan2(dir.y, dir.x) + M_PI);
}
else
{
/* There are four possible scenarios that trigger loading/unloading passengers:
1. transport moves from inactive to active grid
2. the grid that transport is currently in becomes active
3. transport moves from active to inactive grid
4. the grid that transport is currently in unloads
*/
if (_staticPassengers.empty() && GetMap()->IsGridLoaded(GetPositionX(), GetPositionY())) // 2.
LoadStaticPassengers();
}
}
@@ -314,7 +322,7 @@ void Transport::UpdatePosition(float x, float y, float z, float o)
3. transport moves from active to inactive grid
4. the grid that transport is currently in unloads
*/
if (_staticPassengers.empty() && newActive) // 1. and 2.
if (_staticPassengers.empty() && newActive) // 1.
LoadStaticPassengers();
else if (!_staticPassengers.empty() && !newActive && Cell(x, y).DiffGrid(Cell(GetPositionX(), GetPositionY()))) // 3.
UnloadStaticPassengers();
@@ -404,7 +412,7 @@ float Transport::CalculateSegmentPos(float now)
return segmentPos / frame.NextDistFromPrev;
}
bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, float o)
{
Map const* oldMap = GetMap();
@@ -421,7 +429,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
float destX, destY, destZ, destO;
obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, GetOrientation());
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
switch (obj->GetTypeId())
{
@@ -447,7 +455,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
}
}
Relocate(x, y, z, GetOrientation());
Relocate(x, y, z, o);
GetMap()->AddToMap<Transport>(this);
return true;
}
@@ -460,13 +468,13 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z)
{
float destX, destY, destZ, destO;
(*itr)->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, GetOrientation());
TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o);
(*itr)->ToUnit()->NearTeleportTo(destX, destY, destZ, destO);
}
}
UpdatePosition(x, y, z, GetOrientation());
UpdatePosition(x, y, z, o);
return false;
}
}
@@ -78,7 +78,7 @@ class Transport : public GameObject, public TransportBase
private:
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
bool TeleportTransport(uint32 newMapid, float x, float y, float z);
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
void UpdatePassengerPositions(std::set<WorldObject*>& passengers);
void DoEventIfAny(KeyFrame const& node, bool departure);
+5 -2
View File
@@ -1601,7 +1601,8 @@ void ObjectMgr::LoadCreatures()
continue;
}
if (data.spawnMask & ~spawnMasks[data.mapid])
// Skip spawnMask check for transport maps
if (!_transportMaps.count(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid])
TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).", guid, data.spawnMask, data.mapid);
bool ok = true;
@@ -1936,7 +1937,7 @@ void ObjectMgr::LoadGameobjects()
data.spawnMask = fields[14].GetUInt8();
if (data.spawnMask & ~spawnMasks[data.mapid])
if (!_transportMaps.count(data.mapid) && data.spawnMask & ~spawnMasks[data.mapid])
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) that has wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid);
data.phaseMask = fields[15].GetUInt32();
@@ -6480,6 +6481,8 @@ void ObjectMgr::LoadGameObjectTemplate()
TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
entry, got.type, got.moTransport.taxiPathId, got.moTransport.taxiPathId);
}
if (uint32 transportMap = got.moTransport.mapID)
_transportMaps.insert(transportMap);
break;
}
case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18
+2
View File
@@ -1384,6 +1384,8 @@ class ObjectMgr
GO_TO_GO,
GO_TO_CREATURE // GO is dependant on creature
};
std::set<uint32> _transportMaps; // Helper container storing map ids that are for transports only, loaded from gameobject_template
};
#define sObjectMgr ACE_Singleton<ObjectMgr, ACE_Null_Mutex>::instance()
+73 -68
View File
@@ -87,28 +87,60 @@ void TransportMgr::LoadTransportTemplates()
TC_LOG_INFO("server.loading", ">> Loaded %u transport templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
class SplineRawInitializer
{
public:
SplineRawInitializer(Movement::PointsArray& points) : _points(points) { }
void operator()(uint8& mode, bool& cyclic, Movement::PointsArray& points, int& lo, int& hi) const
{
mode = Movement::SplineBase::ModeCatmullrom;
cyclic = false;
points.assign(_points.begin(), _points.end());
lo = 1;
hi = points.size();
}
Movement::PointsArray& _points;
};
void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport)
{
uint32 pathId = goInfo->moTransport.taxiPathId;
TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathId];
std::vector<KeyFrame>& keyFrames = transport->keyFrames;
Movement::PointsArray splinePath;
Movement::PointsArray splinePath, allPoints;
bool mapChange = false;
bool cyclic = true;
for (size_t i = 0; i < path.size(); ++i)
allPoints.push_back(G3D::Vector3(path[i].x, path[i].y, path[i].z));
// Add extra points to allow derivative calculations for all path nodes
allPoints.insert(allPoints.begin(), allPoints.front().lerp(allPoints[1], -0.2f));
allPoints.push_back(allPoints.back().lerp(allPoints[allPoints.size() - 2], -0.2f));
allPoints.push_back(allPoints.back().lerp(allPoints[allPoints.size() - 2], -1.0f));
SplineRawInitializer initer(allPoints);
TransportSpline orientationSpline;
orientationSpline.init_spline_custom(initer);
orientationSpline.initLengths();
for (size_t i = 0; i < path.size(); ++i)
{
if (!mapChange)
{
TaxiPathNodeEntry const& node_i = path[i];
if (i != path.size() - 1 && (node_i.actionFlag == 1 || node_i.mapid != path[i + 1].mapid))
if (i != path.size() - 1 && (node_i.actionFlag & 1 || node_i.mapid != path[i + 1].mapid))
{
cyclic = false;
keyFrames.back().Teleport = true;
mapChange = true;
}
else
{
KeyFrame k(node_i);
G3D::Vector3 h;
orientationSpline.evaluate_derivative(i + 1, 0.0f, h);
k.InitialOrientation = Position::NormalizeOrientation(atan2(h.y, h.x) + M_PI);
keyFrames.push_back(k);
splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z));
transport->mapsUsed.insert(k.Node->mapid);
@@ -118,16 +150,15 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
mapChange = false;
}
// Not sure if data8 means the transport can be stopped or that its path in dbc does not contain extra spline points
if (!goInfo->moTransport.canBeStopped && splinePath.size() >= 2)
if (splinePath.size() >= 2)
{
// Remove special catmull-rom spline points
splinePath.erase(splinePath.begin());
keyFrames.erase(keyFrames.begin());
splinePath.pop_back();
keyFrames.pop_back();
// Cyclic spline has one more extra point
if (cyclic && !splinePath.empty())
if (!keyFrames.front().IsStopFrame() && !keyFrames.front().Node->arrivalEventID && !keyFrames.front().Node->departureEventID)
{
splinePath.erase(splinePath.begin());
keyFrames.erase(keyFrames.begin());
}
if (!keyFrames.back().IsStopFrame() && !keyFrames.back().Node->arrivalEventID && !keyFrames.back().Node->departureEventID)
{
splinePath.pop_back();
keyFrames.pop_back();
@@ -170,67 +201,41 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
// find the rest of the distances between key points
// Every path segment has its own spline
if (cyclic)
size_t start = 0;
for (size_t i = 1; i < keyFrames.size(); ++i)
{
TransportSpline* spline = new TransportSpline();
spline->init_cyclic_spline(&splinePath[0], splinePath.size(), Movement::SplineBase::ModeCatmullrom, 0);
spline->initLengths();
keyFrames[0].DistFromPrev = spline->length(spline->last() - 2, spline->last() - 1);
keyFrames[0].Spline = spline;
for (size_t i = 0; i < keyFrames.size(); ++i)
if (keyFrames[i - 1].Teleport || i + 1 == keyFrames.size())
{
keyFrames[i].Index = i + 1;
keyFrames[i].DistFromPrev = spline->length(i, i + 1);
if (i > 0)
keyFrames[i - 1].NextDistFromPrev = keyFrames[i].DistFromPrev;
keyFrames[i].Spline = spline;
if (keyFrames[i].IsStopFrame())
size_t extra = !keyFrames[i - 1].Teleport ? 1 : 0;
TransportSpline* spline = new TransportSpline();
spline->init_spline(&splinePath[start], i - start + extra, Movement::SplineBase::ModeCatmullrom);
spline->initLengths();
for (size_t j = start; j < i + extra; ++j)
{
// remember first stop frame
if (firstStop == -1)
firstStop = i;
lastStop = i;
keyFrames[j].Index = j - start + 1;
keyFrames[j].DistFromPrev = spline->length(j - start, j + 1 - start);
if (j > 0)
keyFrames[j - 1].NextDistFromPrev = keyFrames[j].DistFromPrev;
keyFrames[j].Spline = spline;
}
if (keyFrames[i - 1].Teleport)
{
keyFrames[i].Index = i - start + 1;
keyFrames[i].DistFromPrev = 0.0f;
keyFrames[i - 1].NextDistFromPrev = 0.0f;
keyFrames[i].Spline = spline;
}
start = i;
}
}
else
{
size_t start = 0;
for (size_t i = 1; i < keyFrames.size(); ++i)
if (keyFrames[i].IsStopFrame())
{
if (keyFrames[i - 1].Teleport || i + 1 == keyFrames.size())
{
size_t extra = !keyFrames[i - 1].Teleport ? 1 : 0;
TransportSpline* spline = new TransportSpline();
spline->init_spline(&splinePath[start], i - start + extra, Movement::SplineBase::ModeCatmullrom);
spline->initLengths();
for (size_t j = start; j < i + extra; ++j)
{
keyFrames[j].Index = j - start + 1;
keyFrames[j].DistFromPrev = spline->length(j - start, j + 1 - start);
if (j > 0)
keyFrames[j - 1].NextDistFromPrev = keyFrames[j].DistFromPrev;
keyFrames[j].Spline = spline;
}
if (keyFrames[i - 1].Teleport)
{
keyFrames[i].Index = i - start + 1;
keyFrames[i].DistFromPrev = 0.0f;
keyFrames[i - 1].NextDistFromPrev = 0.0f;
keyFrames[i].Spline = spline;
}
start = i;
}
if (keyFrames[i].IsStopFrame())
{
// remember first stop frame
if (firstStop == -1)
firstStop = i;
lastStop = i;
}
// remember first stop frame
if (firstStop == -1)
firstStop = i;
lastStop = i;
}
}
@@ -373,7 +378,7 @@ Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map*
float x = startNode->x;
float y = startNode->y;
float z = startNode->z;
float o = 0.0f;
float o = tInfo->keyFrames.begin()->InitialOrientation;
// initialize the gameobject base
uint32 guidLow = guid ? guid : sObjectMgr->GenerateLowGuid(HIGHGUID_MO_TRANSPORT);
+2 -1
View File
@@ -38,7 +38,7 @@ typedef UNORDERED_MAP<uint32, std::set<uint32> > TransportInstanceMap;
struct KeyFrame
{
explicit KeyFrame(TaxiPathNodeEntry const& _node) : Index(0), Node(&_node),
explicit KeyFrame(TaxiPathNodeEntry const& _node) : Index(0), Node(&_node), InitialOrientation(0.0f),
DistSinceStop(-1.0f), DistUntilStop(-1.0f), DistFromPrev(-1.0f), TimeFrom(0.0f), TimeTo(0.0f),
Teleport(false), ArriveTime(0), DepartureTime(0), Spline(NULL), NextDistFromPrev(0.0f), NextArriveTime(0)
{
@@ -46,6 +46,7 @@ struct KeyFrame
uint32 Index;
TaxiPathNodeEntry const* Node;
float InitialOrientation;
float DistSinceStop;
float DistUntilStop;
float DistFromPrev;
+1 -1
View File
@@ -156,7 +156,7 @@ float SplineBase::SegLengthLinear(index_type index) const
return (points[index] - points[index+1]).length();
}
float SplineBase::SegLengthCatmullRom( index_type index ) const
float SplineBase::SegLengthCatmullRom(index_type index) const
{
ASSERT(index >= index_lo && index < index_hi);
+1 -1
View File
@@ -118,7 +118,7 @@ public:
/** As i can see there are a lot of ways how spline can be initialized
would be no harm to have some custom initializers. */
template<class Init> inline void init_spline(Init& initializer)
template<class Init> inline void init_spline_custom(Init& initializer)
{
initializer(m_mode, cyclic, points, index_lo, index_hi);
}
+3
View File
@@ -1382,7 +1382,10 @@ public:
}
else
{
Position pos;
transport->GetPosition(&pos);
handler->PSendSysMessage("Transport %s is %s", transport->GetName().c_str(), transport->GetGoState() == GO_STATE_READY ? "stopped" : "moving");
handler->PSendSysMessage("Transport position: %s", pos.ToString().c_str());
return true;
}