aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Maps
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2013-10-16 18:37:29 +0200
committerShauren <shauren.trinity@gmail.com>2013-10-16 18:37:29 +0200
commitce55647c415b710c6b440d96c2f26ebbc06c1d6e (patch)
tree515af245894c37aa76c590b6e602eb4e398d68be /src/server/game/Maps
parent53cc37bceca9ce7de1b9839251ccc809ebf768b6 (diff)
Core/Transports
* Rewritten path generation, now uses splines - timers are a lot more accurate now * Implemented stopping transports * Implemented spawning transports in instances * Implemented spawning gameobjects as transport passengers * Transport passengers are now stored in creature/gameobject table using gameobject_template.data6 from transport's template as map id
Diffstat (limited to 'src/server/game/Maps')
-rw-r--r--src/server/game/Maps/Map.cpp389
-rw-r--r--src/server/game/Maps/Map.h39
-rw-r--r--src/server/game/Maps/MapManager.cpp8
-rw-r--r--src/server/game/Maps/MapManager.h9
-rw-r--r--src/server/game/Maps/TransportMgr.cpp453
-rw-r--r--src/server/game/Maps/TransportMgr.h159
6 files changed, 984 insertions, 73 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 4660489004d..46eee6613fe 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -217,10 +217,12 @@ void Map::DeleteStateMachine()
}
Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent):
-_creatureToMoveLock(false), i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
+_creatureToMoveLock(false), _gameObjectsToMoveLock(false),
+i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE),
m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD),
-m_activeNonPlayersIter(m_activeNonPlayers.end()), i_gridExpiry(expiry),
+m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()),
+i_gridExpiry(expiry),
i_scriptLock(false)
{
m_parentMap = (_parent ? _parent : this);
@@ -270,6 +272,21 @@ void Map::AddToGrid(Creature* obj, Cell const& cell)
obj->SetCurrentCell(cell);
}
+template<>
+void Map::AddToGrid(GameObject* obj, Cell const& cell)
+{
+ NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
+ grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj);
+
+ obj->SetCurrentCell(cell);
+}
+
+template<class T>
+void Map::SwitchGridContainers(T* /*obj*/, bool /*on*/)
+{
+}
+
+template<>
void Map::SwitchGridContainers(Creature* obj, bool on)
{
ASSERT(!obj->IsPermanentWorldObject());
@@ -291,6 +308,7 @@ void Map::SwitchGridContainers(Creature* obj, bool on)
GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
+
if (on)
{
grid.AddWorldObject(obj);
@@ -301,9 +319,45 @@ void Map::SwitchGridContainers(Creature* obj, bool on)
grid.AddGridObject(obj);
RemoveWorldObject(obj);
}
+
obj->m_isTempWorldObject = on;
}
+template<>
+void Map::SwitchGridContainers(GameObject* obj, bool on)
+{
+ ASSERT(!obj->IsPermanentWorldObject());
+ CellCoord p = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
+ if (!p.IsCoordValid())
+ {
+ TC_LOG_ERROR(LOG_FILTER_MAPS, "Map::SwitchGridContainers: Object " UI64FMTD " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord);
+ return;
+ }
+
+ Cell cell(p);
+ if (!IsGridLoaded(GridCoord(cell.data.Part.grid_x, cell.data.Part.grid_y)))
+ return;
+
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "Switch object " UI64FMTD " from grid[%u, %u] %u", obj->GetGUID(), cell.data.Part.grid_x, cell.data.Part.grid_y, on);
+ NGridType *ngrid = getNGrid(cell.GridX(), cell.GridY());
+ ASSERT(ngrid != NULL);
+
+ GridType &grid = ngrid->GetGridType(cell.CellX(), cell.CellY());
+
+ obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add
+
+ if (on)
+ {
+ grid.AddWorldObject(obj);
+ AddWorldObject(obj);
+ }
+ else
+ {
+ grid.AddGridObject(obj);
+ RemoveWorldObject(obj);
+ }
+}
+
template<class T>
void Map::DeleteFromWorld(T* obj)
{
@@ -432,11 +486,17 @@ void Map::InitializeObject(T* /*obj*/)
template<>
void Map::InitializeObject(Creature* obj)
{
- obj->_moveState = CREATURE_CELL_MOVE_NONE;
+ obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
+}
+
+template<>
+void Map::InitializeObject(GameObject* obj)
+{
+ obj->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
}
template<class T>
-bool Map::AddToMap(T *obj)
+bool Map::AddToMap(T* obj)
{
/// @todo Needs clean up. An object should not be added to map twice.
if (obj->IsInWorld())
@@ -480,6 +540,26 @@ bool Map::AddToMap(T *obj)
return true;
}
+template<>
+bool Map::AddToMap(Transport* obj)
+{
+ //TODO: Needs clean up. An object should not be added to map twice.
+ if (obj->IsInWorld())
+ return true;
+
+ CellCoord cellCoord = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY());
+ if (!cellCoord.IsCoordValid())
+ {
+ TC_LOG_ERROR(LOG_FILTER_MAPS, "Map::Add: Object " UI64FMTD " has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUID(), obj->GetPositionX(), obj->GetPositionY(), cellCoord.x_coord, cellCoord.y_coord);
+ return false; //Should delete object
+ }
+
+ obj->AddToWorld();
+ _transports.insert(obj);
+
+ return true;
+}
+
bool Map::IsGridLoaded(const GridCoord &p) const
{
return (getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord));
@@ -565,6 +645,17 @@ void Map::Update(const uint32 t_diff)
VisitNearbyCellsOf(obj, grid_object_update, world_object_update);
}
+ for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
+ {
+ WorldObject* obj = *_transportsUpdateIter;
+ ++_transportsUpdateIter;
+
+ if (!obj->IsInWorld())
+ continue;
+
+ obj->Update(t_diff);
+ }
+
///- Process necessary scripts
if (!m_scriptSchedule.empty())
{
@@ -574,6 +665,7 @@ void Map::Update(const uint32 t_diff)
}
MoveAllCreaturesInMoveList();
+ MoveAllGameObjectsInMoveList();
if (!m_mapRefManager.isEmpty() || !m_activeNonPlayers.empty())
ProcessRelocationNotifies(t_diff);
@@ -708,6 +800,34 @@ void Map::RemoveFromMap(T *obj, bool remove)
}
}
+template<>
+void Map::RemoveFromMap(Transport* obj, bool remove)
+{
+ obj->RemoveFromWorld();
+
+ if (_transportsUpdateIter != _transports.end())
+ {
+ TransportsContainer::iterator itr = _transports.find(obj);
+ if (itr == _transports.end())
+ return;
+ if (itr == _transportsUpdateIter)
+ ++_transportsUpdateIter;
+ _transports.erase(itr);
+ }
+ else
+ _transports.erase(obj);
+
+ obj->ResetMap();
+
+ if (remove)
+ {
+ // if option set then object already saved at this moment
+ if (!sWorld->getBoolConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY))
+ obj->SaveRespawnTime();
+ DeleteFromWorld(obj);
+ }
+}
+
void Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation)
{
ASSERT(player);
@@ -777,12 +897,44 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa
ASSERT(CheckGridIntegrity(creature, true));
}
+void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail)
+{
+ Cell integrity_check(go->GetPositionX(), go->GetPositionY());
+ Cell old_cell = go->GetCurrentCell();
+
+ ASSERT(integrity_check == old_cell);
+ Cell new_cell(x, y);
+
+ if (!respawnRelocationOnFail && !getNGrid(new_cell.GridX(), new_cell.GridY()))
+ return;
+
+ // delay creature move for grid/cell to grid/cell moves
+ if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
+ {
+#ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) added to moving list from grid[%u, %u]cell[%u, %u] to grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+#endif
+ AddGameObjectToMoveList(go, x, y, z, orientation);
+ // in diffcell/diffgrid case notifiers called at finishing move go in Map::MoveAllGameObjectsInMoveList
+ }
+ else
+ {
+ go->Relocate(x, y, z, orientation);
+ go->UpdateObjectVisibility(false);
+ RemoveGameObjectFromMoveList(go);
+ }
+
+ old_cell = go->GetCurrentCell();
+ integrity_check = Cell(go->GetPositionX(), go->GetPositionY());
+ ASSERT(integrity_check == old_cell);
+}
+
void Map::AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang)
{
if (_creatureToMoveLock) //can this happen?
return;
- if (c->_moveState == CREATURE_CELL_MOVE_NONE)
+ if (c->_moveState == MAP_OBJECT_CELL_MOVE_NONE)
_creaturesToMove.push_back(c);
c->SetNewCellPosition(x, y, z, ang);
}
@@ -792,8 +944,27 @@ void Map::RemoveCreatureFromMoveList(Creature* c)
if (_creatureToMoveLock) //can this happen?
return;
- if (c->_moveState == CREATURE_CELL_MOVE_ACTIVE)
- c->_moveState = CREATURE_CELL_MOVE_INACTIVE;
+ if (c->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE)
+ c->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE;
+}
+
+void Map::AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang)
+{
+ if (_gameObjectsToMoveLock) //can this happen?
+ return;
+
+ if (go->_moveState == MAP_OBJECT_CELL_MOVE_NONE)
+ _gameObjectsToMove.push_back(go);
+ go->SetNewCellPosition(x, y, z, ang);
+}
+
+void Map::RemoveGameObjectFromMoveList(GameObject* go)
+{
+ if (_gameObjectsToMoveLock) //can this happen?
+ return;
+
+ if (go->_moveState == MAP_OBJECT_CELL_MOVE_ACTIVE)
+ go->_moveState = MAP_OBJECT_CELL_MOVE_INACTIVE;
}
void Map::MoveAllCreaturesInMoveList()
@@ -805,13 +976,13 @@ void Map::MoveAllCreaturesInMoveList()
if (c->FindMap() != this) //pet is teleported to another map
continue;
- if (c->_moveState != CREATURE_CELL_MOVE_ACTIVE)
+ if (c->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE)
{
- c->_moveState = CREATURE_CELL_MOVE_NONE;
+ c->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
continue;
}
- c->_moveState = CREATURE_CELL_MOVE_NONE;
+ c->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
if (!c->IsInWorld())
continue;
@@ -852,6 +1023,50 @@ void Map::MoveAllCreaturesInMoveList()
_creatureToMoveLock = false;
}
+void Map::MoveAllGameObjectsInMoveList()
+{
+ _gameObjectsToMoveLock = true;
+ for (std::vector<GameObject*>::iterator itr = _gameObjectsToMove.begin(); itr != _gameObjectsToMove.end(); ++itr)
+ {
+ GameObject* go = *itr;
+ if (go->FindMap() != this) //transport is teleported to another map
+ continue;
+
+ if (go->_moveState != MAP_OBJECT_CELL_MOVE_ACTIVE)
+ {
+ go->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
+ continue;
+ }
+
+ go->_moveState = MAP_OBJECT_CELL_MOVE_NONE;
+ if (!go->IsInWorld())
+ continue;
+
+ // do move or do move to respawn or remove creature if previous all fail
+ if (GameObjectCellRelocation(go, Cell(go->_newPosition.m_positionX, go->_newPosition.m_positionY)))
+ {
+ // update pos
+ go->Relocate(go->_newPosition);
+ go->UpdateObjectVisibility(false);
+ }
+ else
+ {
+ // if GameObject can't be move in new cell/grid (not loaded) move it to repawn cell/grid
+ // GameObject coordinates will be updated and notifiers send
+ if (!GameObjectRespawnRelocation(go, false))
+ {
+ // ... or unload (if respawn grid also not loaded)
+#ifdef TRINITY_DEBUG
+ sLog->outDebug(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) cannot be move to unloaded respawn grid.", go->GetGUIDLow(), go->GetEntry());
+#endif
+ AddObjectToRemoveList(go);
+ }
+ }
+ }
+ _gameObjectsToMove.clear();
+ _gameObjectsToMoveLock = false;
+}
+
bool Map::CreatureCellRelocation(Creature* c, Cell new_cell)
{
Cell const& old_cell = c->GetCurrentCell();
@@ -913,6 +1128,67 @@ bool Map::CreatureCellRelocation(Creature* c, Cell new_cell)
return false;
}
+bool Map::GameObjectCellRelocation(GameObject* go, Cell new_cell)
+{
+ Cell const& old_cell = go->GetCurrentCell();
+ if (!old_cell.DiffGrid(new_cell)) // in same grid
+ {
+ // if in same cell then none do
+ if (old_cell.DiffCell(new_cell))
+ {
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved in grid[%u, %u] from cell[%u, %u] to cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+
+ go->RemoveFromGrid();
+ AddToGrid(go, new_cell);
+ }
+ else
+ {
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved in same grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY());
+ #endif
+ }
+
+ return true;
+ }
+
+ // in diff. grids but active GameObject
+ if (go->isActiveObject())
+ {
+ EnsureGridLoadedForActiveObject(new_cell, go);
+
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "Active GameObject (GUID: %u Entry: %u) moved from grid[%u, %u]cell[%u, %u] to grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+
+ go->RemoveFromGrid();
+ AddToGrid(go, new_cell);
+
+ return true;
+ }
+
+ // in diff. loaded grid normal GameObject
+ if (IsGridLoaded(GridCoord(new_cell.GridX(), new_cell.GridY())))
+ {
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved from grid[%u, %u]cell[%u, %u] to grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+
+ go->RemoveFromGrid();
+ EnsureGridCreated(GridCoord(new_cell.GridX(), new_cell.GridY()));
+ AddToGrid(go, new_cell);
+
+ return true;
+ }
+
+ // fail to move: normal GameObject attempt move to unloaded grid
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) attempted to move from grid[%u, %u]cell[%u, %u] to unloaded grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
+ #endif
+ return false;
+}
+
bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
{
float resp_x, resp_y, resp_z, resp_o;
@@ -943,6 +1219,31 @@ bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
return false;
}
+bool Map::GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly)
+{
+ float resp_x, resp_y, resp_z, resp_o;
+ go->GetRespawnPosition(resp_x, resp_y, resp_z, &resp_o);
+ Cell resp_cell(resp_x, resp_y);
+
+ //GameObject will be unloaded with grid
+ if (diffGridOnly && !go->GetCurrentCell().DiffGrid(resp_cell))
+ return true;
+
+ #ifdef TRINITY_DEBUG
+ TC_LOG_DEBUG(LOG_FILTER_MAPS, "GameObject (GUID: %u Entry: %u) moved from grid[%u, %u]cell[%u, %u] to respawn grid[%u, %u]cell[%u, %u].", go->GetGUIDLow(), go->GetEntry(), go->GetCurrentCell().GridX(), go->GetCurrentCell().GridY(), go->GetCurrentCell().CellX(), go->GetCurrentCell().CellY(), resp_cell.GridX(), resp_cell.GridY(), resp_cell.CellX(), resp_cell.CellY());
+ #endif
+
+ // teleport it to respawn point (like normal respawn if player see)
+ if (GameObjectCellRelocation(go, resp_cell))
+ {
+ go->Relocate(resp_x, resp_y, resp_z, resp_o);
+ go->UpdateObjectVisibility(false);
+ return true;
+ }
+
+ return false;
+}
+
bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
{
const uint32 x = ngrid.getX();
@@ -966,6 +1267,7 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
// Finish creature moves, remove and delete all creatures with delayed remove before moving to respawn grids
// Must know real mob position before move
MoveAllCreaturesInMoveList();
+ MoveAllGameObjectsInMoveList();
// move creatures to respawn grids if this is diff.grid or to remove list
ObjectGridEvacuator worker;
@@ -974,6 +1276,7 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
// Finish creature moves, remove and delete all creatures with delayed remove before unload
MoveAllCreaturesInMoveList();
+ MoveAllGameObjectsInMoveList();
}
{
@@ -1041,6 +1344,7 @@ void Map::UnloadAll()
{
// clear all delayed moves, useless anyway do this moves before map unload.
_creaturesToMove.clear();
+ _gameObjectsToMove.clear();
for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end();)
{
@@ -2008,7 +2312,7 @@ void Map::SendInitSelf(Player* player)
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (Transport* transport = player->GetTransport())
{
- for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
+ for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
{
if (player != (*itr) && player->HaveAtClient(*itr))
{
@@ -2025,24 +2329,10 @@ void Map::SendInitSelf(Player* player)
void Map::SendInitTransports(Player* player)
{
// Hack to send out transports
- MapManager::TransportMap& tmap = sMapMgr->m_TransportsByMap;
-
- // no transports at map
- if (tmap.find(player->GetMapId()) == tmap.end())
- return;
-
UpdateData transData;
-
- MapManager::TransportSet& tset = tmap[player->GetMapId()];
-
- for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
- {
- // send data for current transport in other place
- if ((*i) != player->GetTransport() && (*i)->GetMapId() == GetId())
- {
+ for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
+ if (*i != player->GetTransport())
(*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
- }
- }
WorldPacket packet;
transData.BuildPacket(&packet);
@@ -2052,19 +2342,9 @@ void Map::SendInitTransports(Player* player)
void Map::SendRemoveTransports(Player* player)
{
// Hack to send out transports
- MapManager::TransportMap& tmap = sMapMgr->m_TransportsByMap;
-
- // no transports at map
- if (tmap.find(player->GetMapId()) == tmap.end())
- return;
-
UpdateData transData;
-
- MapManager::TransportSet& tset = tmap[player->GetMapId()];
-
- // except used transport
- for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
- if ((*i) != player->GetTransport() && (*i)->GetMapId() != GetId())
+ for (TransportsContainer::const_iterator i = _transports.begin(); i != _transports.end(); ++i)
+ if (*i != player->GetTransport())
(*i)->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
@@ -2137,8 +2417,8 @@ void Map::RemoveAllObjectsInRemoveList()
bool on = itr->second;
i_objectsToSwitch.erase(itr);
- if (obj->GetTypeId() == TYPEID_UNIT && !obj->IsPermanentWorldObject())
- SwitchGridContainers(obj->ToCreature(), on);
+ if (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_GAMEOBJECT && !obj->IsPermanentWorldObject())
+ SwitchGridContainers(obj, on);
}
//TC_LOG_DEBUG(LOG_FILTER_MAPS, "Object remover 1 check.");
@@ -2233,6 +2513,13 @@ bool Map::ActiveObjectsNearGrid(NGridType const& ngrid) const
return false;
}
+template<class T>
+void Map::AddToActive(T* obj)
+{
+ AddToActiveHelper(obj);
+}
+
+template <>
void Map::AddToActive(Creature* c)
{
AddToActiveHelper(c);
@@ -2254,6 +2541,13 @@ void Map::AddToActive(Creature* c)
}
}
+template<class T>
+void Map::RemoveFromActive(T* obj)
+{
+ RemoveFromActiveHelper(obj);
+}
+
+template <>
void Map::RemoveFromActive(Creature* c)
{
RemoveFromActiveHelper(c);
@@ -2285,6 +2579,10 @@ template void Map::RemoveFromMap(Creature*, bool);
template void Map::RemoveFromMap(GameObject*, bool);
template void Map::RemoveFromMap(DynamicObject*, bool);
+template void Map::AddToActive(DynamicObject*);
+
+template void Map::RemoveFromActive(DynamicObject*);
+
/* ******* Dungeon Instance Maps ******* */
InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
@@ -2772,6 +3070,15 @@ GameObject* Map::GetGameObject(uint64 guid)
return ObjectAccessor::GetObjectInMap(guid, this, (GameObject*)NULL);
}
+Transport* Map::GetTransport(uint64 guid)
+{
+ if (GUID_HIPART(guid) != HIGHGUID_MO_TRANSPORT)
+ return NULL;
+
+ GameObject* go = GetGameObject(guid);
+ return go ? go->ToTransport() : NULL;
+}
+
DynamicObject* Map::GetDynamicObject(uint64 guid)
{
return ObjectAccessor::GetObjectInMap(guid, this, (DynamicObject*)NULL);
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 3deeb4e04b1..c57f7d36bc6 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -52,6 +52,7 @@ struct Position;
class Battleground;
class MapInstanced;
class InstanceMap;
+class Transport;
namespace Trinity { struct ObjectUpdater; }
struct ScriptAction
@@ -278,6 +279,7 @@ class Map : public GridRefManager<NGridType>
void PlayerRelocation(Player*, float x, float y, float z, float orientation);
void CreatureRelocation(Creature* creature, float x, float y, float z, float ang, bool respawnRelocationOnFail = true);
+ void GameObjectRelocation(GameObject* go, float x, float y, float z, float orientation, bool respawnRelocationOnFail = true);
template<class T, class CONTAINER> void Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER> &visitor);
@@ -350,11 +352,13 @@ class Map : public GridRefManager<NGridType>
}
void MoveAllCreaturesInMoveList();
+ void MoveAllGameObjectsInMoveList();
void RemoveAllObjectsInRemoveList();
virtual void RemoveAllPlayers();
// used only in MoveAllCreaturesInMoveList and ObjectGridUnloader
bool CreatureRespawnRelocation(Creature* c, bool diffGridOnly);
+ bool GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly);
// assert print helper
bool CheckGridIntegrity(Creature* c, bool moved) const;
@@ -415,17 +419,13 @@ class Map : public GridRefManager<NGridType>
// must called with AddToWorld
template<class T>
- void AddToActive(T* obj) { AddToActiveHelper(obj); }
-
- void AddToActive(Creature* obj);
+ void AddToActive(T* obj);
// must called with RemoveFromWorld
template<class T>
- void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); }
-
- void RemoveFromActive(Creature* obj);
+ void RemoveFromActive(T* obj);
- void SwitchGridContainers(Creature* creature, bool toWorldContainer);
+ template<class T> void SwitchGridContainers(T* obj, bool on);
template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitFirstFound(const float &x, const float &y, float radius, NOTIFIER &notifier);
template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER &notifier);
@@ -438,6 +438,7 @@ class Map : public GridRefManager<NGridType>
void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = NULL);
Creature* GetCreature(uint64 guid);
GameObject* GetGameObject(uint64 guid);
+ Transport* GetTransport(uint64 guid);
DynamicObject* GetDynamicObject(uint64 guid);
MapInstanced* ToMapInstanced(){ if (Instanceable()) return reinterpret_cast<MapInstanced*>(this); else return NULL; }
@@ -485,6 +486,9 @@ class Map : public GridRefManager<NGridType>
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId);
+ void SendInitTransports(Player* player);
+ void SendRemoveTransports(Player* player);
+
private:
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
@@ -496,18 +500,21 @@ class Map : public GridRefManager<NGridType>
void SendInitSelf(Player* player);
- void SendInitTransports(Player* player);
- void SendRemoveTransports(Player* player);
-
bool CreatureCellRelocation(Creature* creature, Cell new_cell);
+ bool GameObjectCellRelocation(GameObject* go, Cell new_cell);
template<class T> void InitializeObject(T* obj);
void AddCreatureToMoveList(Creature* c, float x, float y, float z, float ang);
void RemoveCreatureFromMoveList(Creature* c);
+ void AddGameObjectToMoveList(GameObject* go, float x, float y, float z, float ang);
+ void RemoveGameObjectFromMoveList(GameObject* go);
bool _creatureToMoveLock;
std::vector<Creature*> _creaturesToMove;
+ bool _gameObjectsToMoveLock;
+ std::vector<GameObject*> _gameObjectsToMove;
+
bool IsGridLoaded(const GridCoord &) const;
void EnsureGridCreated(const GridCoord &);
void EnsureGridCreated_i(const GridCoord &);
@@ -516,9 +523,6 @@ class Map : public GridRefManager<NGridType>
void buildNGridLinkage(NGridType* pNGridType) { pNGridType->link(this); }
- template<class T> void AddType(T *obj);
- template<class T> void RemoveType(T *obj, bool);
-
NGridType* getNGrid(uint32 x, uint32 y) const
{
ASSERT(x < MAX_NUMBER_OF_GRIDS && y < MAX_NUMBER_OF_GRIDS);
@@ -555,6 +559,11 @@ class Map : public GridRefManager<NGridType>
ActiveNonPlayers m_activeNonPlayers;
ActiveNonPlayers::iterator m_activeNonPlayersIter;
+ // Objects that must update even in inactive grids without activating them
+ typedef std::set<Transport*> TransportsContainer;
+ TransportsContainer _transports;
+ TransportsContainer::iterator _transportsUpdateIter;
+
private:
Player* _GetScriptPlayerSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo) const;
Creature* _GetScriptCreatureSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo, bool bReverse = false) const;
@@ -589,10 +598,10 @@ class Map : public GridRefManager<NGridType>
// Type specific code for add/remove to/from grid
template<class T>
- void AddToGrid(T* object, Cell const& cell);
+ void AddToGrid(T* object, Cell const& cell);
template<class T>
- void DeleteFromWorld(T*);
+ void DeleteFromWorld(T*);
template<class T>
void AddToActiveHelper(T* obj)
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 60ebd3f8699..5aa8b85fbca 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -292,8 +292,6 @@ void MapManager::Update(uint32 diff)
iter->second->DelayedUpdate(uint32(i_timer.GetCurrent()));
sObjectAccessor->Update(uint32(i_timer.GetCurrent()));
- for (TransportSet::iterator itr = m_Transports.begin(); itr != m_Transports.end(); ++itr)
- (*itr)->Update(uint32(i_timer.GetCurrent()));
i_timer.SetCurrent(0);
}
@@ -326,12 +324,6 @@ bool MapManager::IsValidMAP(uint32 mapid, bool startUp)
void MapManager::UnloadAll()
{
- for (TransportSet::iterator i = m_Transports.begin(); i != m_Transports.end(); ++i)
- {
- (*i)->RemoveFromWorld();
- delete *i;
- }
-
for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end();)
{
iter->second->UnloadAll();
diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h
index 8af609c61e2..230b4648f4a 100644
--- a/src/server/game/Maps/MapManager.h
+++ b/src/server/game/Maps/MapManager.h
@@ -107,15 +107,6 @@ class MapManager
void DoDelayedMovesAndRemoves();
- void LoadTransports();
- void LoadTransportNPCs();
-
- typedef std::set<Transport*> TransportSet;
- TransportSet m_Transports;
-
- typedef std::map<uint32, TransportSet> TransportMap;
- TransportMap m_TransportsByMap;
-
bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false);
void InitializeVisibilityDistanceInfo();
diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp
new file mode 100644
index 00000000000..62995830c5d
--- /dev/null
+++ b/src/server/game/Maps/TransportMgr.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TransportMgr.h"
+#include "Transport.h"
+#include "InstanceScript.h"
+#include "MoveSpline.h"
+#include "MapManager.h"
+
+TransportTemplate::~TransportTemplate()
+{
+ // Collect shared pointers into a set to avoid deleting the same memory more than once
+ std::set<TransportSpline*> splines;
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ splines.insert(keyFrames[i].Spline);
+
+ for (std::set<TransportSpline*>::iterator itr = splines.begin(); itr != splines.end(); ++itr)
+ delete *itr;
+}
+
+TransportMgr::TransportMgr()
+{
+}
+
+TransportMgr::~TransportMgr()
+{
+}
+
+void TransportMgr::Unload()
+{
+ _transportTemplates.clear();
+}
+
+void TransportMgr::LoadTransportTemplates()
+{
+ uint32 oldMSTime = getMSTime();
+
+ QueryResult result = WorldDatabase.Query("SELECT entry FROM gameobject_template WHERE type = 15 ORDER BY entry ASC");
+
+ if (!result)
+ {
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 transport templates. DB table `gameobject_template` has no transports!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 entry = fields[0].GetUInt32();
+ GameObjectTemplate const* goInfo = sObjectMgr->GetGameObjectTemplate(entry);
+ if (goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size())
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u (name: %s) has an invalid path specified in `gameobject_template`.`data0` (%u) field, skipped.", entry, goInfo->name, goInfo->moTransport.taxiPathId);
+ continue;
+ }
+
+ // paths are generated per template, saves us from generating it again in case of instanced transports
+ TransportTemplate& transport = _transportTemplates[entry];
+ transport.entry = entry;
+ GeneratePath(goInfo, &transport);
+
+ // transports in instance are only on one map
+ if (transport.inInstance)
+ _instanceTransports[*transport.mapsUsed.begin()].insert(entry);
+
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Loaded %u transport templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+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;
+ bool mapChange = false;
+ bool cyclic = true;
+ for (size_t i = 1; i < path.size() - 1; ++i)
+ {
+ if (!mapChange)
+ {
+ TaxiPathNodeEntry const& node_i = path[i];
+ if (node_i.actionFlag == 1 || node_i.mapid != path[i + 1].mapid)
+ {
+ cyclic = false;
+ keyFrames.back().Teleport = true;
+ mapChange = true;
+ }
+ else
+ {
+ KeyFrame k(node_i);
+ keyFrames.push_back(k);
+ splinePath.push_back(G3D::Vector3(node_i.x, node_i.y, node_i.z));
+ transport->mapsUsed.insert(k.Node->mapid);
+ }
+ }
+ else
+ mapChange = false;
+ }
+
+ if (transport->mapsUsed.size() > 1)
+ {
+ for (std::set<uint32>::const_iterator itr = transport->mapsUsed.begin(); itr != transport->mapsUsed.end(); ++itr)
+ ASSERT(!sMapStore.LookupEntry(*itr)->Instanceable());
+
+ transport->inInstance = false;
+ }
+ else
+ transport->inInstance = sMapStore.LookupEntry(*transport->mapsUsed.begin())->Instanceable();
+
+ // last to first is always "teleport", even for closed paths
+ keyFrames.back().Teleport = true;
+
+ const float speed = float(goInfo->moTransport.moveSpeed);
+ const float accel = float(goInfo->moTransport.accelRate);
+ const float accel_dist = 0.5f * speed * speed / accel;
+
+ transport->accelTime = speed / accel;
+ transport->accelDist = accel_dist;
+
+ int32 firstStop = -1;
+ int32 lastStop = -1;
+
+ // first cell is arrived at by teleportation :S
+ keyFrames[0].DistFromPrev = 0;
+ keyFrames[0].Index = 1;
+ if (keyFrames[0].IsStopFrame())
+ {
+ firstStop = 0;
+ lastStop = 0;
+ }
+
+ // find the rest of the distances between key points
+ // Every path segment has its own spline
+ if (cyclic)
+ {
+ 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 = 1; i < keyFrames.size(); ++i)
+ {
+ keyFrames[i].Index = i + 1;
+ keyFrames[i].DistFromPrev = spline->length(i, i + 1);
+ keyFrames[i - 1].NextDistFromPrev = keyFrames[i].DistFromPrev;
+ keyFrames[i].Spline = spline;
+ if (keyFrames[i].IsStopFrame())
+ {
+ // remember first stop frame
+ if (firstStop == -1)
+ firstStop = i;
+ lastStop = i;
+ }
+ }
+ }
+ else
+ {
+ size_t start = 0;
+ for (size_t i = 1; i < keyFrames.size(); ++i)
+ {
+ 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;
+ }
+ }
+ }
+
+ keyFrames.back().NextDistFromPrev = keyFrames.front().DistFromPrev;
+
+ // at stopping keyframes, we define distSinceStop == 0,
+ // and distUntilStop is to the next stopping keyframe.
+ // this is required to properly handle cases of two stopping frames in a row (yes they do exist)
+ float tmpDist = 0.0f;
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ {
+ int32 j = (i + lastStop) % keyFrames.size();
+ if (keyFrames[j].IsStopFrame())
+ tmpDist = 0.0f;
+ else
+ tmpDist += keyFrames[j].DistFromPrev;
+ keyFrames[j].DistSinceStop = tmpDist;
+ }
+
+ tmpDist = 0.0f;
+ for (int32 i = int32(keyFrames.size()) - 1; i >= 0; i--)
+ {
+ int32 j = (i + firstStop) % keyFrames.size();
+ tmpDist += keyFrames[(j + 1) % keyFrames.size()].DistFromPrev;
+ keyFrames[j].DistUntilStop = tmpDist;
+ if (keyFrames[j].IsStopFrame())
+ tmpDist = 0.0f;
+ }
+
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ {
+ float total_dist = keyFrames[i].DistSinceStop + keyFrames[i].DistUntilStop;
+ if (total_dist < 2 * accel_dist) // won't reach full speed
+ {
+ if (keyFrames[i].DistSinceStop < keyFrames[i].DistUntilStop) // is still accelerating
+ {
+ // calculate accel+brake time for this short segment
+ float segment_time = 2.0f * sqrt((keyFrames[i].DistUntilStop + keyFrames[i].DistSinceStop) / accel);
+ // substract acceleration time
+ keyFrames[i].TimeTo = segment_time - sqrt(2 * keyFrames[i].DistSinceStop / accel);
+ }
+ else // slowing down
+ keyFrames[i].TimeTo = sqrt(2 * keyFrames[i].DistUntilStop / accel);
+ }
+ else if (keyFrames[i].DistSinceStop < accel_dist) // still accelerating (but will reach full speed)
+ {
+ // calculate accel + cruise + brake time for this long segment
+ float segment_time = (keyFrames[i].DistUntilStop + keyFrames[i].DistSinceStop) / speed + (speed / accel);
+ // substract acceleration time
+ keyFrames[i].TimeTo = segment_time - sqrt(2 * keyFrames[i].DistSinceStop / accel);
+ }
+ else if (keyFrames[i].DistUntilStop < accel_dist) // already slowing down (but reached full speed)
+ keyFrames[i].TimeTo = sqrt(2 * keyFrames[i].DistUntilStop / accel);
+ else // at full speed
+ keyFrames[i].TimeTo = (keyFrames[i].DistUntilStop / speed) + (0.5f * speed / accel);
+ }
+
+ // calculate tFrom times from tTo times
+ float segmentTime = 0.0f;
+ for (size_t i = 0; i < keyFrames.size(); ++i)
+ {
+ int32 j = (i + lastStop) % keyFrames.size();
+ if (keyFrames[j].IsStopFrame())
+ segmentTime = keyFrames[j].TimeTo;
+ keyFrames[j].TimeFrom = segmentTime - keyFrames[j].TimeTo;
+ }
+
+ // calculate path times
+ keyFrames[0].ArriveTime = 0;
+ float curPathTime = 0.0f;
+ if (keyFrames[0].IsStopFrame())
+ {
+ curPathTime = float(keyFrames[0].Node->delay);
+ keyFrames[0].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
+ }
+
+ for (size_t i = 1; i < keyFrames.size(); ++i)
+ {
+ curPathTime += keyFrames[i-1].TimeTo;
+ if (keyFrames[i].IsStopFrame())
+ {
+ keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
+ keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
+ curPathTime += (float)keyFrames[i].Node->delay;
+ keyFrames[i].DepartureTime = uint32(curPathTime * IN_MILLISECONDS);
+ }
+ else
+ {
+ curPathTime -= keyFrames[i].TimeTo;
+ keyFrames[i].ArriveTime = uint32(curPathTime * IN_MILLISECONDS);
+ keyFrames[i - 1].NextArriveTime = keyFrames[i].ArriveTime;
+ keyFrames[i].DepartureTime = keyFrames[i].ArriveTime;
+ }
+ }
+ keyFrames.back().NextArriveTime = keyFrames.back().DepartureTime;
+
+ transport->pathTime = keyFrames.back().DepartureTime;
+ //WorldDatabase.DirectPExecute("UPDATE `transports` SET `period_gen`=%u WHERE `entry`=%u", transport->pathTime, transport->entry);
+}
+
+void TransportMgr::AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node)
+{
+ TransportAnimation& animNode = _transportAnimations[transportEntry];
+ if (animNode.TotalTime < timeSeg)
+ animNode.TotalTime = timeSeg;
+
+ animNode.Path[timeSeg] = node;
+}
+
+Transport* TransportMgr::CreateTransport(uint32 entry, uint32 guid /*= 0*/, Map* map /*= NULL*/)
+{
+ // instance case, execute GetGameObjectEntry hook
+ if (map)
+ {
+ // SetZoneScript() is called after adding to map, so fetch the script using map
+ if (map->IsDungeon())
+ if (InstanceScript* instance = static_cast<InstanceMap*>(map)->GetInstanceScript())
+ entry = instance->GetGameObjectEntry(0, entry);
+
+ if (!entry)
+ return NULL;
+ }
+
+ TransportTemplate const* tInfo = GetTransportTemplate(entry);
+ if (!tInfo)
+ {
+ TC_LOG_ERROR(LOG_FILTER_SQL, "Transport %u will not be loaded, `transport_template` missing", entry);
+ return NULL;
+ }
+
+ // create transport...
+ Transport* trans = new Transport();
+
+ // ...at first waypoint
+ TaxiPathNodeEntry const* startNode = tInfo->keyFrames.begin()->Node;
+ uint32 mapId = startNode->mapid;
+ float x = startNode->x;
+ float y = startNode->y;
+ float z = startNode->z;
+ float o = 0.0f;
+
+ // initialize the gameobject base
+ uint32 guidLow = guid ? guid : sObjectMgr->GenerateLowGuid(HIGHGUID_MO_TRANSPORT);
+ if (!trans->Create(guidLow, entry, mapId, x, y, z, o, 255))
+ {
+ delete trans;
+ return NULL;
+ }
+
+ if (MapEntry const* mapEntry = sMapStore.LookupEntry(mapId))
+ {
+ if (uint32(mapEntry->Instanceable()) != tInfo->inInstance)
+ {
+ TC_LOG_ERROR(LOG_FILTER_TRANSPORTS, "Transport %u (name: %s) attempted creation in instance map (id: %u) but it is not an instanced transport!", entry, trans->GetName(), mapId);
+ delete trans;
+ return NULL;
+ }
+ }
+
+ // use preset map for instances (need to know which instance)
+ trans->SetMap(map ? map : sMapMgr->CreateMap(mapId, NULL));
+ if (map && map->IsDungeon())
+ trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript();
+
+ // Passengers will be loaded once a player is near
+
+ trans->GetMap()->AddToMap<Transport>(trans);
+ return trans;
+}
+
+void TransportMgr::SpawnContinentTransports()
+{
+ if (_transportTemplates.empty())
+ return;
+
+ uint32 oldMSTime = getMSTime();
+
+ QueryResult result = WorldDatabase.Query("SELECT guid, entry FROM transports");
+
+ uint32 count = 0;
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+ uint32 entry = fields[1].GetUInt32();
+
+ if (TransportTemplate const* tInfo = GetTransportTemplate(entry))
+ if (!tInfo->inInstance)
+ if (CreateTransport(entry, guid))
+ ++count;
+
+ } while (result->NextRow());
+ }
+
+ TC_LOG_INFO(LOG_FILTER_SERVER_LOADING, ">> Spawned %u continent transports in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
+void TransportMgr::CreateInstanceTransports(Map* map)
+{
+ TransportInstanceMap::const_iterator mapTransports = _instanceTransports.find(map->GetId());
+
+ // no transports here
+ if (mapTransports == _instanceTransports.end() || mapTransports->second.empty())
+ return;
+
+ // create transports
+ for (std::set<uint32>::const_iterator itr = mapTransports->second.begin(); itr != mapTransports->second.end(); ++itr)
+ CreateTransport(*itr, 0, map);
+}
+
+TransportAnimationEntry const* TransportAnimation::GetAnimNode(uint32 time) const
+{
+ if (Path.empty())
+ return NULL;
+
+ for (TransportPathContainer::const_reverse_iterator itr2 = Path.rbegin(); itr2 != Path.rend(); ++itr2)
+ if (time >= itr2->first)
+ return itr2->second;
+
+ return Path.begin()->second;
+}
+
+G3D::Quat TransportAnimation::GetAnimRotation(uint32 time) const
+{
+ if (Rotations.empty())
+ return G3D::Quat(0.0f, 0.0f, 0.0f, 1.0f);
+
+ TransportRotationEntry const* rot = Rotations.begin()->second;
+ for (TransportPathRotationContainer::const_reverse_iterator itr2 = Rotations.rbegin(); itr2 != Rotations.rend(); ++itr2)
+ {
+ if (time >= itr2->first)
+ {
+ rot = itr2->second;
+ break;
+ }
+ }
+
+ return G3D::Quat(rot->X, rot->Y, rot->Z, rot->W);
+}
diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h
new file mode 100644
index 00000000000..250a2c50bb1
--- /dev/null
+++ b/src/server/game/Maps/TransportMgr.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TRANSPORTMGR_H
+#define TRANSPORTMGR_H
+
+#include <ace/Singleton.h>
+#include <G3D/Quat.h>
+#include "Spline.h"
+#include "DBCStores.h"
+
+struct KeyFrame;
+struct GameObjectTemplate;
+struct TransportTemplate;
+class Transport;
+class Map;
+
+typedef Movement::Spline<double> TransportSpline;
+typedef std::vector<KeyFrame> KeyFrameVec;
+typedef UNORDERED_MAP<uint32, TransportTemplate> TransportTemplates;
+typedef std::set<Transport*> TransportSet;
+typedef UNORDERED_MAP<uint32, TransportSet> TransportMap;
+typedef UNORDERED_MAP<uint32, std::set<uint32> > TransportInstanceMap;
+
+struct KeyFrame
+{
+ explicit KeyFrame(TaxiPathNodeEntry const& _node) : Node(&_node),
+ 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)
+ {
+ }
+
+ uint32 Index;
+ TaxiPathNodeEntry const* Node;
+ float DistSinceStop;
+ float DistUntilStop;
+ float DistFromPrev;
+ float TimeFrom;
+ float TimeTo;
+ bool Teleport;
+ uint32 ArriveTime;
+ uint32 DepartureTime;
+ TransportSpline* Spline;
+
+ // Data needed for next frame
+ float NextDistFromPrev;
+ uint32 NextArriveTime;
+
+ bool IsTeleportFrame() const { return Teleport; }
+ bool IsStopFrame() const { return Node->actionFlag == 2; }
+};
+
+struct TransportTemplate
+{
+ TransportTemplate() : pathTime(0), accelTime(0.0f), accelDist(0.0f) { }
+ ~TransportTemplate();
+
+ std::set<uint32> mapsUsed;
+ bool inInstance;
+ uint32 pathTime;
+ KeyFrameVec keyFrames;
+ float accelTime;
+ float accelDist;
+ uint32 entry;
+};
+
+typedef std::map<uint32, TransportAnimationEntry const*> TransportPathContainer;
+typedef std::map<uint32, TransportRotationEntry const*> TransportPathRotationContainer;
+
+struct TransportAnimation
+{
+ TransportPathContainer Path;
+ TransportPathRotationContainer Rotations;
+ uint32 TotalTime;
+
+ TransportAnimationEntry const* GetAnimNode(uint32 time) const;
+ G3D::Quat GetAnimRotation(uint32 time) const;
+};
+
+typedef std::map<uint32, TransportAnimation> TransportAnimationContainer;
+
+class TransportMgr
+{
+ friend class ACE_Singleton<TransportMgr, ACE_Thread_Mutex>;
+ friend void LoadDBCStores(std::string const&);
+
+ public:
+ void Unload();
+
+ void LoadTransportTemplates();
+
+ // Creates a transport using given GameObject template entry
+ Transport* CreateTransport(uint32 entry, uint32 guid = 0, Map* map = NULL);
+
+ // Spawns all continent transports, used at core startup
+ void SpawnContinentTransports();
+
+ // creates all transports for instance
+ void CreateInstanceTransports(Map* map);
+
+ TransportTemplate const* GetTransportTemplate(uint32 entry) const
+ {
+ TransportTemplates::const_iterator itr = _transportTemplates.find(entry);
+ if (itr != _transportTemplates.end())
+ return &itr->second;
+ return NULL;
+ }
+
+ TransportAnimation const* GetTransportAnimInfo(uint32 entry) const
+ {
+ TransportAnimationContainer::const_iterator itr = _transportAnimations.find(entry);
+ if (itr != _transportAnimations.end())
+ return &itr->second;
+
+ return NULL;
+ }
+
+ private:
+ TransportMgr();
+ ~TransportMgr();
+ TransportMgr(TransportMgr const&);
+ TransportMgr& operator=(TransportMgr const&);
+
+ // Generates and precaches a path for transport to avoid generation each time transport instance is created
+ void GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport);
+
+ void AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node);
+
+ void AddPathRotationToTransport(uint32 transportEntry, uint32 timeSeg, TransportRotationEntry const* node)
+ {
+ _transportAnimations[transportEntry].Rotations[timeSeg] = node;
+ }
+
+ // Container storing transport templates
+ TransportTemplates _transportTemplates;
+
+ // Container storing transport entries to create for instanced maps
+ TransportInstanceMap _instanceTransports;
+
+ TransportAnimationContainer _transportAnimations;
+};
+
+#define sTransportMgr ACE_Singleton<TransportMgr, ACE_Thread_Mutex>::instance()
+
+#endif // TRANSPORTMGR_H