diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp index 4964d2ef2..3115a9473 100644 --- a/src/game/Corpse.cpp +++ b/src/game/Corpse.cpp @@ -72,12 +72,15 @@ bool Corpse::Create( uint32 guidlow ) bool Corpse::Create( uint32 guidlow, Player *owner) { - SetInstanceId(owner->GetInstanceId()); - - WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetMapId(), owner->GetPhaseMask()); + ASSERT(owner); + WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask()); Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation()); + //we need to assign owner's map for corpse + //in other way we will get a crash in Corpse::SaveToDB() + SetMap(owner->GetMap()); + if(!IsPositionValid()) { sLog.outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)", @@ -207,8 +210,8 @@ bool Corpse::LoadFromDB(uint32 guid, Field *fields) SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE)); // place - SetInstanceId(instanceid); - SetMapId(mapid); + SetLocationInstanceId(instanceid); + SetLocationMapId(mapid); SetPhaseMask(phaseMask, false); Relocate(positionX, positionY, positionZ, ort); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 98e500d8e..a49fe41ee 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -563,8 +563,8 @@ bool Creature::AIM_Initialize() bool Creature::Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 team, const CreatureData *data) { - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); + ASSERT(map); + SetMap(map); SetPhaseMask(phaseMask,false); //oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0; @@ -572,6 +572,12 @@ bool Creature::Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, if (bResult) { + //Notify the map's instance data. + //Only works if you create the object in it, not if it is moves to that map. + //Normally non-players do not teleport to other maps. + if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) + ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this); + switch (GetCreatureInfo()->rank) { case CREATURE_ELITE_RARE: @@ -1312,15 +1318,6 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 team, const if(!UpdateEntry(Entry, team, data)) return false; - //Notify the map's instance data. - //Only works if you create the object in it, not if it is moves to that map. - //Normally non-players do not teleport to other maps. - Map *map = MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); - if(map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData()) - { - ((InstanceMap*)map)->GetInstanceData()->OnCreatureCreate(this); - } - return true; } diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index 89c6a7545..bf81f6dc6 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -56,9 +56,8 @@ void DynamicObject::RemoveFromWorld() bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, uint32 effIndex, float x, float y, float z, int32 duration, float radius ) { - SetInstanceId(caster->GetInstanceId()); - - WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetMapId(), caster->GetPhaseMask()); + WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask()); + SetMap(caster->GetMap()); Relocate(x, y, z, 0); if(!IsPositionValid()) diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index d2d1478cc..b92db0d81 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -109,9 +109,9 @@ void GameObject::RemoveFromWorld() bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state) { + ASSERT(map); Relocate(x,y,z,ang); - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); + SetMap(map); SetPhaseMask(phaseMask,false); if(!IsPositionValid()) diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 35b6c539c..4b589bcc7 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -124,14 +124,12 @@ void Map::LoadMap(int gx,int gy, bool reload) if(GridMaps[gx][gy]) return; - Map* baseMap = const_cast(MapManager::Instance().CreateBaseMap(i_id)); - // load grid map for base map - if (!baseMap->GridMaps[gx][gy]) - baseMap->EnsureGridCreated(GridPair(63-gx,63-gy)); + if (!m_parentMap->GridMaps[gx][gy]) + m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy)); - ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(gx,gy)); - GridMaps[gx][gy] = baseMap->GridMaps[gx][gy]; + ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy)); + GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; return; } @@ -184,11 +182,11 @@ void Map::DeleteStateMachine() delete si_GridStates[GRID_STATE_REMOVAL]; } -Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) +Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), m_activeNonPlayersIter(m_activeNonPlayers.end()), - i_gridExpiry(expiry) + i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this) { for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) { @@ -295,6 +293,13 @@ void Map::DeleteFromWorld(T* obj) delete obj; } +template<> +void Map::DeleteFromWorld(Player* pl) +{ + ObjectAccessor::Instance().RemoveObject(pl); + delete pl; +} + template void Map::AddNotifier(T* , Cell const& , CellPair const& ) { @@ -399,8 +404,7 @@ void Map::LoadGrid(const Cell& cell, bool no_unload) bool Map::Add(Player *player) { player->GetMapRef().link(this, player); - - player->SetInstanceId(GetInstanceId()); + player->SetMap(this); // update player state for other player and visa-versa CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); @@ -431,6 +435,8 @@ Map::Add(T *obj) return; } + obj->SetMap(this); + Cell cell(p); if(obj->isActiveObject()) EnsureGridLoadedAtEnter(cell); @@ -688,8 +694,12 @@ void Map::Remove(Player *player, bool remove) CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) { + if(remove) + player->CleanupsBeforeDelete(); + // invalid coordinates player->RemoveFromWorld(); + player->ResetMap(); if( remove ) DeleteFromWorld(player); @@ -709,13 +719,16 @@ void Map::Remove(Player *player, bool remove) NGridType *grid = getNGrid(cell.GridX(), cell.GridY()); assert(grid != NULL); + if(remove) + player->CleanupsBeforeDelete(); + player->RemoveFromWorld(); RemoveFromGrid(player,grid,cell); SendRemoveTransports(player); - UpdateObjectsVisibilityFor(player,cell,p); + player->ResetMap(); if( remove ) DeleteFromWorld(player); } @@ -760,6 +773,7 @@ Map::Remove(T *obj, bool remove) UpdateObjectVisibility(obj,cell,p); + obj->ResetMap(); if( remove ) { // if option set then object already saved at this moment @@ -1029,7 +1043,8 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce) VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx); } else - ((MapInstanced*)(MapManager::Instance().CreateBaseMap(i_id)))->RemoveGridMapReference(GridPair(gx, gy)); + ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy)); + GridMaps[gx][gy] = NULL; } DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, i_id); @@ -2196,8 +2211,8 @@ template void Map::Remove(DynamicObject *, bool); /* ******* Dungeon Instance Maps ******* */ -InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode) - : Map(id, expiry, InstanceId, SpawnMode), +InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) + : Map(id, expiry, InstanceId, SpawnMode, _parent), m_resetAfterUnload(false), m_unloadWhenEmpty(false), i_data(NULL), i_script_id(0) { @@ -2534,8 +2549,8 @@ uint32 InstanceMap::GetMaxPlayers() const /* ******* Battleground Instance Maps ******* */ -BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId) - : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL) +BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent) + : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL, _parent) { } diff --git a/src/game/Map.h b/src/game/Map.h index a07553181..6f00c81e2 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -245,7 +245,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj { friend class MapReference; public: - Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); + Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); virtual ~Map(); // currently unused for normal maps @@ -300,6 +300,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj static void InitStateMachine(); static void DeleteStateMachine(); + Map const * GetParent() const { return m_parentMap; } + // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetHeight(float x, float y, float z, bool pCheckVMap=true) const; @@ -461,6 +463,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj ActiveNonPlayers m_activeNonPlayers; ActiveNonPlayers::iterator m_activeNonPlayersIter; private: + //used for fast base_map (e.g. MapInstanced class object) search for + //InstanceMaps and BattleGroundMaps... + Map* m_parentMap; + typedef GridReadGuard ReadGuard; typedef GridWriteGuard WriteGuard; @@ -520,7 +526,7 @@ enum InstanceResetMethod class MANGOS_DLL_SPEC InstanceMap : public Map { public: - InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode); + InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); ~InstanceMap(); bool Add(Player *); void Remove(Player *, bool); @@ -545,7 +551,7 @@ class MANGOS_DLL_SPEC InstanceMap : public Map class MANGOS_DLL_SPEC BattleGroundMap : public Map { public: - BattleGroundMap(uint32 id, time_t, uint32 InstanceId); + BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent); ~BattleGroundMap(); bool Add(Player *); diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index e6eaa6298..ee62bae5f 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -108,84 +108,59 @@ void MapInstanced::UnloadAll(bool pForce) - create the instance if it's not created already - the player is not actually added to the instance (only in InstanceMap::Add) */ -Map* MapInstanced::GetInstance(const WorldObject* obj) +Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) { - uint32 CurInstanceId = obj->GetInstanceId(); - Map* map = NULL; + if(GetId() != mapId || !player) + return NULL; - if (obj->GetMapId() == GetId() && CurInstanceId != 0) + Map* map = NULL; + uint32 NewInstanceId = 0; // instanceId of the resulting map + + if(IsBattleGroundOrArena()) { - // the object wants to be put in a certain instance of this map - map = _FindMap(CurInstanceId); + // instantiate or find existing bg map for player + // the instance id is set in battlegroundid + NewInstanceId = player->GetBattleGroundId(); + ASSERT(NewInstanceId); + map = _FindMap(NewInstanceId); if(!map) - { - // For players if the instanceId is set, it's assumed they are already in a map, - // hence the map must be loaded. For Creatures, GameObjects etc the map must exist - // prior to calling GetMap, they are not allowed to create maps for themselves. - sLog.outError("GetInstance: object %s(%d), typeId %d, in world %d, should be in map %d,%d but that's not loaded yet.", obj->GetName(), obj->GetGUIDLow(), obj->GetTypeId(), obj->IsInWorld(), obj->GetMapId(), obj->GetInstanceId()); - assert(false); - } - return(map); + map = CreateBattleGround(NewInstanceId); } else { - // instance not specified, find an existing or create a new one - if(obj->GetTypeId() != TYPEID_PLAYER) + InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty()); + InstanceSave *pSave = pBind ? pBind->save : NULL; + + // the player's permanent player bind is taken into consideration first + // then the player's group bind and finally the solo bind. + if(!pBind || !pBind->perm) { - sLog.outError("MAPINSTANCED: WorldObject '%u' (Entry: %u TypeID: %u) is in map %d,%d and requested base map instance of map %d, this must not happen", obj->GetGUIDLow(), obj->GetEntry(), obj->GetTypeId(), obj->GetMapId(), obj->GetInstanceId(), GetId()); - assert(false); - return NULL; + InstanceGroupBind *groupBind = NULL; + Group *group = player->GetGroup(); + // use the player's difficulty setting (it may not be the same as the group's) + if(group && (groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty()))) + pSave = groupBind->save; + } + + if(pSave) + { + // solo/perm/group + NewInstanceId = pSave->GetInstanceId(); + map = _FindMap(NewInstanceId); + // it is possible that the save exists but the map doesn't + if(!map) + map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty()); } else { - uint32 NewInstanceId = 0; // instanceId of the resulting map - Player* player = (Player*)obj; - - if(IsBattleGroundOrArena()) - { - // instantiate or find existing bg map for player - // the instance id is set in battlegroundid - NewInstanceId = player->GetBattleGroundId(); - assert(NewInstanceId); - map = _FindMap(NewInstanceId); - if(!map) - map = CreateBattleGround(NewInstanceId); - return map; - } - - InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty()); - InstanceSave *pSave = pBind ? pBind->save : NULL; - - // the player's permanet player bind is taken into consideration first - // then the player's group bind and finally the solo bind. - if(!pBind || !pBind->perm) - { - InstanceGroupBind *groupBind = NULL; - Group *group = player->GetGroup(); - // use the player's difficulty setting (it may not be the same as the group's) - if(group && (groupBind = group->GetBoundInstance(GetId(), player->GetDifficulty()))) - pSave = groupBind->save; - } - - if(pSave) - { - // solo/perm/group - NewInstanceId = pSave->GetInstanceId(); - map = _FindMap(NewInstanceId); - // it is possible that the save exists but the map doesn't - if(!map) - map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty()); - return map; - } - else - { - // if no instanceId via group members or instance saves is found - // the instance will be created for the first time - NewInstanceId = MapManager::Instance().GenerateInstanceId(); - return CreateInstance(NewInstanceId, NULL, player->GetDifficulty()); - } + // if no instanceId via group members or instance saves is found + // the instance will be created for the first time + NewInstanceId = MapManager::Instance().GenerateInstanceId(); + map = CreateInstance(NewInstanceId, NULL, player->GetDifficulty()); } } + + return map; } InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty) @@ -210,10 +185,10 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, // some instances only have one difficulty if (entry && !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; - sLog.outDebug("MapInstanced::CreateInstance: %smap instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); + sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); - InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty); - assert(map->IsDungeon()); + InstanceMap *map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); + ASSERT(map->IsDungeon()); bool load_data = save != NULL; map->CreateInstanceData(load_data); @@ -229,8 +204,8 @@ BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId) sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId()); - BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId); - assert(map->IsBattleGroundOrArena()); + BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this); + ASSERT(map->IsBattleGroundOrArena()); m_InstancedMaps[InstanceId] = map; return map; diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 8a6cfdb9f..67c57b98d 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -38,7 +38,7 @@ class MANGOS_DLL_DECL MapInstanced : public Map bool RemoveBones(uint64 guid, float x, float y); void UnloadAll(bool pForce); - Map* GetInstance(const WorldObject* obj); + Map* CreateInstance(const uint32 mapId, Player * player); Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); } void DestroyInstance(uint32 InstanceId); void DestroyInstance(InstancedMaps::iterator &itr); diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 81b3786a5..675df9ab5 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -122,13 +122,13 @@ MapManager::_createBaseMap(uint32 id) return m; } -Map* MapManager::GetMap(uint32 id, const WorldObject* obj) +Map* MapManager::CreateMap(uint32 id, const WorldObject* obj) { ASSERT(obj); //if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId()); Map *m = _createBaseMap(id); - if (m && obj && m->Instanceable()) m = ((MapInstanced*)m)->GetInstance(obj); + if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj); return m; } diff --git a/src/game/MapManager.h b/src/game/MapManager.h index 8755a3f45..f88e62a36 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -37,7 +37,7 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton(this)->_createBaseMap(id); } Map* FindMap(uint32 mapid, uint32 instanceId = 0) const; diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 8f287ca7f..4650e0484 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -65,18 +65,17 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->SetSemaphoreTeleportFar(false); // relocate the player to the teleport destination - GetPlayer()->SetMapId(loc.mapid); + GetPlayer()->SetMap(MapManager::Instance().CreateMap(loc.mapid, GetPlayer())); GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); - // since the MapId is set before the GetInstance call, the InstanceId must be set to 0 - // to let GetInstance() determine the proper InstanceId based on the player's binds - GetPlayer()->SetInstanceId(0); - GetPlayer()->SendInitialPacketsBeforeAddToMap(); // the CanEnter checks are done in TeleporTo but conditions may change // while the player is in transit, for example the map may get full if(!GetPlayer()->GetMap()->Add(GetPlayer())) { + //if player wasn't added to map, reset his map pointer! + GetPlayer()->ResetMap(); + sLog.outDebug("WORLD: teleport of player %s (%d) to location %d, %f, %f, %f, %f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); // teleport the player home if(!GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation())) diff --git a/src/game/Object.cpp b/src/game/Object.cpp index fc7826a51..d3bd33a65 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1049,7 +1049,7 @@ bool Object::PrintIndexError(uint32 index, bool set) const WorldObject::WorldObject() : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), - m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f) + m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f), m_currMap(NULL) { } @@ -1057,11 +1057,9 @@ void WorldObject::CleanupsBeforeDelete() { } -void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask ) +void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 phaseMask ) { Object::_Create(guidlow, 0, guidhigh); - - m_mapId = mapid; m_phaseMask = phaseMask; } @@ -1538,14 +1536,19 @@ void WorldObject::SendObjectDeSpawnAnim(uint64 guid) SendMessageToSet(&data, true); } -Map* WorldObject::GetMap() const +void WorldObject::SetMap(Map * map) { - return MapManager::Instance().GetMap(GetMapId(), this); + ASSERT(map); + m_currMap = map; + //lets save current map's Id/instanceId + m_mapId = map->GetId(); + m_InstanceId = map->GetInstanceId(); } Map const* WorldObject::GetBaseMap() const { - return MapManager::Instance().CreateBaseMap(GetMapId()); + ASSERT(m_currMap); + return m_currMap->GetParent(); } void WorldObject::AddObjectToRemoveList() @@ -1557,7 +1560,6 @@ Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, floa { TemporarySummon* pCreature = new TemporarySummon(GetGUID()); - pCreature->SetInstanceId(GetInstanceId()); uint32 team = 0; if (GetTypeId()==TYPEID_PLAYER) team = ((Player*)this)->GetTeam(); diff --git a/src/game/Object.h b/src/game/Object.h index aa53d628c..8cb44e0c1 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -346,7 +346,7 @@ class MANGOS_DLL_SPEC WorldObject : public Object virtual void Update ( uint32 /*time_diff*/ ) { } - void _Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid, uint32 phaseMask); + void _Create( uint32 guidlow, HighGuid guidhigh, uint32 phaseMask); void Relocate(float x, float y, float z, float orientation) { @@ -395,8 +395,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object void GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z ) const; - void SetMapId(uint32 newMap) { m_mapId = newMap; } uint32 GetMapId() const { return m_mapId; } + uint32 GetInstanceId() const { return m_InstanceId; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); uint32 GetPhaseMask() const { return m_phaseMask; } @@ -421,8 +421,7 @@ class MANGOS_DLL_SPEC WorldObject : public Object float GetDistanceZ(const WorldObject* obj) const; bool IsInMap(const WorldObject* obj) const { - return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() && - GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj); + return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()) && InSamePhase(obj); } bool IsWithinDist3d(float x, float y, float z, float dist2compare) const; bool IsWithinDist2d(float x, float y, float dist2compare) const; @@ -469,10 +468,6 @@ class MANGOS_DLL_SPEC WorldObject : public Object void SendObjectDeSpawnAnim(uint64 guid); virtual void SaveRespawnTime() {} - - uint32 GetInstanceId() const { return m_InstanceId; } - void SetInstanceId(uint32 val) { m_InstanceId = val; } - void AddObjectToRemoveList(); // main visibility check function in normal case (ignore grey zone distance check) @@ -481,15 +476,29 @@ class MANGOS_DLL_SPEC WorldObject : public Object // low level function for visibility change code, must be define in all main world object subclasses virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0; - Map * GetMap() const; + void SetMap(Map * map); + Map * GetMap() const { ASSERT(m_currMap); return m_currMap; } + //used to check all object's GetMap() calls when object is not in world! + void ResetMap() { m_currMap = NULL; } + + //this function should be removed in nearest time... Map const* GetBaseMap() const; + Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime); protected: explicit WorldObject(); std::string m_name; + //these functions are used mostly for Relocate() and Corpse/Player specific stuff... + //use them ONLY in LoadFromDB()/Create() funcs and nowhere else! + //mapId/instanceId should be set in SetMap() function! + void SetLocationMapId(uint32 _mapId) { m_mapId = _mapId; } + void SetLocationInstanceId(uint32 _instanceId) { m_InstanceId = _instanceId; } + private: + Map * m_currMap; //current object's Map location + uint32 m_mapId; // object at map with map_id uint32 m_InstanceId; // in map copy with instance id uint32 m_phaseMask; // in area phase state diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 43eb02a8a..17e35f973 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -363,8 +363,6 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia) // bones->m_inWorld = m_inWorld; // don't overwrite world state // bones->m_type = m_type; // don't overwrite type bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation()); - bones->SetMapId(corpse->GetMapId()); - bones->SetInstanceId(corpse->GetInstanceId()); bones->SetPhaseMask(corpse->GetPhaseMask(), false); bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES); diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index 77695e758..896c0726d 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -123,6 +123,7 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & obj->GetGridRef().link(&m, obj); addUnitState(obj,cell); + obj->SetMap(map); obj->AddToWorld(); if(obj->isActiveObject()) map->AddToActive(obj); @@ -151,6 +152,7 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType obj->GetGridRef().link(&m, obj); addUnitState(obj,cell); + obj->SetMap(map); obj->AddToWorld(); if(obj->isActiveObject()) map->AddToActive(obj); diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 32964c818..6f6958d37 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -744,9 +744,6 @@ bool Pet::CreateBaseAtCreature(Creature* creature) } uint32 guid=objmgr.GenerateLowGuid(HIGHGUID_PET); - sLog.outBasic("SetInstanceID()"); - SetInstanceId(creature->GetInstanceId()); - sLog.outBasic("Create pet"); uint32 pet_number = objmgr.GeneratePetNumber(); if(!Create(guid, creature->GetMap(), creature->GetPhaseMask(), creature->GetEntry(), pet_number)) @@ -1841,8 +1838,7 @@ bool Pet::IsPermanentPetFor(Player* owner) bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number) { - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); + SetMap(map); SetPhaseMask(phaseMask,false); Object::_Create(guidlow, pet_number, HIGHGUID_PET); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 014a20dc4..5d8eb513d 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -540,7 +540,7 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 for (int i = 0; i < PLAYER_SLOTS_COUNT; ++i) m_items[i] = NULL; - SetMapId(info->mapId); + SetLocationMapId(info->mapId); Relocate(info->positionX,info->positionY,info->positionZ); ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(class_); @@ -550,6 +550,8 @@ bool Player::Create( uint32 guidlow, const std::string& name, uint8 race, uint8 return false; } + SetMap(MapManager::Instance().CreateMap(info->mapId, this)); + uint8 powertype = cEntry->powerType; SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE); @@ -12031,7 +12033,11 @@ void Player::PrepareQuestMenu( uint64 guid ) } else { - GameObject *pGameObject = GetMap()->GetGameObject(guid); + //we should obtain map pointer from GetMap() in 99% of cases. Special case + //only for quests which cast teleport spells on player + Map * _map = IsInWorld() ? GetMap() : MapManager::Instance().FindMap(GetMapId(), GetInstanceId()); + ASSERT(_map); + GameObject *pGameObject = _map->GetGameObject(guid); if( pGameObject ) { pObject = (Object*)pGameObject; @@ -13829,7 +13835,8 @@ bool Player::MinimalLoadFromDB( QueryResult *result, uint32 guid ) m_name = fields[2].GetCppString(); Relocate(fields[3].GetFloat(),fields[4].GetFloat(),fields[5].GetFloat()); - SetMapId(fields[6].GetUInt32()); + SetLocationMapId(fields[6].GetUInt32()); + // the instance id is not needed at character enum m_Played_time[0] = fields[7].GetUInt32(); @@ -14108,7 +14115,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // init saved position, and fix it later if problematic uint32 transGUID = fields[31].GetUInt32(); Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat()); - SetMapId(fields[16].GetUInt32()); + SetLocationMapId(fields[16].GetUInt32()); SetDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup _LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP)); @@ -14183,7 +14190,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) else { const WorldLocation& _loc = GetBattleGroundEntryPoint(); - SetMapId(_loc.mapid); + SetLocationMapId(_loc.mapid); Relocate(_loc.coord_x, _loc.coord_y, _loc.coord_z, _loc.orientation); //RemoveArenaAuras(true); } @@ -14196,7 +14203,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) if(!mapEntry || mapEntry->IsBattleGroundOrArena()) { // return to BG master - SetMapId(fields[43].GetUInt32()); + SetLocationMapId(fields[43].GetUInt32()); Relocate(fields[44].GetFloat(),fields[45].GetFloat(),fields[46].GetFloat(),fields[47].GetFloat()); // check entry point and fix to homebind if need @@ -14250,7 +14257,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) m_transport = *iter; m_transport->AddPassenger(this); - SetMapId(m_transport->GetMapId()); + SetLocationMapId(m_transport->GetMapId()); break; } } @@ -14283,11 +14290,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // NOW player must have valid map // load the player's map here if it's not already loaded - Map *map = GetMap(); - - // since the player may not be bound to the map yet, make sure subsequent - // getmap calls won't create new maps - SetInstanceId(map->GetInstanceId()); + SetMap(MapManager::Instance().CreateMap(GetMapId(), this)); // if the player is in an instance and it has been reset in the meantime teleport him to the entrance if(GetInstanceId() && !sInstanceSaveManager.GetInstanceSave(GetInstanceId())) @@ -14465,15 +14468,19 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) { sLog.outError("Character %u have wrong data in taxi destination list, teleport to homebind.",GetGUIDLow()); RelocateToHomebind(); - SaveRecallPosition(); // save as recall also to prevent recall and fall from sky } else // have start node, to it { sLog.outError("Character %u have too short taxi destination list, teleport to original node.",GetGUIDLow()); - SetMapId(nodeEntry->map_id); + SetLocationMapId(nodeEntry->map_id); Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z,0.0f); - SaveRecallPosition(); // save as recall also to prevent recall and fall from sky } + + //we can be relocated from taxi and still have an outdated Map pointer! + //so we need to get a new Map pointer! + SetMap(MapManager::Instance().CreateMap(GetMapId(), this)); + SaveRecallPosition(); // save as recall also to prevent recall and fall from sky + m_taxi.ClearTaxiDestinations(); } else if(uint32 node_id = m_taxi.GetTaxiSource()) diff --git a/src/game/Player.h b/src/game/Player.h index efe279b1c..b27883c41 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -2071,7 +2071,7 @@ class MANGOS_DLL_SPEC Player : public Unit float m_homebindX; float m_homebindY; float m_homebindZ; - void RelocateToHomebind() { SetMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); } + void RelocateToHomebind() { SetLocationMapId(m_homebindMapId); Relocate(m_homebindX,m_homebindY,m_homebindZ); } // currently visible objects at player client typedef std::set ClientGUIDs; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 506154833..b16e8d0c2 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4080,7 +4080,6 @@ void Spell::EffectSummonPet(uint32 i) return; OldSummon->GetMap()->Remove((Creature*)OldSummon,false); - OldSummon->SetMapId(m_caster->GetMapId()); float px, py, pz; m_caster->GetClosePoint(px, py, pz, OldSummon->GetObjectSize()); diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp index 6ba0e405e..fdb2f6003 100644 --- a/src/game/Totem.cpp +++ b/src/game/Totem.cpp @@ -54,8 +54,6 @@ void Totem::Update( uint32 time ) void Totem::Summon(Unit* owner) { sLog.outDebug("AddObject at Totem.cpp line 49"); - - SetInstanceId(owner->GetInstanceId()); owner->GetMap()->Add((Creature*)this); // select totem model in dependent from owner team diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp index a338c7b0b..43e854fd0 100644 --- a/src/game/Transports.cpp +++ b/src/game/Transports.cpp @@ -102,7 +102,8 @@ void MapManager::LoadTransports() m_TransportsByMap[*i].insert(t); //If we someday decide to use the grid to track transports, here: - //MapManager::Instance().LoadGrid(mapid,x,y,true); + t->SetMap(MapManager::Instance().CreateMap(mapid, t)); + //t->GetMap()->Add((GameObject *)t); ++count; } while(result->NextRow()); @@ -138,8 +139,6 @@ Transport::Transport() : GameObject() bool Transport::Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags) { Relocate(x,y,z,ang); - - SetMapId(mapid); // instance id and phaseMask isn't set to values different from std. if(!IsPositionValid()) @@ -432,7 +431,6 @@ Transport::WayPointMap::const_iterator Transport::GetNextWayPoint() void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) { Map const* oldMap = GetMap(); - SetMapId(newMapid); Relocate(x, y, z); for(PlayerSet::iterator itr = m_passengers.begin(); itr != m_passengers.end();) @@ -458,7 +456,11 @@ void Transport::TeleportTransport(uint32 newMapid, float x, float y, float z) //plr->GetSession()->SendPacket(&data); } - Map const* newMap = GetMap(); + //we need to create and save new Map object with 'newMapid' because if not done -> lead to invalid Map object reference... + //player far teleport would try to create same instance, but we need it NOW for transport... + //correct me if I'm wrong O.o + Map * newMap = MapManager::Instance().CreateMap(newMapid, this); + SetMap(newMap); if(oldMap != newMap) { diff --git a/src/game/Transports.h b/src/game/Transports.h index 1ade79499..1ae05a753 100644 --- a/src/game/Transports.h +++ b/src/game/Transports.h @@ -54,24 +54,11 @@ class TransportPath std::vector i_nodes; }; -class Transport : protected GameObject +class Transport : public GameObject { public: explicit Transport(); - // prevent using Transports as normal GO, but allow call some inherited functions - using GameObject::IsTransport; - using GameObject::GetEntry; - using GameObject::GetGUID; - using GameObject::GetGUIDLow; - using GameObject::GetMapId; - using GameObject::GetPositionX; - using GameObject::GetPositionY; - using GameObject::GetPositionZ; - using GameObject::BuildCreateUpdateBlockForPlayer; - using GameObject::BuildOutOfRangeUpdateBlock; - using GameObject::GetPackGUID; - bool Create(uint32 guidlow, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags); bool GenerateWaypoints(uint32 pathid, std::set &mapids); void Update(uint32 p_time); diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp index c6c6f9279..5c5fad437 100644 --- a/src/game/Vehicle.cpp +++ b/src/game/Vehicle.cpp @@ -62,8 +62,7 @@ void Vehicle::Update(uint32 diff) bool Vehicle::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 vehicleId, uint32 team) { - SetMapId(map->GetId()); - SetInstanceId(map->GetInstanceId()); + SetMap(map); Object::_Create(guidlow, Entry, HIGHGUID_VEHICLE); diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 2a5d35b2b..798147fe8 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -385,15 +385,9 @@ void WorldSession::LogoutPlayer(bool Save) // the player may not be in the world when logging out // e.g if he got disconnected during a transfer to another map // calls to GetMap in this case may cause crashes - if(_player->IsInWorld()) _player->GetMap()->Remove(_player, false); - // RemoveFromWorld does cleanup that requires the player to be in the accessor - ObjectAccessor::Instance().RemoveObject(_player); - - ///- Delete the player object - _player->CleanupsBeforeDelete(); // do some cleanup before deleting to prevent crash at crossreferences to already deleted data - - delete _player; - _player = NULL; + Map* _map = _player->GetMap(); + _map->Remove(_player, true); + _player = NULL; // deleted in Remove call ///- Send the 'logout complete' packet to the client WorldPacket data( SMSG_LOGOUT_COMPLETE, 0 ); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 33f5a72f5..d3d53e7ab 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8181" + #define REVISION_NR "8182" #endif // __REVISION_NR_H__