2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "ObjectAccessor.h"
20 #include "ObjectMgr.h"
21 #include "Policies/SingletonImp.h"
24 #include "GameObject.h"
25 #include "DynamicObject.h"
27 #include "WorldPacket.h"
30 #include "GridNotifiers.h"
31 #include "MapManager.h"
34 #include "GridNotifiersImpl.h"
36 #include "ObjectDefines.h"
37 #include "MapInstanced.h"
42 #define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
43 INSTANTIATE_SINGLETON_2(ObjectAccessor
, CLASS_LOCK
);
44 INSTANTIATE_CLASS_MUTEX(ObjectAccessor
, ACE_Thread_Mutex
);
46 ObjectAccessor::ObjectAccessor() {}
47 ObjectAccessor::~ObjectAccessor()
49 for(Player2CorpsesMapType::const_iterator itr
= i_player2corpse
.begin(); itr
!= i_player2corpse
.end(); ++itr
)
54 ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject
const &u
, uint64 guid
)
56 if(IS_PLAYER_GUID(guid
))
62 if(IS_VEHICLE_GUID(guid
))
63 return GetVehicle(guid
);
65 return u
.IsInWorld() ? u
.GetMap()->GetCreature(guid
) : NULL
;
69 ObjectAccessor::GetUnit(WorldObject
const &u
, uint64 guid
)
74 if(IS_PLAYER_GUID(guid
))
75 return FindPlayer(guid
);
77 return GetCreatureOrPetOrVehicle(u
, guid
);
81 ObjectAccessor::GetCorpse(WorldObject
const &u
, uint64 guid
)
83 Corpse
* ret
= GetObjectInWorld(guid
, (Corpse
*)NULL
);
86 if(ret
->GetMapId() != u
.GetMapId())
88 if(ret
->GetInstanceId() != u
.GetInstanceId())
93 WorldObject
* ObjectAccessor::GetWorldObject(WorldObject
const &p
, uint64 guid
)
95 switch(GUID_HIPART(guid
))
97 case HIGHGUID_PLAYER
: return FindPlayer(guid
);
98 case HIGHGUID_GAMEOBJECT
: return p
.GetMap()->GetGameObject(guid
);
99 case HIGHGUID_UNIT
: return p
.GetMap()->GetCreature(guid
);
100 case HIGHGUID_PET
: return GetPet(guid
);
101 case HIGHGUID_VEHICLE
: return GetVehicle(guid
);
102 case HIGHGUID_DYNAMICOBJECT
:return p
.GetMap()->GetDynamicObject(guid
);
103 case HIGHGUID_TRANSPORT
: return NULL
;
104 case HIGHGUID_CORPSE
: return GetCorpse(p
,guid
);
105 case HIGHGUID_MO_TRANSPORT
: return NULL
;
112 Object
* ObjectAccessor::GetObjectByTypeMask(WorldObject
const &p
, uint64 guid
, uint32 typemask
)
114 switch(GUID_HIPART(guid
))
117 if(typemask
& TYPEMASK_ITEM
&& p
.GetTypeId() == TYPEID_PLAYER
)
118 return ((Player
const &)p
).GetItemByGuid( guid
);
120 case HIGHGUID_PLAYER
:
121 if(typemask
& TYPEMASK_PLAYER
)
122 return FindPlayer(guid
);
124 case HIGHGUID_GAMEOBJECT
:
125 if(typemask
& TYPEMASK_GAMEOBJECT
)
126 return p
.GetMap()->GetGameObject(guid
);
129 if(typemask
& TYPEMASK_UNIT
)
130 return p
.GetMap()->GetCreature(guid
);
133 if(typemask
& TYPEMASK_UNIT
)
136 case HIGHGUID_VEHICLE
:
137 if(typemask
& TYPEMASK_UNIT
)
138 return GetVehicle(guid
);
140 case HIGHGUID_DYNAMICOBJECT
:
141 if(typemask
& TYPEMASK_DYNAMICOBJECT
)
142 return p
.GetMap()->GetDynamicObject(guid
);
144 case HIGHGUID_TRANSPORT
:
145 case HIGHGUID_CORPSE
:
146 case HIGHGUID_MO_TRANSPORT
:
154 ObjectAccessor::FindPlayer(uint64 guid
)
156 Player
* plr
= GetObjectInWorld(guid
, (Player
*)NULL
);
157 if(!plr
|| !plr
->IsInWorld())
164 ObjectAccessor::FindPlayerByName(const char *name
)
167 HashMapHolder
<Player
>::MapType
& m
= HashMapHolder
<Player
>::GetContainer();
168 HashMapHolder
<Player
>::MapType::iterator iter
= m
.begin();
169 for(; iter
!= m
.end(); ++iter
)
170 if(iter
->second
->IsInWorld() && ( ::strcmp(name
, iter
->second
->GetName()) == 0 ))
176 ObjectAccessor::SaveAllPlayers()
178 Guard
guard(*HashMapHolder
<Player
*>::GetLock());
179 HashMapHolder
<Player
>::MapType
& m
= HashMapHolder
<Player
>::GetContainer();
180 HashMapHolder
<Player
>::MapType::iterator itr
= m
.begin();
181 for(; itr
!= m
.end(); ++itr
)
182 itr
->second
->SaveToDB();
186 ObjectAccessor::UpdateObject(Object
* obj
, Player
* exceptPlayer
)
188 UpdateDataMapType update_players
;
189 obj
->BuildUpdate(update_players
);
192 for(UpdateDataMapType::iterator iter
= update_players
.begin(); iter
!= update_players
.end(); ++iter
)
194 if(iter
->first
== exceptPlayer
)
197 iter
->second
.BuildPacket(&packet
);
198 iter
->first
->GetSession()->SendPacket(&packet
);
204 ObjectAccessor::_buildUpdateObject(Object
*obj
, UpdateDataMapType
&update_players
)
206 bool build_for_all
= true;
208 if( obj
->isType(TYPEMASK_ITEM
) )
210 Item
*item
= static_cast<Item
*>(obj
);
211 pl
= item
->GetOwner();
212 build_for_all
= false;
216 _buildPacket(pl
, obj
, update_players
);
218 // Capt: okey for all those fools who think its a real fix
219 // THIS IS A TEMP FIX
222 WorldObject
* temp
= dynamic_cast<WorldObject
*>(obj
);
224 //assert(dynamic_cast<WorldObject*>(obj)!=NULL);
226 _buildChangeObjectForPlayer(temp
, update_players
);
228 sLog
.outDebug("ObjectAccessor: Ln 405 Temp bug fix");
233 ObjectAccessor::_buildPacket(Player
*pl
, Object
*obj
, UpdateDataMapType
&update_players
)
235 UpdateDataMapType::iterator iter
= update_players
.find(pl
);
237 if( iter
== update_players
.end() )
239 std::pair
<UpdateDataMapType::iterator
, bool> p
= update_players
.insert( UpdateDataValueType(pl
, UpdateData()) );
244 obj
->BuildValuesUpdateBlockForPlayer(&iter
->second
, iter
->first
);
248 ObjectAccessor::_buildChangeObjectForPlayer(WorldObject
*obj
, UpdateDataMapType
&update_players
)
250 CellPair p
= MaNGOS::ComputeCellPair(obj
->GetPositionX(), obj
->GetPositionY());
252 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
254 WorldObjectChangeAccumulator
notifier(*obj
, update_players
);
255 TypeContainerVisitor
<WorldObjectChangeAccumulator
, WorldTypeMapContainer
> player_notifier(notifier
);
256 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
257 cell_lock
->Visit(cell_lock
, player_notifier
, *obj
->GetMap());
261 ObjectAccessor::GetPet(uint64 guid
)
263 return GetObjectInWorld(guid
, (Pet
*)NULL
);
267 ObjectAccessor::GetVehicle(uint64 guid
)
269 return GetObjectInWorld(guid
, (Vehicle
*)NULL
);
273 ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid
)
275 Guard
guard(i_corpseGuard
);
277 Player2CorpsesMapType::iterator iter
= i_player2corpse
.find(guid
);
278 if( iter
== i_player2corpse
.end() ) return NULL
;
280 assert(iter
->second
->GetType() != CORPSE_BONES
);
286 ObjectAccessor::RemoveCorpse(Corpse
*corpse
)
288 assert(corpse
&& corpse
->GetType() != CORPSE_BONES
);
290 Guard
guard(i_corpseGuard
);
291 Player2CorpsesMapType::iterator iter
= i_player2corpse
.find(corpse
->GetOwnerGUID());
292 if( iter
== i_player2corpse
.end() )
295 // build mapid*cellid -> guid_set map
296 CellPair cell_pair
= MaNGOS::ComputeCellPair(corpse
->GetPositionX(), corpse
->GetPositionY());
297 uint32 cell_id
= (cell_pair
.y_coord
*TOTAL_NUMBER_OF_CELLS_PER_MAP
) + cell_pair
.x_coord
;
299 objmgr
.DeleteCorpseCellData(corpse
->GetMapId(), cell_id
, corpse
->GetOwnerGUID());
300 corpse
->RemoveFromWorld();
302 i_player2corpse
.erase(iter
);
306 ObjectAccessor::AddCorpse(Corpse
*corpse
)
308 assert(corpse
&& corpse
->GetType() != CORPSE_BONES
);
310 Guard
guard(i_corpseGuard
);
311 assert(i_player2corpse
.find(corpse
->GetOwnerGUID()) == i_player2corpse
.end());
312 i_player2corpse
[corpse
->GetOwnerGUID()] = corpse
;
314 // build mapid*cellid -> guid_set map
315 CellPair cell_pair
= MaNGOS::ComputeCellPair(corpse
->GetPositionX(), corpse
->GetPositionY());
316 uint32 cell_id
= (cell_pair
.y_coord
*TOTAL_NUMBER_OF_CELLS_PER_MAP
) + cell_pair
.x_coord
;
318 objmgr
.AddCorpseCellData(corpse
->GetMapId(), cell_id
, corpse
->GetOwnerGUID(), corpse
->GetInstanceId());
322 ObjectAccessor::AddCorpsesToGrid(GridPair
const& gridpair
,GridType
& grid
,Map
* map
)
324 Guard
guard(i_corpseGuard
);
325 for(Player2CorpsesMapType::iterator iter
= i_player2corpse
.begin(); iter
!= i_player2corpse
.end(); ++iter
)
326 if(iter
->second
->GetGrid() == gridpair
)
328 // verify, if the corpse in our instance (add only corpses which are)
329 if (map
->Instanceable())
331 if (iter
->second
->GetInstanceId() == map
->GetInstanceId())
333 grid
.AddWorldObject(iter
->second
, iter
->second
->GetGUID());
338 grid
.AddWorldObject(iter
->second
, iter
->second
->GetGUID());
344 ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid
, bool insignia
)
346 Corpse
*corpse
= GetCorpseForPlayerGUID(player_guid
);
349 //in fact this function is called from several places
350 //even when player doesn't have a corpse, not an error
351 //sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid);
355 DEBUG_LOG("Deleting Corpse and spawning bones.");
357 // remove corpse from player_guid -> corpse map
358 RemoveCorpse(corpse
);
360 // remove resurrectable corpse from grid object registry (loaded state checked into call)
361 // do not load the map if it's not loaded
362 Map
*map
= MapManager::Instance().FindMap(corpse
->GetMapId(), corpse
->GetInstanceId());
364 map
->Remove(corpse
, false);
366 // remove corpse from DB
367 corpse
->DeleteFromDB();
369 Corpse
*bones
= NULL
;
370 // create the bones only if the map and the grid is loaded at the corpse's location
371 // ignore bones creating option in case insignia
372 if (map
&& (insignia
||
373 (map
->IsBattleGroundOrArena() ? sWorld
.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA
) : sWorld
.getConfig(CONFIG_DEATH_BONES_WORLD
))) &&
374 !map
->IsRemovalGrid(corpse
->GetPositionX(), corpse
->GetPositionY()))
376 // Create bones, don't change Corpse
378 bones
->Create(corpse
->GetGUIDLow());
380 for (int i
= 3; i
< CORPSE_END
; ++i
) // don't overwrite guid and object type
381 bones
->SetUInt32Value(i
, corpse
->GetUInt32Value(i
));
383 bones
->SetGrid(corpse
->GetGrid());
384 // bones->m_time = m_time; // don't overwrite time
385 // bones->m_inWorld = m_inWorld; // don't overwrite world state
386 // bones->m_type = m_type; // don't overwrite type
387 bones
->Relocate(corpse
->GetPositionX(), corpse
->GetPositionY(), corpse
->GetPositionZ(), corpse
->GetOrientation());
388 bones
->SetPhaseMask(corpse
->GetPhaseMask(), false);
390 bones
->SetUInt32Value(CORPSE_FIELD_FLAGS
, CORPSE_FLAG_UNK2
| CORPSE_FLAG_BONES
);
391 bones
->SetUInt64Value(CORPSE_FIELD_OWNER
, 0);
393 for (int i
= 0; i
< EQUIPMENT_SLOT_END
; ++i
)
395 if(corpse
->GetUInt32Value(CORPSE_FIELD_ITEM
+ i
))
396 bones
->SetUInt32Value(CORPSE_FIELD_ITEM
+ i
, 0);
399 // add bones in grid store if grid loaded where corpse placed
403 // all references to the corpse should be removed at this point
410 ObjectAccessor::Update(uint32 diff
)
412 UpdateDataMapType update_players
;
414 Guard
guard(i_updateGuard
);
415 while(!i_objects
.empty())
417 Object
* obj
= *i_objects
.begin();
418 i_objects
.erase(i_objects
.begin());
421 _buildUpdateObject(obj
, update_players
);
422 obj
->ClearUpdateMask(false);
426 WorldPacket packet
; // here we allocate a std::vector with a size of 0x10000
427 for(UpdateDataMapType::iterator iter
= update_players
.begin(); iter
!= update_players
.end(); ++iter
)
429 iter
->second
.BuildPacket(&packet
);
430 iter
->first
->GetSession()->SendPacket(&packet
);
431 packet
.clear(); // clean the string
436 ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType
&m
)
438 for(PlayerMapType::iterator iter
= m
.begin(); iter
!= m
.end(); ++iter
)
439 if(iter
->getSource()->HaveAtClient(&i_object
))
440 ObjectAccessor::_buildPacket(iter
->getSource(), &i_object
, i_updateDatas
);
444 ObjectAccessor::UpdateObjectVisibility(WorldObject
*obj
)
446 CellPair p
= MaNGOS::ComputeCellPair(obj
->GetPositionX(), obj
->GetPositionY());
449 obj
->GetMap()->UpdateObjectVisibility(obj
, cell
, p
);
452 void ObjectAccessor::UpdateVisibilityForPlayer( Player
* player
)
454 CellPair p
= MaNGOS::ComputeCellPair(player
->GetPositionX(), player
->GetPositionY());
456 Map
* m
= player
->GetMap();
458 m
->UpdatePlayerVisibility(player
, cell
, p
);
459 m
->UpdateObjectsVisibilityFor(player
, cell
, p
);
462 /// Define the static member of HashMapHolder
464 template <class T
> UNORDERED_MAP
< uint64
, T
* > HashMapHolder
<T
>::m_objectMap
;
465 template <class T
> ACE_Thread_Mutex HashMapHolder
<T
>::i_lock
;
467 /// Global definitions for the hashmap storage
469 template class HashMapHolder
<Player
>;
470 template class HashMapHolder
<Pet
>;
471 template class HashMapHolder
<Vehicle
>;
472 template class HashMapHolder
<GameObject
>;
473 template class HashMapHolder
<DynamicObject
>;
474 template class HashMapHolder
<Creature
>;
475 template class HashMapHolder
<Corpse
>;
477 template Player
* ObjectAccessor::GetObjectInWorld
<Player
>(uint32 mapid
, float x
, float y
, uint64 guid
, Player
* /*fake*/);
478 template Pet
* ObjectAccessor::GetObjectInWorld
<Pet
>(uint32 mapid
, float x
, float y
, uint64 guid
, Pet
* /*fake*/);
479 template Vehicle
* ObjectAccessor::GetObjectInWorld
<Vehicle
>(uint32 mapid
, float x
, float y
, uint64 guid
, Vehicle
* /*fake*/);
480 template Creature
* ObjectAccessor::GetObjectInWorld
<Creature
>(uint32 mapid
, float x
, float y
, uint64 guid
, Creature
* /*fake*/);
481 template Corpse
* ObjectAccessor::GetObjectInWorld
<Corpse
>(uint32 mapid
, float x
, float y
, uint64 guid
, Corpse
* /*fake*/);
482 template GameObject
* ObjectAccessor::GetObjectInWorld
<GameObject
>(uint32 mapid
, float x
, float y
, uint64 guid
, GameObject
* /*fake*/);
483 template DynamicObject
* ObjectAccessor::GetObjectInWorld
<DynamicObject
>(uint32 mapid
, float x
, float y
, uint64 guid
, DynamicObject
* /*fake*/);