2 * Copyright (C) 2005-2008 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 "WorldSession.h"
28 #include "WorldPacket.h"
31 #include "GridNotifiers.h"
32 #include "MapManager.h"
35 #include "GridNotifiersImpl.h"
37 #include "ObjectDefines.h"
38 #include "MapInstanced.h"
42 #define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex>
43 INSTANTIATE_SINGLETON_2(ObjectAccessor
, CLASS_LOCK
);
44 INSTANTIATE_CLASS_MUTEX(ObjectAccessor
, ZThread::FastMutex
);
49 struct MANGOS_DLL_DECL BuildUpdateForPlayer
52 UpdateDataMapType
&i_updatePlayers
;
54 BuildUpdateForPlayer(Player
&player
, UpdateDataMapType
&data_map
) : i_player(player
), i_updatePlayers(data_map
) {}
56 void Visit(PlayerMapType
&m
)
58 for(PlayerMapType::iterator iter
=m
.begin(); iter
!= m
.end(); ++iter
)
60 if( iter
->getSource() == &i_player
)
63 UpdateDataMapType::iterator iter2
= i_updatePlayers
.find(iter
->getSource());
64 if( iter2
== i_updatePlayers
.end() )
66 std::pair
<UpdateDataMapType::iterator
, bool> p
= i_updatePlayers
.insert( ObjectAccessor::UpdateDataValueType(iter
->getSource(), UpdateData()) );
71 i_player
.BuildValuesUpdateBlockForPlayer(&iter2
->second
, iter2
->first
);
75 template<class SKIP
> void Visit(GridRefManager
<SKIP
> &) {}
79 ObjectAccessor::ObjectAccessor() {}
80 ObjectAccessor::~ObjectAccessor() {}
83 ObjectAccessor::GetNPCIfCanInteractWith(Player
const &player
, uint64 guid
, uint32 npcflagmask
)
90 Creature
*unit
= GetCreature(player
, guid
);
95 if(!player
.CanInteractWithNPCs(!unit
->isSpiritService()))
98 // appropriate npc type
99 if(npcflagmask
&& !unit
->HasFlag( UNIT_NPC_FLAGS
, npcflagmask
))
102 // alive or spirit healer
103 if(!unit
->isAlive() && (!unit
->isSpiritService() || player
.isAlive() ))
106 // not allow interaction under control
107 if(unit
->GetCharmerOrOwnerGUID())
111 if( unit
->IsHostileTo(&player
))
115 FactionTemplateEntry
const* factionTemplate
= sFactionTemplateStore
.LookupEntry(unit
->getFaction());
118 FactionEntry
const* faction
= sFactionStore
.LookupEntry(factionTemplate
->faction
);
119 if( faction
->reputationListID
>= 0 && player
.GetReputationRank(faction
) <= REP_UNFRIENDLY
)
124 if(!unit
->IsWithinDistInMap(&player
,INTERACTION_DISTANCE
))
131 ObjectAccessor::GetCreatureOrPet(WorldObject
const &u
, uint64 guid
)
133 if(Creature
*unit
= GetPet(guid
))
136 return GetCreature(u
, guid
);
140 ObjectAccessor::GetCreature(WorldObject
const &u
, uint64 guid
)
142 Creature
* ret
= GetObjectInWorld(guid
, (Creature
*)NULL
);
143 if(ret
&& ret
->GetMapId() != u
.GetMapId()) ret
= NULL
;
148 ObjectAccessor::GetUnit(WorldObject
const &u
, uint64 guid
)
153 if(IS_PLAYER_GUID(guid
))
154 return FindPlayer(guid
);
156 return GetCreatureOrPet(u
, guid
);
160 ObjectAccessor::GetCorpse(WorldObject
const &u
, uint64 guid
)
162 Corpse
* ret
= GetObjectInWorld(guid
, (Corpse
*)NULL
);
163 if(ret
&& ret
->GetMapId() != u
.GetMapId()) ret
= NULL
;
167 Object
* ObjectAccessor::GetObjectByTypeMask(Player
const &p
, uint64 guid
, uint32 typemask
)
171 if(typemask
& TYPEMASK_PLAYER
)
173 obj
= FindPlayer(guid
);
177 if(typemask
& TYPEMASK_UNIT
)
179 obj
= GetCreatureOrPet(p
,guid
);
183 if(typemask
& TYPEMASK_GAMEOBJECT
)
185 obj
= GetGameObject(p
,guid
);
189 if(typemask
& TYPEMASK_DYNAMICOBJECT
)
191 obj
= GetDynamicObject(p
,guid
);
195 if(typemask
& TYPEMASK_ITEM
)
197 obj
= p
.GetItemByGuid( guid
);
205 ObjectAccessor::GetGameObject(WorldObject
const &u
, uint64 guid
)
207 GameObject
* ret
= GetObjectInWorld(guid
, (GameObject
*)NULL
);
208 if(ret
&& ret
->GetMapId() != u
.GetMapId()) ret
= NULL
;
213 ObjectAccessor::GetDynamicObject(Unit
const &u
, uint64 guid
)
215 DynamicObject
* ret
= GetObjectInWorld(guid
, (DynamicObject
*)NULL
);
216 if(ret
&& ret
->GetMapId() != u
.GetMapId()) ret
= NULL
;
221 ObjectAccessor::FindPlayer(uint64 guid
)
223 return GetObjectInWorld(guid
, (Player
*)NULL
);
227 ObjectAccessor::FindPlayerByName(const char *name
)
230 HashMapHolder
<Player
>::MapType
& m
= HashMapHolder
<Player
>::GetContainer();
231 HashMapHolder
<Player
>::MapType::iterator iter
= m
.begin();
232 for(; iter
!= m
.end(); ++iter
)
233 if( ::strcmp(name
, iter
->second
->GetName()) == 0 )
239 ObjectAccessor::SaveAllPlayers()
241 Guard
guard(*HashMapHolder
<Player
*>::GetLock());
242 HashMapHolder
<Player
>::MapType
& m
= HashMapHolder
<Player
>::GetContainer();
243 HashMapHolder
<Player
>::MapType::iterator itr
= m
.begin();
244 for(; itr
!= m
.end(); ++itr
)
245 itr
->second
->SaveToDB();
249 ObjectAccessor::UpdateObject(Object
* obj
, Player
* exceptPlayer
)
251 UpdateDataMapType update_players
;
252 obj
->BuildUpdate(update_players
);
255 for(UpdateDataMapType::iterator iter
= update_players
.begin(); iter
!= update_players
.end(); ++iter
)
257 if(iter
->first
== exceptPlayer
)
260 iter
->second
.BuildPacket(&packet
);
261 iter
->first
->GetSession()->SendPacket(&packet
);
267 ObjectAccessor::AddUpdateObject(Object
*obj
)
269 Guard
guard(i_updateGuard
);
270 i_objects
.insert(obj
);
274 ObjectAccessor::RemoveUpdateObject(Object
*obj
)
276 Guard
guard(i_updateGuard
);
277 std::set
<Object
*>::iterator iter
= i_objects
.find(obj
);
278 if( iter
!= i_objects
.end() )
279 i_objects
.erase( iter
);
283 ObjectAccessor::_buildUpdateObject(Object
*obj
, UpdateDataMapType
&update_players
)
285 bool build_for_all
= true;
287 if( obj
->isType(TYPEMASK_ITEM
) )
289 Item
*item
= static_cast<Item
*>(obj
);
290 pl
= item
->GetOwner();
291 build_for_all
= false;
295 _buildPacket(pl
, obj
, update_players
);
297 // Capt: okey for all those fools who think its a real fix
298 // THIS IS A TEMP FIX
301 WorldObject
* temp
= dynamic_cast<WorldObject
*>(obj
);
303 //assert(dynamic_cast<WorldObject*>(obj)!=NULL);
305 _buildChangeObjectForPlayer(temp
, update_players
);
307 sLog
.outDebug("ObjectAccessor: Ln 405 Temp bug fix");
312 ObjectAccessor::_buildPacket(Player
*pl
, Object
*obj
, UpdateDataMapType
&update_players
)
314 UpdateDataMapType::iterator iter
= update_players
.find(pl
);
316 if( iter
== update_players
.end() )
318 std::pair
<UpdateDataMapType::iterator
, bool> p
= update_players
.insert( UpdateDataValueType(pl
, UpdateData()) );
323 obj
->BuildValuesUpdateBlockForPlayer(&iter
->second
, iter
->first
);
327 ObjectAccessor::_buildChangeObjectForPlayer(WorldObject
*obj
, UpdateDataMapType
&update_players
)
329 CellPair p
= MaNGOS::ComputeCellPair(obj
->GetPositionX(), obj
->GetPositionY());
331 cell
.data
.Part
.reserved
= ALL_DISTRICT
;
333 WorldObjectChangeAccumulator
notifier(*obj
, update_players
);
334 TypeContainerVisitor
<WorldObjectChangeAccumulator
, WorldTypeMapContainer
> player_notifier(notifier
);
335 CellLock
<GridReadGuard
> cell_lock(cell
, p
);
336 cell_lock
->Visit(cell_lock
, player_notifier
, *MapManager::Instance().GetMap(obj
->GetMapId(), obj
));
340 ObjectAccessor::GetPet(uint64 guid
)
342 return GetObjectInWorld(guid
, (Pet
*)NULL
);
346 ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid
)
348 Guard
guard(i_corpseGuard
);
350 Player2CorpsesMapType::iterator iter
= i_player2corpse
.find(guid
);
351 if( iter
== i_player2corpse
.end() ) return NULL
;
353 assert(iter
->second
->GetType() != CORPSE_BONES
);
359 ObjectAccessor::RemoveCorpse(Corpse
*corpse
)
361 assert(corpse
&& corpse
->GetType() != CORPSE_BONES
);
363 Guard
guard(i_corpseGuard
);
364 Player2CorpsesMapType::iterator iter
= i_player2corpse
.find(corpse
->GetOwnerGUID());
365 if( iter
== i_player2corpse
.end() )
368 // build mapid*cellid -> guid_set map
369 CellPair cell_pair
= MaNGOS::ComputeCellPair(corpse
->GetPositionX(), corpse
->GetPositionY());
370 uint32 cell_id
= (cell_pair
.y_coord
*TOTAL_NUMBER_OF_CELLS_PER_MAP
) + cell_pair
.x_coord
;
372 objmgr
.DeleteCorpseCellData(corpse
->GetMapId(),cell_id
,corpse
->GetOwnerGUID());
373 corpse
->RemoveFromWorld();
375 i_player2corpse
.erase(iter
);
379 ObjectAccessor::AddCorpse(Corpse
*corpse
)
381 assert(corpse
&& corpse
->GetType() != CORPSE_BONES
);
383 Guard
guard(i_corpseGuard
);
384 assert(i_player2corpse
.find(corpse
->GetOwnerGUID()) == i_player2corpse
.end());
385 i_player2corpse
[corpse
->GetOwnerGUID()] = corpse
;
387 // build mapid*cellid -> guid_set map
388 CellPair cell_pair
= MaNGOS::ComputeCellPair(corpse
->GetPositionX(), corpse
->GetPositionY());
389 uint32 cell_id
= (cell_pair
.y_coord
*TOTAL_NUMBER_OF_CELLS_PER_MAP
) + cell_pair
.x_coord
;
391 objmgr
.AddCorpseCellData(corpse
->GetMapId(),cell_id
,corpse
->GetOwnerGUID(),corpse
->GetInstanceId());
395 ObjectAccessor::AddCorpsesToGrid(GridPair
const& gridpair
,GridType
& grid
,Map
* map
)
397 Guard
guard(i_corpseGuard
);
398 for(Player2CorpsesMapType::iterator iter
= i_player2corpse
.begin(); iter
!= i_player2corpse
.end(); ++iter
)
399 if(iter
->second
->GetGrid()==gridpair
)
401 // verify, if the corpse in our instance (add only corpses which are)
402 if (map
->Instanceable())
404 if (iter
->second
->GetInstanceId() == map
->GetInstanceId())
406 grid
.AddWorldObject(iter
->second
,iter
->second
->GetGUID());
411 grid
.AddWorldObject(iter
->second
,iter
->second
->GetGUID());
417 ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid
)
419 Corpse
*corpse
= GetCorpseForPlayerGUID(player_guid
);
422 //in fact this function is called from several places
423 //even when player doesn't have a corpse, not an error
424 //sLog.outError("ERROR: Try remove corpse that not in map for GUID %ul", player_guid);
428 DEBUG_LOG("Deleting Corpse and spawning bones.\n");
430 // remove corpse from player_guid -> corpse map
431 RemoveCorpse(corpse
);
433 // remove resurrectble corpse from grid object registry (loaded state checked into call)
434 // do not load the map if it's not loaded
435 Map
*map
= MapManager::Instance().FindMap(corpse
->GetMapId(), corpse
->GetInstanceId());
436 if(map
) map
->Remove(corpse
,false);
438 // remove corpse from DB
439 corpse
->DeleteFromDB();
441 Corpse
*bones
= NULL
;
442 // create the bones only if the map and the grid is loaded at the corpse's location
443 if(map
&& !map
->IsRemovalGrid(corpse
->GetPositionX(), corpse
->GetPositionY()))
445 // Create bones, don't change Corpse
447 bones
->Create(corpse
->GetGUIDLow());
449 for (int i
= 3; i
< CORPSE_END
; i
++) // don't overwrite guid and object type
450 bones
->SetUInt32Value(i
, corpse
->GetUInt32Value(i
));
452 bones
->SetGrid(corpse
->GetGrid());
453 // bones->m_time = m_time; // don't overwrite time
454 // bones->m_inWorld = m_inWorld; // don't overwrite world state
455 // bones->m_type = m_type; // don't overwrite type
456 bones
->Relocate(corpse
->GetPositionX(), corpse
->GetPositionY(), corpse
->GetPositionZ(), corpse
->GetOrientation());
457 bones
->SetMapId(corpse
->GetMapId());
458 bones
->SetInstanceId(corpse
->GetInstanceId());
460 bones
->SetUInt32Value(CORPSE_FIELD_FLAGS
, CORPSE_FLAG_UNK2
| CORPSE_FLAG_BONES
);
461 bones
->SetUInt64Value(CORPSE_FIELD_OWNER
, 0);
463 for (int i
= 0; i
< EQUIPMENT_SLOT_END
; i
++)
465 if(corpse
->GetUInt32Value(CORPSE_FIELD_ITEM
+ i
))
466 bones
->SetUInt32Value(CORPSE_FIELD_ITEM
+ i
, 0);
469 // add bones in grid store if grid loaded where corpse placed
473 // all references to the corpse should be removed at this point
480 ObjectAccessor::Update(uint32 diff
)
482 UpdateDataMapType update_players
;
484 Guard
guard(i_updateGuard
);
485 while(!i_objects
.empty())
487 Object
* obj
= *i_objects
.begin();
488 i_objects
.erase(i_objects
.begin());
491 _buildUpdateObject(obj
, update_players
);
492 obj
->ClearUpdateMask(false);
496 WorldPacket packet
; // here we allocate a std::vector with a size of 0x10000
497 for(UpdateDataMapType::iterator iter
= update_players
.begin(); iter
!= update_players
.end(); ++iter
)
499 iter
->second
.BuildPacket(&packet
);
500 iter
->first
->GetSession()->SendPacket(&packet
);
501 packet
.clear(); // clean the string
506 ObjectAccessor::UpdatePlayers(uint32 diff
)
508 HashMapHolder
<Player
>::MapType
& playerMap
= HashMapHolder
<Player
>::GetContainer();
509 for(HashMapHolder
<Player
>::MapType::iterator iter
= playerMap
.begin(); iter
!= playerMap
.end(); ++iter
)
510 if(iter
->second
->IsInWorld())
511 iter
->second
->Update(diff
);
515 ObjectAccessor::PlayersNearGrid(uint32 x
, uint32 y
, uint32 m_id
, uint32 i_id
) const
517 CellPair
cell_min(x
*MAX_NUMBER_OF_CELLS
, y
*MAX_NUMBER_OF_CELLS
);
518 CellPair
cell_max(cell_min
.x_coord
+ MAX_NUMBER_OF_CELLS
, cell_min
.y_coord
+MAX_NUMBER_OF_CELLS
);
525 HashMapHolder
<Player
>::MapType
& playerMap
= HashMapHolder
<Player
>::GetContainer();
526 for(HashMapHolder
<Player
>::MapType::const_iterator iter
=playerMap
.begin(); iter
!= playerMap
.end(); ++iter
)
528 if( m_id
!= iter
->second
->GetMapId() || i_id
!= iter
->second
->GetInstanceId() )
531 CellPair p
= MaNGOS::ComputeCellPair(iter
->second
->GetPositionX(), iter
->second
->GetPositionY());
532 if( (cell_min
.x_coord
<= p
.x_coord
&& p
.x_coord
<= cell_max
.x_coord
) &&
533 (cell_min
.y_coord
<= p
.y_coord
&& p
.y_coord
<= cell_max
.y_coord
) )
541 ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType
&m
)
543 for(PlayerMapType::iterator iter
= m
.begin(); iter
!= m
.end(); ++iter
)
544 if(iter
->getSource()->HaveAtClient(&i_object
))
545 ObjectAccessor::_buildPacket(iter
->getSource(), &i_object
, i_updateDatas
);
549 ObjectAccessor::UpdateObjectVisibility(WorldObject
*obj
)
551 CellPair p
= MaNGOS::ComputeCellPair(obj
->GetPositionX(), obj
->GetPositionY());
554 MapManager::Instance().GetMap(obj
->GetMapId(), obj
)->UpdateObjectVisibility(obj
,cell
,p
);
557 void ObjectAccessor::UpdateVisibilityForPlayer( Player
* player
)
559 CellPair p
= MaNGOS::ComputeCellPair(player
->GetPositionX(), player
->GetPositionY());
561 Map
* m
= MapManager::Instance().GetMap(player
->GetMapId(),player
);
563 m
->UpdatePlayerVisibility(player
,cell
,p
);
564 m
->UpdateObjectsVisibilityFor(player
,cell
,p
);
567 /// Define the static member of HashMapHolder
569 template <class T
> UNORDERED_MAP
< uint64
, T
* > HashMapHolder
<T
>::m_objectMap
;
570 template <class T
> ZThread::FastMutex HashMapHolder
<T
>::i_lock
;
572 /// Global defintions for the hashmap storage
574 template class HashMapHolder
<Player
>;
575 template class HashMapHolder
<Pet
>;
576 template class HashMapHolder
<GameObject
>;
577 template class HashMapHolder
<DynamicObject
>;
578 template class HashMapHolder
<Creature
>;
579 template class HashMapHolder
<Corpse
>;
581 template Player
* ObjectAccessor::GetObjectInWorld
<Player
>(uint32 mapid
, float x
, float y
, uint64 guid
, Player
* /*fake*/);
582 template Pet
* ObjectAccessor::GetObjectInWorld
<Pet
>(uint32 mapid
, float x
, float y
, uint64 guid
, Pet
* /*fake*/);
583 template Creature
* ObjectAccessor::GetObjectInWorld
<Creature
>(uint32 mapid
, float x
, float y
, uint64 guid
, Creature
* /*fake*/);
584 template Corpse
* ObjectAccessor::GetObjectInWorld
<Corpse
>(uint32 mapid
, float x
, float y
, uint64 guid
, Corpse
* /*fake*/);
585 template GameObject
* ObjectAccessor::GetObjectInWorld
<GameObject
>(uint32 mapid
, float x
, float y
, uint64 guid
, GameObject
* /*fake*/);
586 template DynamicObject
* ObjectAccessor::GetObjectInWorld
<DynamicObject
>(uint32 mapid
, float x
, float y
, uint64 guid
, DynamicObject
* /*fake*/);