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
This commit is contained in:
Shauren
2013-10-16 18:37:29 +02:00
parent 53cc37bcec
commit ce55647c41
43 changed files with 2165 additions and 946 deletions

View File

@@ -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);