帮助文档
专业提供香港服务器、香港云服务器、香港高防服务器租用、香港云主机、台湾服务器、美国服务器、美国云服务器vps租用、韩国高防服务器租用、新加坡服务器、日本服务器租用 一站式全球网络解决方案提供商!专业运营维护IDC数据中心,提供高质量的服务器托管,服务器机房租用,服务器机柜租用,IDC机房机柜租用等服务,稳定、安全、高性能的云端计算服务,实时满足您的多样性业务需求。 香港大带宽稳定可靠,高级工程师提供基于服务器硬件、操作系统、网络、应用环境、安全的免费技术支持。
服务器资讯 / 香港服务器租用 / 香港VPS租用 / 香港云服务器 / 美国服务器租用 / 台湾服务器租用 / 日本服务器租用 / 官方公告 / 帮助文档
魔兽服务器学习-笔记(服务器部署、地图管理、DB、日志模块、任务模块、战斗模块)
发布时间:2024-03-08 06:48:10   分类:帮助文档
魔兽服务器学习-笔记(服务器部署、地图管理、DB、日志模块、任务模块、战斗模块) 文章目录 一、环境准备1)依赖安装2)源码下载和编译 二、生成数据信息1)地图数据信息(客户端信息)2)数据库信息 三、启动服务器四、日志模块五、数据库模块六、场景模块1)地图管理2)AOI算法1、静态数据讲解2、动态数据:3、动态数据结构NGrid解析4、涉及用户登录的逻辑及grid状态转变5、涉及玩家退出的逻辑及grid状态转变 3)地图数据驱动1)网络驱动2)地图定时更新做的事 4)动态数据管理(1)设计模式-访问者模式及代码表现形式 5)碰撞检测实现(BIH+AABB) 七、战斗模块1)技能模块①技能信息类SpellInfo 八、MMO常用模块(任务、副本、商店等)九、AI十、游戏实体代码1)trinitycore实体类介绍2)分开介绍各实力类(1)object类 十、背包模块 一、环境准备 1)依赖安装 sudo apt-get update sudo apt-get install git clang cmake gcc g++ libmysqlclient-dev libss-dev libbz2-dev libreadline-dev libncurses-dev libboost-all-dev mysql-server-5.7 p7zip sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100 sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang 100 // sudo yum install -y clang 2)源码下载和编译 git clone -b 3.3.5 https//github.com//TrinityCore/TrinityCore.git mkdir build cd build cmake ../ -DCMAKE_INSTALL_PREFIX=/home/lighthouse/tinycore -DCONF_DIR=/home/lighthouse/tinycore/bin make -j2 (nproc看核心数来编译) make install 二、生成数据信息 1)地图数据信息(客户端信息) 1)cd ~ 2)mkdir res (根目录创建res文件夹) 3)把客户端目录的Data和Interface移动到res目录下 4)cd res 在res目录执行游戏目录bin/下面的mapextractor, 生成dbc和maps文件夹 5)mkdir vmaps 在res目录执行游戏目录bin/下面的vmap4extractor, 生成vmaps文件夹和Buildings目录 5)在res目录执行游戏目录bin/下面的vmap4assembler, ../lighthouse/bin/vmap4assembler Buildings vmaps 6) mkdir mmaps 在res目录执行游戏目录bin/下面的mmaps_generator 生成mmaps目录 2)数据库信息 注意 需要提前安装mysql mysql -uroot -p password 1)在TrinityCore的sql/create目录的路径赋值,打开mysql mysql> source ../Trinity/sql/create/create_mysql.sql show database; 可以看到生成了auth \ character \ world 三、启动服务器 1)先进到项目的bin目录,复制authserver.conf 启动授权服务器 ./authserver 2)同样步骤,复制worldserver.conf 并且改写DataDir,指定res目录 DataDir="../../res" 启动worldserver 启动授权服务器 ./worldserver 四、日志模块 五、数据库模块 六、场景模块 1)地图管理 ①哪些模块会用到地图模块? 1)运动模块:走、跳、飞行 2)副本 3)寻路 ②地图模块要实现哪些功能? 1)AOI:管理地图地理信息、地图对象信息 2)功能:视野、数据同步、碰撞检测、寻路算法 ③怎么驱动地图模块? 1)移动的网络数据驱动 2)定时更新(怪物的AI行为) 2)AOI算法 职责: ①静态数据: 《1》trinity由mapextractor生成.map文件(基础地图信息),数据包括 1) area data (区域物体信息) 2) height data (高度信息) 3) liquid data (水) 4) hole data (洞) 《2》由mmaps_generator生成可移动地图信息 .mmap,游戏中的地图移动数据(用来给navmesh寻路),也就是用recast和detour生成寻路信息 1) mmtile 索引对应具体地图的所有信息(x+y做名字前缀) 2) .mmap 索引 《3》vmapsextractor生成地图元素信息(可视场景信息:山脉、水体、建筑物等静态场景信息),用于未来做碰撞检测, *.m2和 *.wmo文件 静态物品包围盒信息 *.mdx 角色、物品和怪物包围盒信息 《4》vmap4assembler合并vmapsextractor和mmaps_generator生成的地图信息,vmtile信息 ②动态数据 1、静态数据讲解 NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; //NGridType是动态数据 GridMap* GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; //原始数据,最新的已去除 //静态数据,64*64的格子, //每个格子是8*8个cell,grid和cell都有自己的坐标系 //动物、角色、怪物都是在具体的cell当中 std::bitset marked_cells; 2、动态数据: 玩家在哪个grid的cell,哪个grid才会被加载,否则不会被加载到内存当中 (只有玩家进入这个区域才会动态加载这个区域的资源) 3、动态数据结构NGrid解析 ①数据结构 //NGridType是模板类 extern template class NGrid; typedef NGrid NGridType; AllWorldObjectTypes:(动态的obj) player玩家、宠物、尸体、动态物品(远处target) typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, DynamicObject/*farsight target*/) AllWorldObjectTypes; AllGridObjectTypes :(静态的obj) 游戏obj、除了宠物的obj、动态物体、尸体 typedef TYPELIST_7(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/, AreaTrigger, SceneObject, Conversation) AllGridObjectTypes; ②具体分析 NGrid有两个容器:i_container和i_objects private: uint32 i_gridId; GridInfo i_GridInfo; GridReference > i_Reference; int32 i_x; int32 i_y; grid_state_t i_cellstate; GridType i_cells[N][N]; bool i_GridObjectDataLoaded; typedef Grid GridType; class Grid private: TypeMapContainer i_container; TypeMapContainer i_objects; 玩家进入某个grid的cell,地图加载数据激活推动消息推送 4、涉及用户登录的逻辑及grid状态转变 MapRefManager m_mapRefManager;//MapRefManager双向循环链表 1)根据地图ID、xyz轴、面向在地图上准备new obj 2)把玩家链接到这个地图对应的双向循环链表上 3)根据玩家坐标创建一个cell,加载玩家到对应地图的内存上,若这个cell只有一个玩家则加载cell全部地图信息 4)把玩家的包围盒和怪物、NPC、玩家用BSP tree包围盒做碰撞检测(访问者模式) DynamicMapTree _dynamicTree; void Balance() { _dynamicTree.balance(); } 5、涉及玩家退出的逻辑及grid状态转变 1)当定时器超时玩家没重连,那就把玩家从当前地图清除 ⑤地图的状态 1)Idle 2)Active 3)InValid //无效状态 4)REMOVAL //准备从内存中卸载 地图状态转换说明: ①起伏创建是Invalid, ②加载具体cell到grid里面是Idle状态, ③当把玩家放进来的时候是Active状态, ④当玩家退出或掉线时候,这个cell是无人的时候,变为Idle状态 ⑤当超时重连结束,玩家被从地图删除实例,则是Removal状态,下次服务器tick触发的时候把地图从内存卸载 (魔兽主线程等待子线程update地图事件,全部结束后才往下把所有map走delayUpdate,更新地图状态机,走从内存卸载删除逻辑) 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; 3)地图数据驱动 玩家进入某个grid的cell,地图加载数据激活推动消息推送 1)网络驱动 网络结构说明 ①创线程池A,线程主要做: 1)信号处理 2)远程连接请求 3)数据库心跳 4)生成core检查 5)异步日志 ... ②主线程有主循环,按照一定频率update游戏世界逻辑,执行的逻辑比如 1)更新玩家session信息,根据玩家连接状态更改session状态 (如果不是线程安全,那就在主线程处理,后面的业务逻辑是多线程处理的) 2)主线程处理的逻辑包括:从数据库获取基础的玩家初始数据比如背包等 3)其他线程中的处理:在地图中攻击、寻路、走路 ③线程池B,主要处理地图数据 读取配置中的线程数量,创建线程池,并给每条线程发更新地图的放到阻塞的任务队列,每条map也能处理来自客户端发送的数据包 void MapManager::Update(uint32 diff) { i_timer.Update(diff); if (!i_timer.Passed()) return; MapMapType::iterator iter = i_maps.begin(); while (iter != i_maps.end()) { if (iter->second->CanUnload(diff)) { if (DestroyMap(iter->second)) iter = i_maps.erase(iter); else ++iter; continue; } if (m_updater.activated()) m_updater.schedule_update(*iter->second, uint32(i_timer.GetCurrent())); else iter->second->Update(uint32(i_timer.GetCurrent())); ++iter; } if (m_updater.activated()) m_updater.wait(); for (iter = i_maps.begin(); iter != i_maps.end(); ++iter) iter->second->DelayedUpdate(uint32(i_timer.GetCurrent())); i_timer.SetCurrent(0); } ④线程池C用来负载均衡处理客户端发包(Network) 2)地图定时更新做的事 ①更新这个地图中的玩家,用访问者模式给玩家广播周围的obj(让自己在同cell里面被其他人看到),处理视野相关内容 ②包围盒_dynamicTree二叉树检测物体碰撞(惰性更新,每次更新的时候进行平衡) void Map::Update(uint32 t_diff) { _dynamicTree.update(t_diff); //包围盒检测 /// update worldsessions for existing players for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter) { Player* player = m_mapRefIter->GetSource(); if (player && player->IsInWorld()) { //player->Update(t_diff); WorldSession* session = player->GetSession(); MapSessionFilter updater(session); session->Update(t_diff, updater); } } ... } ③处理人物的重生计时 /// process any due respawns if (_respawnCheckTimer <= t_diff) { ProcessRespawns(); UpdateSpawnGroupConditions(); _respawnCheckTimer = sWorld->getIntConfig(CONFIG_RESPAWN_MINCHECKINTERVALMS); } else _respawnCheckTimer -= t_diff; ④玩家战斗中技能释放、副本流程、人物、成就的更新 4)动态数据管理 (1)设计模式-访问者模式及代码表现形式 概念 ①提供一个访问者类,可以改变元素类的执行算法 ②传入不同的访问者,可以使用不同的执行算法解决的问题 稳定的数据结构和容易改变的操作耦合问题解决方法 在元素类型中提供对应不同访问者的接口目的 将数据结构和数据操作进行分离代码 T是算法,CONTAINER是数据结构 1)TypeContainer.h 有两种结构:双向链表和散列表,解决不同链表、不同散列表的差异 2)TypeContainerFunctions.h 解决双向链表和散列表之间的差异 3)TypeCOntainerVistor.h 解决对访问者的抽象,不同访问者实现不同的算法 template inline void Map::Visit(Cell const& cell, TypeContainerVisitor& 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() || IsGridLoaded(GridCoord(x, y))) { EnsureGridLoaded(cell); getNGrid(x, y)->VisitGrid(cell_x, cell_y, visitor); } } 通过下面这个函数将不同obj加入到不同的双向链表里面 1)不同双向链表: TypeMapContainer i_container; TypeMapContainer i_objects; 2)访问者算法加入不同链表的算法 template class GridReference : public Reference, 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, OBJECT>() { } ~GridReference() { this->unlink(); } GridReference* next() { return (GridReference*)Reference, OBJECT>::next(); } }; 3)不同类型的访问者做不同处理,visit就是不同的算法 class TC_GAME_API ObjectGridLoader : public ObjectGridLoaderBase { friend class ObjectWorldLoader; public: ObjectGridLoader(NGridType& grid, Map* map, Cell const& cell) : ObjectGridLoaderBase(grid, map, cell) { } void Visit(GameObjectMapType &m); void Visit(CreatureMapType &m); void Visit(AreaTriggerMapType &m); void Visit(CorpseMapType &) const { } //尸体obj void Visit(DynamicObjectMapType&) const { } //动态物品,掉落装备等 void Visit(SceneObjectMapType&) const { } //场景对象 void Visit(ConversationMapType&) const { } //对话obj void LoadN(); }; 5)碰撞检测实现(BIH+AABB) 碰撞检测目标 对象模型的包围盒数据来源 vmap4extractor提取的场景信息(建筑、山脉、水体等)、角色、怪物、装备等3d模型信息逻辑流程 1)是否在视线范围内 2)碰撞检测,算命中位置(如不同楼层等高度信息) 3)获取地图信息怎么实现?(一句话:射线和包围盒的碰撞) ①插入的时候会平衡一次 ②然后就是定时200ms平衡一次实现代码 class TC_COMMON_API DynamicMapTree { DynTreeImpl *impl; public: DynamicMapTree(); ~DynamicMapTree(); bool isInLineOfSight(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, PhaseShift const& phaseShift) const; bool getIntersectionTime(G3D::Ray const& ray, G3D::Vector3 const& endPos, PhaseShift const& phaseShift, float& maxDist) const; bool getObjectHitPos(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos, G3D::Vector3& resultHitPos, float modifyDist, PhaseShift const& phaseShift) const; //看层高 float getHeight(float x, float y, float z, float maxSearchDist, PhaseShift const& phaseShift) const; bool getAreaInfo(float x, float y, float& z, PhaseShift const& phaseShift, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const; void getAreaAndLiquidData(float x, float y, float z, PhaseShift const& phaseShift, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const; //添加、删除、看是否存在 void insert(GameObjectModel const&); void remove(GameObjectModel const&); bool contains(GameObjectModel const&) const; //更新就是平衡 void balance(); void update(uint32 diff); //定时平衡,200ms平衡一次 }; 核心算法和数据结构 数据结构是BIH树,核心算法是AABB(轴对称边界盒算法,射线和包围盒相交的算法),BIH作为二叉树是为了快速进行流程,避免费时计算 如何实现BIH树? 1、构建BIH树 2、光线追踪算法AABB(AABB并不是稳定的结构,可能随时会有新obj进来)碰撞计算逻辑 1、计算包围盒(vmap数据中进行加载) 2、在一个grid中所有对象根据中轴线构建二叉树,左边为左子树,右边为右子树,判断节点方块与光线是否相交,若相交则不断递归下去,直到满足递归停止条件(递归深度64) 3、注意:每个节点都是子树对象包围盒的并集 4、射线就是行走路径 优化 ①初始时构建一次 ②定时构建: 1、200ms构建一次 2、如果BIH树发生改变才会重新构建 七、战斗模块 总体评价 分为skill和spell模块 1)技能模块 技能枚举 enum SpellRangeFlag { SPELL_RANGE_DEFAULT = 0, SPELL_RANGE_MELEE = 1, //melee,近战 SPELL_RANGE_RANGED = 2 //hunter range and ranged weapon,远程 }; ①技能信息类SpellInfo class TC_GAME_API SpellInfo { friend class SpellMgr; public: uint32 Id; SpellCategoryEntry const* CategoryEntry; uint32 Dispel; uint32 Mechanic; uint32 Attributes; ........ 八、MMO常用模块(任务、副本、商店等) 九、AI 文章记录在魔兽AI解析 十、游戏实体代码 代码细节 1)基类构造函数放在protected里面保证了该类的实例不能被直接创建,只能通过继承该类的子类来创建实例 1)trinitycore实体类介绍 ①Unit:表示游戏中的各种实体,例如玩家、NPC、怪物等。Unit是一个抽象的概念,包含了所有实体共有的属性和行为,例如位置、朝向、生命值、法力值、攻击力、防御力等。与Object、WorldObject和GameObject类不同的是,Unit类更加关注实体的战斗属性和行为,例如攻击、防御、技能等。 ②Creature:表示游戏中的怪物,是从Unit类继承而来的。Creature类包含了各种怪物特有的属性和行为,例如怪物类型、等级、掉落物品等。 ③Player:表示游戏中的玩家,也是从Unit类继承而来的。Player类包含了各种玩家特有的属性和行为,例如职业、技能、装备等。 ④Object类:是所有游戏实体类的基类,包含了所有实体共有的属性和行为,例如位置、朝向、生命值、法力值、攻击力、防御力等。与Unit、WorldObject和GameObject类不同的是,Object类更加关注实体的基本属性和行为,例如位置、朝向、生命值、法力值等。 ⑤WorldObject类:是从Object类继承而来的类,表示游戏中的所有可视实体,例如玩家、NPC、怪物、游戏对象等。与Unit、Object和GameObject类不同的是,WorldObject类更加关注实体的可视化属性和行为,例如模型、动画、光照等。 ⑥GameObject类:是从WorldObject类继承而来的类,表示游戏中的游戏对象,例如门、箱子、火堆等。与Unit、Object和WorldObject类不同的是,GameObject类更加关注实体的对象属性和行为,例如对象类型、状态、交互方式等。 2)分开介绍各实力类 (1)object类 十、背包模块 这里的代码解析我放到别的文章中去了 背包模块代码解析
香港云服务器租用推荐
服务器租用资讯
·广东云服务有限公司怎么样
·广东云服务器怎么样
·广东锐讯网络有限公司怎么样
·广东佛山的蜗牛怎么那么大
·广东单位电话主机号怎么填写
·管家婆 花生壳怎么用
·官网域名过期要怎么办
·官网邮箱一般怎么命名
·官网网站被篡改怎么办
服务器租用推荐
·美国服务器租用
·台湾服务器租用
·香港云服务器租用
·香港裸金属服务器
·香港高防服务器租用
·香港服务器租用特价