芒果魔兽的AOI算法 跟其他AOI算法差不多 也是通过九宫格计算需要同步的范围 然后使用自定义的一个TypeMapContainer 结构 key 值是下列结构
struct ContainerMapList
{
GridRefManager<OBJECT> _element;
};
芒果魔兽 设置的key 值 是针对的每个地图 所以下列代码可以看到 只有地图类继承了这个格子索引管理类
class Map : public GridRefManager<NGridType>
{
friend class MapReference;
friend class ObjectGridLoader;
friend class ObjectWorldLoader;
protected:
Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode);
}
这个Key是一种特殊的数据类型 芒果魔兽重写了一个双向链表 这个key的值 是双向链表的head 类型 具体代码如下
1.双向链表 及链表头
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LINKEDLIST
#define _LINKEDLIST
#include <cstddef>
//============================================
class LinkedListHead;
class LinkedListElement
{
private:
friend class LinkedListHead;
LinkedListElement* iNext;
LinkedListElement* iPrev;
public:
LinkedListElement() { iNext = nullptr; iPrev = nullptr; }
~LinkedListElement() { delink(); }
bool hasNext() const { return (iNext->iNext != nullptr); }
bool hasPrev() const { return (iPrev->iPrev != nullptr); }
bool isInList() const { return (iNext != nullptr && iPrev != nullptr); }
LinkedListElement* next() { return hasNext() ? iNext : nullptr; }
LinkedListElement const* next() const { return hasNext() ? iNext : nullptr; }
LinkedListElement* prev() { return hasPrev() ? iPrev : nullptr; }
LinkedListElement const* prev() const { return hasPrev() ? iPrev : nullptr; }
LinkedListElement* nocheck_next() { return iNext; }
LinkedListElement const* nocheck_next() const { return iNext; }
LinkedListElement* nocheck_prev() { return iPrev; }
LinkedListElement const* nocheck_prev() const { return iPrev; }
void delink()
{
if (isInList())
{
iNext->iPrev = iPrev;
iPrev->iNext = iNext;
iNext = nullptr;
iPrev = nullptr;
}
}
void insertBefore(LinkedListElement* pElem)
{
pElem->iNext = this;
pElem->iPrev = iPrev;
iPrev->iNext = pElem;
iPrev = pElem;
}
void insertAfter(LinkedListElement* pElem)
{
pElem->iPrev = this;
pElem->iNext = iNext;
iNext->iPrev = pElem;
iNext = pElem;
}
};
//============================================
class LinkedListHead
{
private:
LinkedListElement iFirst;
LinkedListElement iLast;
uint32 iSize;
public:
LinkedListHead()
{
// create empty list
iFirst.iNext = &iLast;
iLast.iPrev = &iFirst;
iSize = 0;
}
bool isEmpty() const { return (!iFirst.iNext->isInList()); }
LinkedListElement* getFirst() { return (isEmpty() ? nullptr : iFirst.iNext); }
LinkedListElement const* getFirst() const { return (isEmpty() ? nullptr : iFirst.iNext); }
LinkedListElement* getLast() { return (isEmpty() ? nullptr : iLast.iPrev); }
LinkedListElement const* getLast() const { return (isEmpty() ? nullptr : iLast.iPrev); }
void insertFirst(LinkedListElement* pElem)
{
iFirst.insertAfter(pElem);
}
void insertLast(LinkedListElement* pElem)
{
iLast.insertBefore(pElem);
}
uint32 getSize() const
{
if (!iSize)
{
uint32 result = 0;
LinkedListElement const* e = getFirst();
while (e)
{
++result;
e = e->next();
}
return result;
}
return iSize;
}
void incSize() { ++iSize; }
void decSize() { --iSize; }
template<class _Ty>
class Iterator
{
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef _Ty value_type;
typedef ptrdiff_t difference_type;
typedef ptrdiff_t distance_type;
typedef _Ty* pointer;
typedef _Ty const* const_pointer;
typedef _Ty& reference;
typedef _Ty const& const_reference;
Iterator()
: _Ptr(nullptr)
{
// construct with null node pointer
}
Iterator(pointer _Pnode)
: _Ptr(_Pnode)
{
// construct with node pointer _Pnode
}
Iterator& operator=(Iterator const& _Right)
{
return (*this) = _Right._Ptr;
}
Iterator& operator=(const_pointer const& _Right)
{
_Ptr = (pointer)_Right;
return (*this);
}
reference operator*()
{
// return designated value
return *_Ptr;
}
pointer operator->()
{
// return pointer to class object
return _Ptr;
}
Iterator& operator++()
{
// preincrement
_Ptr = _Ptr->next();
return (*this);
}
Iterator operator++(int)
{
// postincrement
iterator _Tmp = *this;
++*this;
return (_Tmp);
}
Iterator& operator--()
{
// predecrement
_Ptr = _Ptr->prev();
return (*this);
}
Iterator operator--(int)
{
// postdecrement
iterator _Tmp = *this;
--*this;
return (_Tmp);
}
bool operator==(Iterator const& _Right) const
{
// test for iterator equality
return (_Ptr == _Right._Ptr);
}
bool operator!=(Iterator const& _Right) const
{
// test for iterator inequality
return (!(*this == _Right));
}
bool operator==(pointer const& _Right) const
{
// test for pointer equality
return (_Ptr != _Right);
}
bool operator!=(pointer const& _Right) const
{
// test for pointer equality
return (!(*this == _Right));
}
bool operator==(const_reference _Right) const
{
// test for reference equality
return (_Ptr == &_Right);
}
bool operator!=(const_reference _Right) const
{
// test for reference equality
return (_Ptr != &_Right);
}
pointer _Mynode()
{
// return node pointer
return (_Ptr);
}
protected:
pointer _Ptr; // pointer to node
};
typedef Iterator<LinkedListElement> iterator;
};
//============================================
#endif
2.RefManager管理链表头
#include "Utilities/LinkedList.h"
#include "Utilities/LinkedReference/Reference.h"
template <class TO, class FROM>
class RefManager : public LinkedListHead
{
public:
typedef LinkedListHead::Iterator<Reference<TO, FROM> > iterator;
typedef LinkedListHead::Iterator<Reference<TO, FROM> const > const_iterator;
RefManager() {}
virtual ~RefManager() { clearReferences(); }
Reference<TO, FROM>* getFirst() { return ((Reference<TO, FROM>*) LinkedListHead::getFirst()); }
Reference<TO, FROM> const* getFirst() const { return ((Reference<TO, FROM> const*) LinkedListHead::getFirst()); }
Reference<TO, FROM>* getLast() { return ((Reference<TO, FROM>*) LinkedListHead::getLast()); }
Reference<TO, FROM> const* getLast() const { return ((Reference<TO, FROM> const*) LinkedListHead::getLast()); }
iterator begin() { return iterator(getFirst()); }
iterator end() { return iterator(nullptr); }
iterator rbegin() { return iterator(getLast()); }
iterator rend() { return iterator(nullptr); }
const_iterator begin() const { return const_iterator(getFirst()); }
const_iterator end() const { return const_iterator(nullptr); }
void clearReferences()
{
LinkedListElement* ref;
while ((ref = getFirst()) != nullptr)
{
((Reference<TO, FROM>*) ref)->invalidate();
ref->delink(); // the delink might be already done by invalidate(), but doing it here again does not hurt and insures an empty list
}
}
};
3.双向链表子节点GridReference 类
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _GRIDREFERENCE_H
#define _GRIDREFERENCE_H
#include "Utilities/LinkedReference/Reference.h"
template<class OBJECT> class GridRefManager;
template<class OBJECT>
class GridReference : public Reference<GridRefManager<OBJECT>, OBJECT>
{
protected:
void targetObjectBuildLink() override
{
// called from link()
this->getTarget()->insertFirst(this);
this->getTarget()->incSize();
}
void targetObjectDestroyLink() override
{
// called from unlink()
if (this->isValid())
this->getTarget()->decSize();
}
void sourceObjectDestroyLink() override
{
// called from invalidate()
this->getTarget()->decSize();
}
public:
GridReference()
: Reference<GridRefManager<OBJECT>, OBJECT>()
{
}
~GridReference()
{
this->unlink();
}
GridReference* next()
{
return (GridReference*)Reference<GridRefManager<OBJECT>, OBJECT>::next();
}
};
#endif
4.容器类型类 自定义了几种数据结构 TypeUnorderedMapContainer 以及 TypeMapContaine
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_TYPECONTAINER_H
#define MANGOS_TYPECONTAINER_H
/*
* Here, you'll find a series of containers that allow you to hold multiple
* types of object at the same time.
*/
#include <cassert>
#include <map>
#include <vector>
#include "Common.h"
#include "Utilities/TypeList.h"
#include "GameSystem/GridRefManager.h"
template<class OBJECT, class KEY_TYPE>
struct ContainerUnorderedMap
{
std::unordered_map<KEY_TYPE, OBJECT*> _element;
};
template<class KEY_TYPE>
struct ContainerUnorderedMap<TypeNull, KEY_TYPE>
{
};
template<class H, class T, class KEY_TYPE>
struct ContainerUnorderedMap< TypeList<H, T>, KEY_TYPE >
{
ContainerUnorderedMap<H, KEY_TYPE> _elements;
ContainerUnorderedMap<T, KEY_TYPE> _TailElements;
};
template<class OBJECT_TYPES, class KEY_TYPE = OBJECT_HANDLE>
class TypeUnorderedMapContainer
{
public:
template<class SPECIFIC_TYPE>
bool insert(KEY_TYPE handle, SPECIFIC_TYPE* obj)
{
return TypeUnorderedMapContainer::insert(i_elements, handle, obj);
}
template<class SPECIFIC_TYPE>
bool erase(KEY_TYPE handle, SPECIFIC_TYPE* /*obj*/)
{
return TypeUnorderedMapContainer::erase(i_elements, handle, (SPECIFIC_TYPE*)nullptr);
}
template<class SPECIFIC_TYPE>
SPECIFIC_TYPE* find(KEY_TYPE hdl, SPECIFIC_TYPE* /*obj*/)
{
return TypeUnorderedMapContainer::find(i_elements, hdl, (SPECIFIC_TYPE*)nullptr);
}
template<class SPECIFIC_TYPE>
typename std::unordered_map<KEY_TYPE, SPECIFIC_TYPE*>::iterator begin()
{
return i_elements._elements._element.begin();
}
template<class SPECIFIC_TYPE>
typename std::unordered_map<KEY_TYPE, SPECIFIC_TYPE*>::iterator end()
{
return i_elements._elements._element.end();
}
private:
ContainerUnorderedMap<OBJECT_TYPES, KEY_TYPE> i_elements;
// Helpers
// Insert helpers
template<class SPECIFIC_TYPE>
static bool insert(ContainerUnorderedMap<SPECIFIC_TYPE, KEY_TYPE>& elements, KEY_TYPE handle, SPECIFIC_TYPE* obj)
{
typename std::unordered_map<KEY_TYPE, SPECIFIC_TYPE*>::iterator i = elements._element.find(handle);
if (i == elements._element.end())
{
elements._element[handle] = obj;
return true;
}
assert(i->second == obj && "Object with certain key already in but objects are different!");
return false;
}
template<class SPECIFIC_TYPE>
static bool insert(ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*elements*/, KEY_TYPE /*handle*/, SPECIFIC_TYPE* /*obj*/)
{
return false;
}
template<class SPECIFIC_TYPE, class T>
static bool insert(ContainerUnorderedMap<T, KEY_TYPE>& /*elements*/, KEY_TYPE /*handle*/, SPECIFIC_TYPE* /*obj*/)
{
return false;
}
template<class SPECIFIC_TYPE, class H, class T>
static bool insert(ContainerUnorderedMap< TypeList<H, T>, KEY_TYPE >& elements, KEY_TYPE handle, SPECIFIC_TYPE* obj)
{
bool ret = TypeUnorderedMapContainer::insert(elements._elements, handle, obj);
return ret ? ret : TypeUnorderedMapContainer::insert(elements._TailElements, handle, obj);
}
// Find helpers
template<class SPECIFIC_TYPE>
static SPECIFIC_TYPE* find(ContainerUnorderedMap<SPECIFIC_TYPE, KEY_TYPE>& elements, KEY_TYPE hdl, SPECIFIC_TYPE* /*obj*/)
{
typename std::unordered_map<KEY_TYPE, SPECIFIC_TYPE*>::iterator i = elements._element.find(hdl);
if (i == elements._element.end())
return nullptr;
return i->second;
}
template<class SPECIFIC_TYPE>
static SPECIFIC_TYPE* find(ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*elements*/, KEY_TYPE /*hdl*/, SPECIFIC_TYPE* /*obj*/)
{
return nullptr;
}
template<class SPECIFIC_TYPE, class T>
static SPECIFIC_TYPE* find(ContainerUnorderedMap<T, KEY_TYPE>& /*elements*/, KEY_TYPE /*hdl*/, SPECIFIC_TYPE* /*obj*/)
{
return nullptr;
}
template<class SPECIFIC_TYPE, class H, class T>
static SPECIFIC_TYPE* find(ContainerUnorderedMap< TypeList<H, T>, KEY_TYPE >& elements, KEY_TYPE hdl, SPECIFIC_TYPE* /*obj*/)
{
SPECIFIC_TYPE* ret = TypeUnorderedMapContainer::find(elements._elements, hdl, (SPECIFIC_TYPE*)nullptr);
return ret ? ret : TypeUnorderedMapContainer::find(elements._TailElements, hdl, (SPECIFIC_TYPE*)nullptr);
}
// Erase helpers
template<class SPECIFIC_TYPE>
static bool erase(ContainerUnorderedMap<SPECIFIC_TYPE, KEY_TYPE>& elements, KEY_TYPE handle, SPECIFIC_TYPE* /*obj*/)
{
elements._element.erase(handle);
return true;
}
template<class SPECIFIC_TYPE>
static bool erase(ContainerUnorderedMap<TypeNull, KEY_TYPE>& /*elements*/, KEY_TYPE /*handle*/, SPECIFIC_TYPE* /*obj*/)
{
return false;
}
template<class SPECIFIC_TYPE, class T>
static bool erase(ContainerUnorderedMap<T, KEY_TYPE>& /*elements*/, KEY_TYPE /*handle*/, SPECIFIC_TYPE* /*obj*/)
{
return false;
}
template<class SPECIFIC_TYPE, class H, class T>
static bool erase(ContainerUnorderedMap< TypeList<H, T>, KEY_TYPE >& elements, KEY_TYPE handle, SPECIFIC_TYPE* /*obj*/)
{
bool ret = TypeUnorderedMapContainer::erase(elements._elements, handle, (SPECIFIC_TYPE*)nullptr);
return ret ? ret : TypeUnorderedMapContainer::erase(elements._TailElements, handle, (SPECIFIC_TYPE*)nullptr);
}
};
/*
* @class ContainerMapList is a multi-type container for map elements
* By itself it's meaningless but collaborating with TypeContainers,
* it becomes the most powerful container in the whole system.
*/
template<class OBJECT>
struct ContainerMapList
{
GridRefManager<OBJECT> _element;
};
template<>
struct ContainerMapList<TypeNull> /* nothing is in type null */
{
};
template<class H, class T>
struct ContainerMapList<TypeList<H, T> >
{
ContainerMapList<H> _elements;
ContainerMapList<T> _TailElements;
};
#include "TypeContainerFunctions.h"
/*
* @class TypeMapContainer contains a fixed number of types and is
* determined at compile time. This is probably the most complicated
* class and do its simplest thing, that is, holds objects
* of different types.
*/
template<class OBJECT_TYPES>
class TypeMapContainer
{
public:
template<class SPECIFIC_TYPE>
size_t Count() const { return MaNGOS::Count(i_elements, (SPECIFIC_TYPE*)nullptr); }
/// inserts a specific object into the container
template<class SPECIFIC_TYPE>
bool insert(SPECIFIC_TYPE* obj)
{
SPECIFIC_TYPE* t = MaNGOS::Insert(i_elements, obj);
return (t != nullptr);
}
/// Removes the object from the container, and returns the removed object
template<class SPECIFIC_TYPE>
bool remove(SPECIFIC_TYPE* obj)
{
SPECIFIC_TYPE* t = MaNGOS::Remove(i_elements, obj);
return (t != nullptr);
}
ContainerMapList<OBJECT_TYPES>& GetElements() { return i_elements; }
const ContainerMapList<OBJECT_TYPES>& GetElements() const { return i_elements;}
private:
ContainerMapList<OBJECT_TYPES> i_elements;
};
#endif
6.上面容器类使用了一些命名空间的函数 方便实现功能 下面是函数的代码
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TYPECONTAINER_FUNCTIONS_H
#define TYPECONTAINER_FUNCTIONS_H
/*
* Here you'll find a list of helper functions to make
* the TypeContainer usefull. Without it, its hard
* to access or mutate the container.
*/
#include "Platform/Define.h"
#include "Utilities/TypeList.h"
#include <map>
namespace MaNGOS
{
/* ContainerMapList Helpers */
// count functions
template<class SPECIFIC_TYPE>
size_t Count(const ContainerMapList<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE* /*fake*/)
{
return elements._element.getSize();
}
template<class SPECIFIC_TYPE>
size_t Count(const ContainerMapList<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*fake*/)
{
return 0;
}
template<class SPECIFIC_TYPE, class T>
size_t Count(const ContainerMapList<T>& /*elements*/, SPECIFIC_TYPE* /*fake*/)
{
return 0;
}
template<class SPECIFIC_TYPE, class T>
size_t Count(const ContainerMapList<TypeList<SPECIFIC_TYPE, T> >& elements, SPECIFIC_TYPE* fake)
{
return Count(elements._elements, fake);
}
template<class SPECIFIC_TYPE, class H, class T>
size_t Count(const ContainerMapList<TypeList<H, T> >& elements, SPECIFIC_TYPE* fake)
{
return Count(elements._TailElements, fake);
}
// non-const insert functions
template<class SPECIFIC_TYPE>
SPECIFIC_TYPE* Insert(ContainerMapList<SPECIFIC_TYPE>& elements, SPECIFIC_TYPE* obj)
{
// elements._element[hdl] = obj;
obj->GetGridRef().link(&elements._element, obj);
return obj;
}
template<class SPECIFIC_TYPE>
SPECIFIC_TYPE* Insert(ContainerMapList<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
{
return nullptr;
}
// this is a missed
template<class SPECIFIC_TYPE, class T>
SPECIFIC_TYPE* Insert(ContainerMapList<T>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
{
return nullptr; // a missed
}
// Recursion
template<class SPECIFIC_TYPE, class H, class T>
SPECIFIC_TYPE* Insert(ContainerMapList<TypeList<H, T> >& elements, SPECIFIC_TYPE* obj)
{
SPECIFIC_TYPE* t = Insert(elements._elements, obj);
return (t != nullptr ? t : Insert(elements._TailElements, obj));
}
// non-const remove method
template<class SPECIFIC_TYPE>
SPECIFIC_TYPE* Remove(ContainerMapList<SPECIFIC_TYPE>& /*elements*/, SPECIFIC_TYPE* obj)
{
obj->GetGridRef().unlink();
return obj;
}
template<class SPECIFIC_TYPE>
SPECIFIC_TYPE* Remove(ContainerMapList<TypeNull>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
{
return nullptr;
}
// this is a missed
template<class SPECIFIC_TYPE, class T>
SPECIFIC_TYPE* Remove(ContainerMapList<T>& /*elements*/, SPECIFIC_TYPE* /*obj*/)
{
return nullptr; // a missed
}
template<class SPECIFIC_TYPE, class T, class H>
SPECIFIC_TYPE* Remove(ContainerMapList<TypeList<H, T> >& elements, SPECIFIC_TYPE* obj)
{
// The head element is bad
SPECIFIC_TYPE* t = Remove(elements._elements, obj);
return (t != nullptr ? t : Remove(elements._TailElements, obj));
}
}
#endif
上面代码 我们看到了一些功能 函数 但是特别需要注意的是 下面这个代码
obj->GetGridRef().link(&elements._element, obj);
//以及
obj->GetGridRef().unlink();
这两个用到的link函数是最终添加对象到双向链表的子节点 所以需要你的需要添加到双向链表的类 都要实现GetGridRef()方法 代码如下
//摄像机类需要实现以下方法
GridReference<Camera>& GetGridRef() { return m_gridRef; }
bool isActiveObject() const { return false; }
GridReference<Camera> m_gridRef;
// 在线玩家类需要实现以下方法
GridReference<Player>& GetGridRef() { return m_gridRef; }
GridReference<Player> m_gridRef;
//尸体类需要实现以下方法
GridReference<Corpse>& GetGridRef() { return m_gridRef; }
GridReference<Corpse> m_gridRef;
//生物类需要实现以下方法
GridReference<Creature>& GetGridRef() { return m_gridRef; }
GridReference<Creature> m_gridRef;
上面就已经完成了 AOI算法的容器类 下面需要实现一个 访问容器类 后续同步数据的时候会使用到
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_TYPECONTAINERVISITOR_H
#define MANGOS_TYPECONTAINERVISITOR_H
/*
* @class TypeContainerVisitor is implemented as a visitor pattern. It is
* a visitor to the TypeMapContainer or ContainerMapList. The visitor has
* to overload its types as a visit method is called.
*/
#include "Platform/Define.h"
#include "TypeContainer.h"
// forward declaration
template<class T, class Y> class TypeContainerVisitor;
// visitor helper
template<class VISITOR, class TYPE_CONTAINER>
void VisitorHelper(VISITOR& v, TYPE_CONTAINER& c)
{
v.Visit(c);
}
// terminate condition container map list
template<class VISITOR>
void VisitorHelper(VISITOR& /*v*/, ContainerMapList<TypeNull>& /*c*/)
{
}
template<class VISITOR, class T>
void VisitorHelper(VISITOR& v, ContainerMapList<T>& c)
{
v.Visit(c._element);
}
// recursion container map list
template<class VISITOR, class H, class T>
void VisitorHelper(VISITOR& v, ContainerMapList<TypeList<H, T> >& c)
{
VisitorHelper(v, c._elements);
VisitorHelper(v, c._TailElements);
}
// for TypeMapContainer
template<class VISITOR, class OBJECT_TYPES>
void VisitorHelper(VISITOR& v, TypeMapContainer<OBJECT_TYPES>& c)
{
VisitorHelper(v, c.GetElements());
}
template<class VISITOR, class TYPE_CONTAINER>
class TypeContainerVisitor
{
public:
TypeContainerVisitor(VISITOR& v)
: i_visitor(v)
{
}
void Visit(TYPE_CONTAINER& c)
{
VisitorHelper(i_visitor, c);
}
void Visit(const TYPE_CONTAINER& c) const
{
VisitorHelper(i_visitor, c);
}
private:
VISITOR& i_visitor;
};
#endif
上面所有容器的函数准备工作已经完成 这时候可以创建每个格子的容器了
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_GRID_H
#define MANGOS_GRID_H
/*
@class Grid
Grid is a logical segment of the game world represented inside MaNGOS.
Grid is bind at compile time to a particular type of object which
we call it the object of interested. There are many types of loader,
specially, dynamic loader, static loader, or on-demand loader. There's
a subtle difference between dynamic loader and on-demand loader but
this is implementation specific to the loader class. From the
Grid's perspective, the loader meets its API requirement is suffice.
*/
#include "Platform/Define.h"
#include "Policies/ThreadingModel.h"
#include "TypeContainer.h"
#include "TypeContainerVisitor.h"
// forward declaration
template<class A, class T, class O> class GridLoader;
template
<
class ACTIVE_OBJECT,
class WORLD_OBJECT_TYPES,
class GRID_OBJECT_TYPES
>
class Grid
{
// allows the GridLoader to access its internals
template<class A, class T, class O> friend class GridLoader;
public:
/** destructor to clean up its resources. This includes unloading the
grid if it has not been unload.
*/
~Grid() {}
/** an object of interested enters the grid
*/
template<class SPECIFIC_OBJECT>
bool AddWorldObject(SPECIFIC_OBJECT* obj)
{
return i_objects.template insert<SPECIFIC_OBJECT>(obj);
}
/** an object of interested exits the grid
*/
template<class SPECIFIC_OBJECT>
bool RemoveWorldObject(SPECIFIC_OBJECT* obj)
{
return i_objects.template remove<SPECIFIC_OBJECT>(obj);
}
/** Grid visitor for grid objects
*/
template<class T>
void Visit(TypeContainerVisitor<T, TypeMapContainer<GRID_OBJECT_TYPES> >& visitor)
{
visitor.Visit(i_container);
}
/** Grid visitor for world objects
*/
template<class T>
void Visit(TypeContainerVisitor<T, TypeMapContainer<WORLD_OBJECT_TYPES> >& visitor)
{
visitor.Visit(i_objects);
}
/** Returns the number of object within the grid.
*/
uint32 ActiveObjectsInGrid() const
{
return m_activeGridObjects.size() + i_objects.template Count<ACTIVE_OBJECT>();
}
/** Inserts a container type object into the grid.
*/
template<class SPECIFIC_OBJECT>
bool AddGridObject(SPECIFIC_OBJECT* obj)
{
if (obj->isActiveObject())
m_activeGridObjects.insert(obj);
return i_container.template insert<SPECIFIC_OBJECT>(obj);
}
/** Removes a containter type object from the grid
*/
template<class SPECIFIC_OBJECT>
bool RemoveGridObject(SPECIFIC_OBJECT* obj)
{
if (obj->isActiveObject())
m_activeGridObjects.erase(obj);
return i_container.template remove<SPECIFIC_OBJECT>(obj);
}
private:
TypeMapContainer<GRID_OBJECT_TYPES> i_container;
TypeMapContainer<WORLD_OBJECT_TYPES> i_objects;
typedef std::set<void*> ActiveGridObjects;
ActiveGridObjects m_activeGridObjects;
};
#endif
上面类就是每个格子会保存的对象 类 其中有加添 移除函数 下面需要创建一个每个的格子的管理类
下面是代码 其中还有格子信息类 魔兽世界地图数据是 1个格子的同步cell 为16 *16 所以下面 代码中的uint32 N, 后续会传递16 数据过来过来
/*
* This file is part of the CMaNGOS Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_NGRID_H
#define MANGOS_NGRID_H
/** NGrid is nothing more than a wrapper of the Grid with an NxN cells
*/
#include "GameSystem/Grid.h"
#include "GameSystem/GridReference.h"
#include "Util/Timer.h"
#include <cassert>
class GridInfo
{
public:
GridInfo()
: i_timer(0), i_unloadActiveLockCount(0), i_unloadExplicitLock(false)
{
}
GridInfo(time_t expiry, bool unload = true)
: i_timer(expiry), i_unloadActiveLockCount(0), i_unloadExplicitLock(!unload)
{
}
const TimeTracker& getTimeTracker() const { return i_timer; }
bool getUnloadLock() const
{
return i_unloadActiveLockCount || i_unloadExplicitLock;
}
void setUnloadExplicitLock(bool on) { i_unloadExplicitLock = on; }
void incUnloadActiveLock() { ++i_unloadActiveLockCount; }
void decUnloadActiveLock() { if (i_unloadActiveLockCount) --i_unloadActiveLockCount; }
void setTimer(const TimeTracker& pTimer) { i_timer = pTimer; }
void ResetTimeTracker(time_t interval) { i_timer.Reset(interval); }
void UpdateTimeTracker(time_t diff) { i_timer.Update(diff); }
private:
TimeTracker i_timer;
uint16 i_unloadActiveLockCount : 16; // lock from active object spawn points (prevent clone loading)
bool i_unloadExplicitLock : 1; // explicit manual lock or config setting
};
typedef enum
{
GRID_STATE_INVALID = 0,
GRID_STATE_ACTIVE = 1,
GRID_STATE_IDLE = 2,
GRID_STATE_REMOVAL = 3,
MAX_GRID_STATE = 4
} grid_state_t;
template
<
uint32 N,
class ACTIVE_OBJECT,
class WORLD_OBJECT_TYPES,
class GRID_OBJECT_TYPES
>
class NGrid
{
public:
typedef Grid<ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> GridType;
NGrid(uint32 id, uint32 x, uint32 y, time_t expiry, bool unload = true)
: i_gridId(id), i_x(x), i_y(y), i_cellstate(GRID_STATE_INVALID), i_GridObjectDataLoaded(false)
{
i_GridInfo = GridInfo(expiry, unload);
}
const GridType& operator()(uint32 x, uint32 y) const
{
assert(x < N);
assert(y < N);
return i_cells[x][y];
}
GridType& operator()(uint32 x, uint32 y)
{
assert(x < N);
assert(y < N);
return i_cells[x][y];
}
const uint32& GetGridId() const { return i_gridId; }
grid_state_t GetGridState() const { return i_cellstate; }
void SetGridState(grid_state_t s) { i_cellstate = s; }
uint32 getX() const { return i_x; }
uint32 getY() const { return i_y; }
void link(GridRefManager<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> >* pTo)
{
i_Reference.link(pTo, this);
}
bool isGridObjectDataLoaded() const { return i_GridObjectDataLoaded; }
void setGridObjectDataLoaded(bool pLoaded) { i_GridObjectDataLoaded = pLoaded; }
GridInfo* getGridInfoRef() { return &i_GridInfo; }
const TimeTracker& getTimeTracker() const { return i_GridInfo.getTimeTracker(); }
bool getUnloadLock() const { return i_GridInfo.getUnloadLock(); }
void setUnloadExplicitLock(bool on) { i_GridInfo.setUnloadExplicitLock(on); }
void incUnloadActiveLock() { i_GridInfo.incUnloadActiveLock(); }
void decUnloadActiveLock() { i_GridInfo.decUnloadActiveLock(); }
void ResetTimeTracker(time_t interval) { i_GridInfo.ResetTimeTracker(interval); }
void UpdateTimeTracker(time_t diff) { i_GridInfo.UpdateTimeTracker(diff); }
template<class SPECIFIC_OBJECT>
void AddWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
{
getGridType(x, y).AddWorldObject(obj);
}
template<class SPECIFIC_OBJECT>
void RemoveWorldObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
{
getGridType(x, y).RemoveWorldObject(obj);
}
template<class T, class TT>
void Visit(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
{
for (uint32 x = 0; x < N; ++x)
for (uint32 y = 0; y < N; ++y)
i_cells[x][y].Visit(visitor);
}
template<class T, class TT>
void Visit(const uint32& x, const uint32& y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
{
getGridType(x, y).Visit(visitor);
}
uint32 ActiveObjectsInGrid() const
{
uint32 count = 0;
for (uint32 x = 0; x < N; ++x)
for (uint32 y = 0; y < N; ++y)
count += i_cells[x][y].ActiveObjectsInGrid();
return count;
}
template<class SPECIFIC_OBJECT>
bool AddGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
{
return getGridType(x, y).AddGridObject(obj);
}
template<class SPECIFIC_OBJECT>
bool RemoveGridObject(const uint32 x, const uint32 y, SPECIFIC_OBJECT* obj)
{
return getGridType(x, y).RemoveGridObject(obj);
}
private:
GridType& getGridType(const uint32& x, const uint32& y)
{
assert(x < N);
assert(y < N);
return i_cells[x][y];
}
uint32 i_gridId;
GridInfo i_GridInfo;
GridReference<NGrid<N, ACTIVE_OBJECT, WORLD_OBJECT_TYPES, GRID_OBJECT_TYPES> > i_Reference;
uint32 i_x;
uint32 i_y;
grid_state_t i_cellstate;
GridType i_cells[N][N];
bool i_GridObjectDataLoaded;
};
#endif
到此 容器算法基础框架搭建完毕 下面开始使用 使用的时候需要参考一个模板编程 这个宏定义代码实现的是可以把不同的类型数据 串联起来 实现元编程
class TypeNull;
template<typename HEAD, typename TAIL>
struct TypeList
{
typedef HEAD Head;
typedef TAIL Tail;
};
// enough for now.. can be expand at any point in time as needed
#define TYPELIST_1(T1) TypeList<T1, TypeNull>
#define TYPELIST_2(T1, T2) TypeList<T1, TYPELIST_1(T2) >
#define TYPELIST_3(T1, T2, T3) TypeList<T1, TYPELIST_2(T2, T3) >
#define TYPELIST_4(T1, T2, T3, T4) TypeList<T1, TYPELIST_3(T2, T3, T4) >
#define TYPELIST_5(T1, T2, T3, T4, T5) TypeList<T1, TYPELIST_4(T2, T3, T4, T5) >
#endif
typedef 串连上面的类
typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, Camera) AllWorldObjectTypes;
typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes;
typedef TYPELIST_4(Creature, Pet, GameObject, DynamicObject) AllMapStoredObjectTypes;
typedef GridRefManager<Camera> CameraMapType;
typedef GridRefManager<Corpse> CorpseMapType;
typedef GridRefManager<Creature> CreatureMapType;
typedef GridRefManager<DynamicObject> DynamicObjectMapType;
typedef GridRefManager<GameObject> GameObjectMapType;
typedef GridRefManager<Player> PlayerMapType;
typedef Grid<Player, AllWorldObjectTypes, AllGridObjectTypes> GridType;
typedef NGrid<MAX_NUMBER_OF_CELLS, Player, AllWorldObjectTypes, AllGridObjectTypes> NGridType;
typedef TypeMapContainer<AllGridObjectTypes> GridTypeMapContainer;
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;
MAX_NUMBER_OF_CELLS 是16 这样所有的类就串连起来 开始使用 地图类中创建格子容器管理类 魔兽世界的一个地图是无缝地图 一个无缝地图数据是64*64
//在MAP类里面 定义格子对象
private:
time_t i_gridExpiry;
time_t m_curTime;
tm m_curTimeTm;
NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
在地图初始化的时候 会初始化指针
void Map::Initialize(bool loadInstanceData /*= true*/)
{
m_CreatureGuids.Set(sObjectMgr.GetFirstTemporaryCreatureLowGuid());
m_GameObjectGuids.Set(sObjectMgr.GetFirstTemporaryGameObjectLowGuid());
for (unsigned int j = 0; j < MAX_NUMBER_OF_GRIDS; ++j)
{
for (unsigned int idx = 0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
{
// z code
m_bLoadedGrids[idx][j] = false;
setNGrid(nullptr, idx, j);
}
}
}
并且在玩家 或者一些特殊对象进入到地图的某个Cell的时候 生成对应的对象格子容器对象 下面代码需要的注意的是 buildNGridLinkage(getNGrid(p.x_coord, p.y_coord)); 函数 这个是把地图跟NGRIDTYPE做第一次链接 地图是所以双向链表的头 所以继承 GridRefManager<NGridType> 这个函数就把地图跟每个NGridtype关联起来了
class Map : public GridRefManager<NGridType>
void Map::EnsureGridCreated(const GridPair& p)
{
if (!getNGrid(p.x_coord, p.y_coord))
{
setNGrid(new NGridType(p.x_coord * MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_BOOL_GRID_UNLOAD)),
p.x_coord, p.y_coord);
// build a linkage between this map and NGridType
buildNGridLinkage(getNGrid(p.x_coord, p.y_coord));
getNGrid(p.x_coord, p.y_coord)->SetGridState(GRID_STATE_IDLE);
// z coord
int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord;
int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord;
if (!m_bLoadedGrids[gx][gy])
LoadMapAndVMap(gx, gy);
}
}
bool Map::EnsureGridLoaded(const Cell& cell)
{
EnsureGridCreated(GridPair(cell.GridX(), cell.GridY()));
NGridType* grid = getNGrid(cell.GridX(), cell.GridY());
MANGOS_ASSERT(grid != nullptr);
if (!isGridObjectDataLoaded(cell.GridX(), cell.GridY()))
{
// it's important to set it loaded before loading!
// otherwise there is a possibility of infinity chain (grid loading will be called many times for the same grid)
// possible scenario:
// active object A(loaded with loader.LoadN call and added to the map)
// summons some active object B, while B added to map grid loading called again and so on..
setGridObjectDataLoaded(true, cell.GridX(), cell.GridY());
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
// Add resurrectable corpses to world object list in grid
sObjectAccessor.AddCorpsesToGrid(GridPair(cell.GridX(), cell.GridY()), (*grid)(cell.CellX(), cell.CellY()), this);
return true;
}
return false;
}
玩家 或者任何生物进入到该地图后 就会通过AddToGrid()函数 把对象添加进对应格子容器cell里
template<class T>
void Map::AddToGrid(T* obj, NGridType* grid, Cell const& cell)
{
(*grid)(cell.CellX(), cell.CellY()).AddGridObject<T>(obj);
}
上面完成了添加 下面开始AOI同步算法 当需要同步数据时候 具体同步函数都在GridNotifiers.h里面 我们拿其中的一个举例 需要同步不同逻辑的时候需要先 写一个结构体
struct ObjectMessageDistDeliverer
{
WorldObject const& i_object;
WorldPacket const& i_message;
float i_dist;
ObjectMessageDistDeliverer(WorldObject const& obj, WorldPacket const& msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {}
void Visit(CameraMapType& m);
template<class SKIP> void Visit(GridRefManager<SKIP>&) {}
};
void ObjectMessageDistDeliverer::Visit(CameraMapType& m)
{
for (auto& iter : m)
{
if (!i_dist || iter.getSource()->GetBody()->IsWithinDist(&i_object, i_dist))
{
if (WorldSession* session = iter.getSource()->GetOwner()->GetSession())
session->SendPacket(i_message);
}
}
}
上面代码需要注意的两点 第一是你需要同步的对象类型 例如这个例子 需要同步的是拥有CameraMapType的类 所以单独实现了 void Visit(CameraMapType& m);方法 而其他需要同步的对象 就直接跳过了 template<class SKIP> void Visit(GridRefManager<SKIP>&) {}
下面开始
void Map::MessageDistBroadcast(WorldObject const* obj, WorldPacket const& msg, float dist)
{
CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
{
sLog.outError("Map::MessageBroadcast: Object (GUID: %u TypeId: %u) have invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), p.x_coord, p.y_coord);
return;
}
Cell cell(p);
cell.SetNoCreate();
if (!loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)))
return;
MaNGOS::ObjectMessageDistDeliverer post_man(*obj, msg, dist);
TypeContainerVisitor<MaNGOS::ObjectMessageDistDeliverer, WorldTypeMapContainer > message(post_man);
cell.Visit(p, message, *this, *obj, dist);
}
上面代码其实是范围广播消息 先根据坐标计算出玩家具体的cell 生成了一个ObjectMessageDistDeliverer 对象 这个对象其实是类似回调函数 然后还生成了一个访问容器TypeContainerVisitor 具体代码参考上面 cell.Visit(p, message, *this, *obj, dist);开始执行计算 dist参数是同步的范围 obj是一个世界物品
template<class T, class CONTAINER>
inline void
Cell::Visit(const CellPair& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& m, const WorldObject& obj, float radius) const
{
Cell::Visit(standing_cell, visitor, m, obj.GetPositionX(), obj.GetPositionY(), radius + obj.GetObjectBoundingRadius());
}
template<class T, class CONTAINER>
inline void
Cell::Visit(const CellPair& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& m, float x, float y, float radius) const
{
if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
return;
//如果范围小于等于0 就只需要同步给当前cell里面的对象
if (radius <= 0.0f)
{
m.Visit(*this, visitor);
return;
}
// 修正范围
if (radius > MAX_VISIBILITY_DISTANCE)
radius = MAX_VISIBILITY_DISTANCE;
// 计算同步区域
CellArea area = Cell::CalculateCellArea(x, y, radius);
// 检测是不是区域是不是同一区域
if (!area)
{
m.Visit(*this, visitor);
return;
}
CellPair& begin_cell = area.low_bound;
CellPair& end_cell = area.high_bound;
//上面据算出需要更新的区域边界
//如果超过4 就需要同步圆形范围
if (((end_cell.x_coord - begin_cell.x_coord) > 4) && ((end_cell.y_coord - begin_cell.y_coord) > 4))
{
VisitCircle(visitor, m, begin_cell, end_cell);
return;
}
//这里是先给当前cell的数据不同
m.Visit(*this, visitor);
// 同步周边
for (uint32 i = begin_cell.x_coord; i <= end_cell.x_coord; ++i)
{
for (uint32 j = begin_cell.y_coord; j <= end_cell.y_coord; ++j)
{
CellPair cell_pair(i, j);
// lets skip standing cell since we already visited it
if (cell_pair != standing_cell)
{
Cell r_zone(cell_pair);
r_zone.data.Part.nocreate = data.Part.nocreate;
m.Visit(r_zone, visitor);
}
}
}
}
具体看注释
template<class T, class CONTAINER>
inline void
Map::Visit(const Cell& cell, TypeContainerVisitor<T, CONTAINER>& visitor)
{
const uint32 x = cell.GridX();
const uint32 y = cell.GridY();
const uint32 cell_x = cell.CellX();
const uint32 cell_y = cell.CellY();
if (!cell.NoCreate() || loaded(GridPair(x, y)))
{
EnsureGridLoaded(cell);
getNGrid(x, y)->Visit(cell_x, cell_y, visitor);
}
}
找到具体的格子容器 执行同步
template<class T, class TT>
void Visit(const uint32& x, const uint32& y, TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
{
getGridType(x, y).Visit(visitor);
}
GridType& getGridType(const uint32& x, const uint32& y)
{
assert(x < N);
assert(y < N);
return i_cells[x][y];
}
template<class T, class TT>
void Visit(TypeContainerVisitor<T, TypeMapContainer<TT> >& visitor)
{
for (uint32 x = 0; x < N; ++x)
for (uint32 y = 0; y < N; ++y)
i_cells[x][y].Visit(visitor);
}
template<class T>
void Visit(TypeContainerVisitor<T, TypeMapContainer<WORLD_OBJECT_TYPES> >& visitor)
{
visitor.Visit(i_objects);
}
上面就是数据在GIRD传递的过程 下面 开始数据开始调用 之前创建的ObjectMessageDistDeliverer结构体 是封装到了TypeContainerVisitor容器内的 下面代码是调用过程
template<class VISITOR, class TYPE_CONTAINER>
class TypeContainerVisitor
{
public:
TypeContainerVisitor(VISITOR& v)
: i_visitor(v)
{
}
void Visit(TYPE_CONTAINER& c)
{
VisitorHelper(i_visitor, c);
}
void Visit(const TYPE_CONTAINER& c) const
{
VisitorHelper(i_visitor, c);
}
private:
VISITOR& i_visitor;
};
template<class VISITOR, class OBJECT_TYPES>
void VisitorHelper(VISITOR& v, TypeMapContainer<OBJECT_TYPES>& c)
{
VisitorHelper(v, c.GetElements());
}
前面我们说过 我们使用过
typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, Camera) AllWorldObjectTypes;
typedef TypeMapContainer<AllWorldObjectTypes> WorldTypeMapContainer;
所以
TypeContainerVisitor<MaNGOS::ObjectMessageDistDeliverer, WorldTypeMapContainer > message(post_man);
这个第二个参数 就代表了TYPE_CONTAINER 的类型是 ContainerMapList<TypeList<H, T> >&
所以这里最后调用的函数是下面的 并且使用了递归访问了结构体内的visit函数
template<class VISITOR, class H, class T>
void VisitorHelper(VISITOR& v, ContainerMapList<TypeList<H, T> >& c)
{
VisitorHelper(v, c._elements);
VisitorHelper(v, c._TailElements);
}
因为其他类型都skip了 最后访问的到了到了ObjectMessageDistDeliverer的void Visit(CameraMapType& m);函数 就把需要同步的物体信息转发给了有摄像机的连线玩家
PS 上面代码展示的只是AOI算法同步数据 玩家或者物体移动进入新的cell需要重新定位 从旧的cell里面移除 并且添加到新的cell里面去 芒果魔兽源码可以参考RemoveFromGrid 调用的地方
文章中有不理解的地方 进群交流讨论服务器技术 可以加Q群397926909