root/trunk/src/game/ObjectAccessor.cpp @ 123

Revision 120, 20.8 kB (checked in by yumileroy, 17 years ago)

[svn] * Allow WorldObjects? to keep the grid active, and prevent it from being unloaded. This can be done through calling WorldObject::setActive(bool) from the scripting library. Note that entire instances are still unloaded if no player is present on that map to save resources. This behavior can be changed if the need arises.

Original author: w12x
Date: 2008-10-27 08:41:55-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "ObjectAccessor.h"
22#include "ObjectMgr.h"
23#include "Policies/SingletonImp.h"
24#include "Player.h"
25#include "Creature.h"
26#include "GameObject.h"
27#include "DynamicObject.h"
28#include "Corpse.h"
29#include "WorldSession.h"
30#include "WorldPacket.h"
31#include "Item.h"
32#include "Corpse.h"
33#include "GridNotifiers.h"
34#include "MapManager.h"
35#include "Map.h"
36#include "CellImpl.h"
37#include "GridNotifiersImpl.h"
38#include "Opcodes.h"
39#include "ObjectDefines.h"
40#include "MapInstanced.h"
41
42#include <cmath>
43
44#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex>
45INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
46INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ZThread::FastMutex);
47
48namespace Trinity
49{
50
51    struct TRINITY_DLL_DECL BuildUpdateForPlayer
52    {
53        Player &i_player;
54        UpdateDataMapType &i_updatePlayers;
55
56        BuildUpdateForPlayer(Player &player, UpdateDataMapType &data_map) : i_player(player), i_updatePlayers(data_map) {}
57
58        void Visit(PlayerMapType &m)
59        {
60            for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
61            {
62                if( iter->getSource() == &i_player )
63                    continue;
64
65                UpdateDataMapType::iterator iter2 = i_updatePlayers.find(iter->getSource());
66                if( iter2 == i_updatePlayers.end() )
67                {
68                    std::pair<UpdateDataMapType::iterator, bool> p = i_updatePlayers.insert( ObjectAccessor::UpdateDataValueType(iter->getSource(), UpdateData()) );
69                    assert(p.second);
70                    iter2 = p.first;
71                }
72
73                i_player.BuildValuesUpdateBlockForPlayer(&iter2->second, iter2->first);
74            }
75        }
76
77        template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
78    };
79}
80
81ObjectAccessor::ObjectAccessor() {}
82ObjectAccessor::~ObjectAccessor() {}
83
84Creature*
85ObjectAccessor::GetNPCIfCanInteractWith(Player const &player, uint64 guid, uint32 npcflagmask)
86{
87    // unit checks
88    if (!guid)
89        return NULL;
90
91    // exist
92    Creature *unit = GetCreature(player, guid);
93    if (!unit)
94        return NULL;
95
96    // player check
97    if(!player.CanInteractWithNPCs(!unit->isSpiritService()))
98        return NULL;
99
100    // appropriate npc type
101    if(npcflagmask && !unit->HasFlag( UNIT_NPC_FLAGS, npcflagmask ))
102        return NULL;
103
104    // alive or spirit healer
105    if(!unit->isAlive() && (!unit->isSpiritService() || player.isAlive() ))
106        return NULL;
107
108    // not allow interaction under control
109    if(unit->GetCharmerOrOwnerGUID())
110        return NULL;
111
112    // not enemy
113    if( unit->IsHostileTo(&player))
114        return NULL;
115
116    // not unfriendly
117    FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(unit->getFaction());
118    if(factionTemplate)
119    {
120        FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction);
121        if( faction->reputationListID >= 0 && player.GetReputationRank(faction) <= REP_UNFRIENDLY)
122            return NULL;
123    }
124
125    // not too far
126    if(!unit->IsWithinDistInMap(&player,INTERACTION_DISTANCE))
127        return NULL;
128
129    return unit;
130}
131
132Creature*
133ObjectAccessor::GetCreatureOrPet(WorldObject const &u, uint64 guid)
134{
135    if(Creature *unit = GetPet(guid))
136        return unit;
137
138    return GetCreature(u, guid);
139}
140
141Creature*
142ObjectAccessor::GetCreature(WorldObject const &u, uint64 guid)
143{
144    Creature * ret = GetObjectInWorld(guid, (Creature*)NULL);
145    if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
146    return ret;
147}
148
149Unit*
150ObjectAccessor::GetUnit(WorldObject const &u, uint64 guid)
151{
152    if(!guid)
153        return NULL;
154
155    if(IS_PLAYER_GUID(guid))
156        return FindPlayer(guid);
157
158    return GetCreatureOrPet(u, guid);
159}
160
161Corpse*
162ObjectAccessor::GetCorpse(WorldObject const &u, uint64 guid)
163{
164    Corpse * ret = GetObjectInWorld(guid, (Corpse*)NULL);
165    if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
166    return ret;
167}
168
169Object* ObjectAccessor::GetObjectByTypeMask(Player const &p, uint64 guid, uint32 typemask)
170{
171    Object *obj = NULL;
172
173    if(typemask & TYPEMASK_PLAYER)
174    {
175        obj = FindPlayer(guid);
176        if(obj) return obj;
177    }
178
179    if(typemask & TYPEMASK_UNIT)
180    {
181        obj = GetCreatureOrPet(p,guid);
182        if(obj) return obj;
183    }
184
185    if(typemask & TYPEMASK_GAMEOBJECT)
186    {
187        obj = GetGameObject(p,guid);
188        if(obj) return obj;
189    }
190
191    if(typemask & TYPEMASK_DYNAMICOBJECT)
192    {
193        obj = GetDynamicObject(p,guid);
194        if(obj) return obj;
195    }
196
197    if(typemask & TYPEMASK_ITEM)
198    {
199        obj = p.GetItemByGuid( guid );
200        if(obj) return obj;
201    }
202
203    return NULL;
204}
205
206GameObject*
207ObjectAccessor::GetGameObject(WorldObject const &u, uint64 guid)
208{
209    GameObject * ret = GetObjectInWorld(guid, (GameObject*)NULL);
210    if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
211    return ret;
212}
213
214DynamicObject*
215ObjectAccessor::GetDynamicObject(Unit const &u, uint64 guid)
216{
217    DynamicObject * ret = GetObjectInWorld(guid, (DynamicObject*)NULL);
218    if(ret && ret->GetMapId() != u.GetMapId()) ret = NULL;
219    return ret;
220}
221
222Player*
223ObjectAccessor::FindPlayer(uint64 guid)
224{
225    return GetObjectInWorld(guid, (Player*)NULL);
226}
227
228Player*
229ObjectAccessor::FindPlayerByName(const char *name)
230{
231    //TODO: Player Guard
232    HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
233    HashMapHolder<Player>::MapType::iterator iter = m.begin();
234    for(; iter != m.end(); ++iter)
235        if( ::strcmp(name, iter->second->GetName()) == 0 )
236            return iter->second;
237    return NULL;
238}
239
240void
241ObjectAccessor::SaveAllPlayers()
242{
243    Guard guard(*HashMapHolder<Player*>::GetLock());
244    HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
245    HashMapHolder<Player>::MapType::iterator itr = m.begin();
246    for(; itr != m.end(); ++itr)
247        itr->second->SaveToDB();
248}
249
250void
251ObjectAccessor::_update()
252{
253    UpdateDataMapType update_players;
254    {
255        Guard guard(i_updateGuard);
256        while(!i_objects.empty())
257        {
258            Object* obj = *i_objects.begin();
259            i_objects.erase(i_objects.begin());
260            if (!obj)
261                continue;
262            _buildUpdateObject(obj, update_players);
263            obj->ClearUpdateMask(false);
264        }
265    }
266
267    WorldPacket packet;                                     // here we allocate a std::vector with a size of 0x10000
268    for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
269    {
270        iter->second.BuildPacket(&packet);
271        iter->first->GetSession()->SendPacket(&packet);
272        packet.clear();                                     // clean the string
273    }
274}
275
276void
277ObjectAccessor::UpdateObject(Object* obj, Player* exceptPlayer)
278{
279    UpdateDataMapType update_players;
280    obj->BuildUpdate(update_players);
281
282    WorldPacket packet;
283    for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
284    {
285        if(iter->first == exceptPlayer)
286            continue;
287
288        iter->second.BuildPacket(&packet);
289        iter->first->GetSession()->SendPacket(&packet);
290        packet.clear();
291    }
292}
293
294void
295ObjectAccessor::AddUpdateObject(Object *obj)
296{
297    Guard guard(i_updateGuard);
298    i_objects.insert(obj);
299}
300
301void
302ObjectAccessor::RemoveUpdateObject(Object *obj)
303{
304    Guard guard(i_updateGuard);
305    std::set<Object *>::iterator iter = i_objects.find(obj);
306    if( iter != i_objects.end() )
307        i_objects.erase( iter );
308}
309
310void
311ObjectAccessor::_buildUpdateObject(Object *obj, UpdateDataMapType &update_players)
312{
313    bool build_for_all = true;
314    Player *pl = NULL;
315    if( obj->isType(TYPEMASK_ITEM) )
316    {
317        Item *item = static_cast<Item *>(obj);
318        pl = item->GetOwner();
319        build_for_all = false;
320    }
321
322    if( pl != NULL )
323        _buildPacket(pl, obj, update_players);
324
325    // Capt: okey for all those fools who think its a real fix
326    //       THIS IS A TEMP FIX
327    if( build_for_all )
328    {
329        WorldObject * temp = dynamic_cast<WorldObject*>(obj);
330
331        //assert(dynamic_cast<WorldObject*>(obj)!=NULL);
332        if (temp)
333            _buildChangeObjectForPlayer(temp, update_players);
334        else
335            sLog.outDebug("ObjectAccessor: Ln 405 Temp bug fix");
336    }
337}
338
339void
340ObjectAccessor::_buildPacket(Player *pl, Object *obj, UpdateDataMapType &update_players)
341{
342    UpdateDataMapType::iterator iter = update_players.find(pl);
343
344    if( iter == update_players.end() )
345    {
346        std::pair<UpdateDataMapType::iterator, bool> p = update_players.insert( UpdateDataValueType(pl, UpdateData()) );
347        assert(p.second);
348        iter = p.first;
349    }
350
351    obj->BuildValuesUpdateBlockForPlayer(&iter->second, iter->first);
352}
353
354void
355ObjectAccessor::_buildChangeObjectForPlayer(WorldObject *obj, UpdateDataMapType &update_players)
356{
357    CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
358    Cell cell(p);
359    cell.data.Part.reserved = ALL_DISTRICT;
360    cell.SetNoCreate();
361    WorldObjectChangeAccumulator notifier(*obj, update_players);
362    TypeContainerVisitor<WorldObjectChangeAccumulator, WorldTypeMapContainer > player_notifier(notifier);
363    CellLock<GridReadGuard> cell_lock(cell, p);
364    cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(obj->GetMapId(), obj));
365}
366
367Pet*
368ObjectAccessor::GetPet(uint64 guid)
369{
370    return GetObjectInWorld(guid, (Pet*)NULL);
371}
372
373Corpse*
374ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid)
375{
376    Guard guard(i_corpseGuard);
377
378    Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
379    if( iter == i_player2corpse.end() ) return NULL;
380
381    assert(iter->second->GetType() != CORPSE_BONES);
382
383    return iter->second;
384}
385
386void
387ObjectAccessor::RemoveCorpse(Corpse *corpse)
388{
389    assert(corpse && corpse->GetType() != CORPSE_BONES);
390
391    Guard guard(i_corpseGuard);
392    Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
393    if( iter == i_player2corpse.end() )
394        return;
395
396    // build mapid*cellid -> guid_set map
397    CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
398    uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
399
400    objmgr.DeleteCorpseCellData(corpse->GetMapId(),cell_id,corpse->GetOwnerGUID());
401    corpse->RemoveFromWorld();
402
403    i_player2corpse.erase(iter);
404}
405
406void
407ObjectAccessor::AddCorpse(Corpse *corpse)
408{
409    assert(corpse && corpse->GetType() != CORPSE_BONES);
410
411    Guard guard(i_corpseGuard);
412    assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
413    i_player2corpse[corpse->GetOwnerGUID()] = corpse;
414
415    // build mapid*cellid -> guid_set map
416    CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
417    uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
418
419    objmgr.AddCorpseCellData(corpse->GetMapId(),cell_id,corpse->GetOwnerGUID(),corpse->GetInstanceId());
420}
421
422void
423ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair,GridType& grid,Map* map)
424{
425    Guard guard(i_corpseGuard);
426    for(Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
427        if(iter->second->GetGrid()==gridpair)
428    {
429        // verify, if the corpse in our instance (add only corpses which are)
430        if (map->Instanceable())
431        {
432            if (iter->second->GetInstanceId() == map->GetInstanceId())
433            {
434                grid.AddWorldObject(iter->second,iter->second->GetGUID());
435            }
436        }
437        else
438        {
439            grid.AddWorldObject(iter->second,iter->second->GetGUID());
440        }
441    }
442}
443
444Corpse*
445ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid)
446{
447    Corpse *corpse = GetCorpseForPlayerGUID(player_guid);
448    if(!corpse)
449    {
450        //in fact this function is called from several places
451        //even when player doesn't have a corpse, not an error
452        //sLog.outError("ERROR: Try remove corpse that not in map for GUID %ul", player_guid);
453        return NULL;
454    }
455
456    DEBUG_LOG("Deleting Corpse and spawning bones.\n");
457
458    // remove corpse from player_guid -> corpse map
459    RemoveCorpse(corpse);
460
461    // remove resurrectble corpse from grid object registry (loaded state checked into call)
462    // do not load the map if it's not loaded
463    Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId());
464    if(map) map->Remove(corpse,false);
465
466    // remove corpse from DB
467    corpse->DeleteFromDB();
468
469    Corpse *bones = NULL;
470    // create the bones only if the map and the grid is loaded at the corpse's location
471    if(map && !map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
472    {
473        // Create bones, don't change Corpse
474        bones = new Corpse;
475        bones->Create(corpse->GetGUIDLow());
476
477        for (int i = 3; i < CORPSE_END; i++)                    // don't overwrite guid and object type
478            bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
479
480        bones->SetGrid(corpse->GetGrid());
481        // bones->m_time = m_time;                              // don't overwrite time
482        // bones->m_inWorld = m_inWorld;                        // don't overwrite world state
483        // bones->m_type = m_type;                              // don't overwrite type
484        bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
485        bones->SetMapId(corpse->GetMapId());
486        bones->SetInstanceId(corpse->GetInstanceId());
487
488        bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
489        bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0);
490
491        for (int i = 0; i < EQUIPMENT_SLOT_END; i++)
492        {
493            if(corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
494                bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
495        }
496
497        // add bones in grid store if grid loaded where corpse placed
498        map->Add(bones);
499    }
500
501    // all references to the corpse should be removed at this point
502    delete corpse;
503
504    return bones;
505}
506
507void
508ObjectAccessor::AddActiveObject( WorldObject * obj )
509{
510    i_activeobjects.insert(obj);
511}
512
513void
514ObjectAccessor::RemoveActiveObject( WorldObject * obj )
515{
516    i_activeobjects.erase(obj);
517}
518
519void
520ObjectAccessor::Update(uint32 diff)
521{
522    {
523        // player update might remove the player from grid, and that causes crashes. We HAVE to update players first, and then the active objects.
524        HashMapHolder<Player>::MapType& playerMap = HashMapHolder<Player>::GetContainer();
525        for(HashMapHolder<Player>::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter)
526        {
527            if(iter->second->IsInWorld())
528            {
529                iter->second->Update(diff);
530            }
531        }
532
533        // clone the active object list, because update might remove from it
534        std::set<WorldObject *> activeobjects(i_activeobjects);
535
536        std::set<WorldObject *>::const_iterator itr;
537        for(itr = activeobjects.begin(); itr != activeobjects.end(); ++itr)
538        {
539            (*itr)->GetMap()->resetMarkedCells();
540        }
541
542        Map *map;
543
544        Trinity::ObjectUpdater updater(diff);
545        // for creature
546        TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer  > grid_object_update(updater);
547        // for pets
548        TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer > world_object_update(updater);
549
550        for(itr = activeobjects.begin(); itr != activeobjects.end(); ++itr)
551        {
552            WorldObject *obj = (*itr);
553            map = obj->GetMap();
554
555            CellPair standing_cell(Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
556
557            // Check for correctness of standing_cell, it also avoids problems with update_cell
558            if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
559                continue;
560
561            // the overloaded operators handle range checking
562            // so ther's no need for range checking inside the loop
563            CellPair begin_cell(standing_cell), end_cell(standing_cell);
564            begin_cell << 1; begin_cell -= 1;               // upper left
565            end_cell >> 1; end_cell += 1;                   // lower right
566
567            for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++)
568            {
569                for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++)
570                {
571                    uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
572                    if( !map->isCellMarked(cell_id) )
573                    {
574                        CellPair cell_pair(x,y);
575                        map->markCell(cell_id);
576                        Cell cell(cell_pair);
577                        cell.data.Part.reserved = CENTER_DISTRICT;
578                        cell.SetNoCreate();
579                        CellLock<NullGuard> cell_lock(cell, cell_pair);
580                        cell_lock->Visit(cell_lock, grid_object_update,  *map);
581                        cell_lock->Visit(cell_lock, world_object_update, *map);
582                    }
583                }
584            }
585        }
586    }
587
588    _update();
589}
590
591bool
592ObjectAccessor::ActiveObjectsNearGrid(uint32 x, uint32 y, uint32 m_id, uint32 i_id) const
593{
594    CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS);
595    CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
596    cell_min << 2;
597    cell_min -= 2;
598    cell_max >> 2;
599    cell_max += 2;
600
601    for(std::set<WorldObject*>::const_iterator itr = i_activeobjects.begin(); itr != i_activeobjects.end(); ++itr)
602    {
603        if( m_id != (*itr)->GetMapId() || i_id != (*itr)->GetInstanceId() )
604            continue;
605
606        CellPair p = Trinity::ComputeCellPair((*itr)->GetPositionX(), (*itr)->GetPositionY());
607        if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
608            (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
609            return true;
610
611    }
612
613    return false;
614}
615
616void
617ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m)
618{
619    for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
620        if(iter->getSource()->HaveAtClient(&i_object))
621            ObjectAccessor::_buildPacket(iter->getSource(), &i_object, i_updateDatas);
622}
623
624void
625ObjectAccessor::UpdateObjectVisibility(WorldObject *obj)
626{
627    CellPair p = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
628    Cell cell(p);
629
630    MapManager::Instance().GetMap(obj->GetMapId(), obj)->UpdateObjectVisibility(obj,cell,p);
631}
632
633void ObjectAccessor::UpdateVisibilityForPlayer( Player* player )
634{
635    CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
636    Cell cell(p);
637    Map* m = MapManager::Instance().GetMap(player->GetMapId(),player);
638
639    m->UpdatePlayerVisibility(player,cell,p);
640    m->UpdateObjectsVisibilityFor(player,cell,p);
641}
642
643/// Define the static member of HashMapHolder
644
645template <class T> HM_NAMESPACE::hash_map< uint64, T* > HashMapHolder<T>::m_objectMap;
646template <class T> ZThread::FastMutex HashMapHolder<T>::i_lock;
647
648/// Global defintions for the hashmap storage
649
650template class HashMapHolder<Player>;
651template class HashMapHolder<Pet>;
652template class HashMapHolder<GameObject>;
653template class HashMapHolder<DynamicObject>;
654template class HashMapHolder<Creature>;
655template class HashMapHolder<Corpse>;
656
657template Player* ObjectAccessor::GetObjectInWorld<Player>(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/);
658template Pet* ObjectAccessor::GetObjectInWorld<Pet>(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/);
659template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/);
660template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/);
661template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/);
662template DynamicObject* ObjectAccessor::GetObjectInWorld<DynamicObject>(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/);
Note: See TracBrowser for help on using the browser.