目录

概念及功能

网格对象(Grid Object) 和世界对象(World Object)

工作流程


  • 概念及功能

    TrinityCore 的 Grid 系统是一套复杂的地图分区管理机制,其核心目标是通过动态管控游戏世界的区域状态和对象生命周期,在保证玩家体验的同时最大化服务器性能。它具有以下功能:

    • 地图划分与定位
      TrinityCore 将每一张地图(Map)都划分成 64*64 的小方块,即网格(Grid),每个 Grid 的大小是 533.33 码。网格的坐标从右下角 (0,0) 到左上角 (63,63),以 (32,32) 为中心点。这种划分方式便于服务器和客户端对地图进行管理和定位,例如可以在GM模式下使用 “.go grid 48,18” 类似命令跳到当前地图编号为 (48,18) 的格子。

    • 资源加载与卸载
      客户端和服务端均按 Grid 为单位进行地图资源的加载和卸载。当角色在地图中移动时,客户端只加载角色附近的 Grid,当角色走到一个 Grid 边界时,再新加载相邻的 Grid,同时卸载远离角色的 Grid,从而有效控制内存占用。服务端也是如此,只有当某个 Grid 有角色进入时,才会将其标记为活跃状态,加载其中的动态信息,如怪物、NPC、矿点等;当 Grid 内没有活跃角色且超过一定时间后,会将其标记为不活跃状态,卸载其中的动态对象,回收 Grid。

    • 对象管理
      Grid 用于管理其中的各种对象,包括网格对象(grid object)和世界对象(world object)。Grid 类提供了一系列方法来插入、移除和统计这些对象,如add_grid_object方法用于将一个对象插入到网格中,get_world_object_countingrid方法用于获取网格中世界对象的数量。

    • 寻路支持
      Grid 与寻路功能相关,TrinityCore 可以利用导航网格(Grid)做寻路,通过 Detour 库等实现角色在地图上的路径规划,确保角色能够在网格划分的地图上顺利找到目标位置。

  • 网格对象(Grid Object)世界对象(World Object)

    • 世界对象(World Object)
      是游戏世界中所有 “可交互实体” 的基类(WorldObject),代表游戏中具有独立存在意义的实体,例如角色(Player)、NPC(Creature)、物品(Item)、动态物体(GameObject,如箱子、门)等。世界对象(World Object)是游戏逻辑的核心载体,拥有独立的属性(如位置、方向、状态)和行为(如移动、战斗、交互),并直接参与游戏玩法(如任务、战斗、交易)。

      • 世界对象负责实现具体的游戏逻辑,例如:处理玩家输入(移动、技能释放),NPC 的 AI 行为(巡逻、攻击、对话),物品的拾取、使用效果,碰撞检测、交互判定(如点击 NPC 触发对话),等等。
      • 世界对象生命周期与实体本身绑定:例如玩家登录时创建,下线时销毁;NPC 被刷新时创建,被删除(如死亡后消失)时销毁。
      • 当世界对象(如角色移动)从一个 Grid 进入另一个 Grid 时,其对应的网格对象会从旧 Grid 移除,添加到新 Grid 中。
      • 世界对象在整个游戏世界中具有唯一标识(GUID),可被全局查询和引用。

      • 世界对象是基类,派生类包括Corpse、Creature、DynamicObject、GameObjectPlayer、AreaTrigger、SceneObject、Conversation等,每个派生类都有独特的属性和方法(如Player有背包系统,Creature有 AI 组件)。

    • 网格对象(Grid Object)
      是与 Grid 网格绑定的 “辅助管理对象”(GridObject),主要用于衔接世界对象与 Grid 系统,负责将世界对象 “锚定” 到具体的网格中,以便 Grid 系统对其进行定位、加载 / 卸载和区域管理。它更像是世界对象在 Grid 系统中的 “代理” 或 “索引”,本身不直接参与游戏逻辑,仅用于 Grid 内部的管理和查询。

      • 网格对象主要服务于 Grid 系统的管理需求,例如:记录世界对象在 Grid 中的位置偏移,辅助 Grid 快速定位实体;作为 Grid 内部的 “容器项”,参与 Grid 的对象列表维护(如添加、移除、遍历);触发 Grid 的状态变化(如当 Grid 中首个世界对象进入时,标记 Grid 为 “活跃” 并加载资源)。
      • 网格对象生命周期与 Grid 绑定:当一个世界对象进入某个 Grid 时,Grid 会为其创建对应的网格对象;当世界对象离开 Grid 或 Grid 被卸载时,网格对象会被销毁。
      • 网格对象仅存在于所属 Grid 中:每个网格对象严格属于一个 Grid,用于在该 Grid 内标记世界对象的存在,方便 Grid 快速定位其中的所有实体。
      • 网格对象是模板类(GridObject<T>),其中T通常是WorldObject的派生类(如GridObject<Creature>),它内部持有一个指向对应世界对象的指针,实现 Grid 与世界对象的关联。
  • 工作流程

        工作流程分为初始化与地图划分、Grid 激活与对象加载、活跃状态管理、Grid 失活与资源回收四个阶段,各阶段紧密衔接,形成完整的闭环逻辑。

        一、初始化与地图划分:构建 Grid 的 “骨架”

        Grid 系统的工作从地图(Map)加载开始,当服务器启动或角色首次进入某张地图时,系统会先完成 Grid 的基础构建:

  1. 地图元数据加载
    从数据库(如map表)和地图资源文件(.adt等)中读取地图的基础信息,包括地图 ID、尺寸、地形数据等。每张地图被视为一个独立的 “世界区域”,由Map类实例管理。

  2. Grid 网格划分
    按照固定规则将地图划分为64×64 的 Grid 网格(共 4096 个 Grid),每个 Grid 的物理尺寸为 533.33 码(约 133.33 游戏单位)。网格坐标以地图右下角为原点 (0,0),左上角为 (63,63),形成类似二维数组的索引体系(如 Grid (10,20) 代表第 10 列、第 20 行的网格)。

  3. Grid 基础实例化
    为每个 Grid 创建基础实例(Grid类对象),此时的 Grid 仅包含坐标信息和空的对象列表,处于 **“未初始化” 状态 **(不加载任何世界对象,仅作为占位符存在)。这些 Grid 由GridManager统一管理,通过地图 ID+Grid 坐标可快速定位。

        二、Grid 激活与对象加载:从 “休眠” 到 “活跃”

        Grid 默认处于 “休眠” 状态,仅当需要响应用户交互时才被激活。“有玩家角色进入” 是触发 Grid 激活的核心条件

  1. 玩家位置检测
    当角色(Player对象)通过移动、传送、复活等方式进入某 Grid 时,系统通过角色坐标计算其所在的 Grid 坐标(如通过Map::GetGridX()Map::GetGridY()方法),并检查该 Grid 的当前状态。

  2. Grid 状态切换:从非活跃到活跃

    • 若 Grid 处于 “非活跃状态”(无玩家且未加载对象),系统会将其标记为 “活跃状态”(Active),并触发Grid::Activate()方法。
    • 激活时,Grid 会向Map模块注册自身,加入 “活跃 Grid 列表”,以便后续接收定期更新(如每 100ms 一次的逻辑帧更新)。
  3. 世界对象加载
    激活后,Grid 开始加载其内 “应存在” 的世界对象(WorldObject)。

    • 查询数据源:根据地图 ID 和 Grid 坐标,从数据库(如creaturegameobject表)查询该 Grid 内的静态对象(如固定刷新的 NPC、门、矿点)和动态对象(如任务触发的怪物)。
    • 实例化对象:根据查询结果,创建对应的世界对象实例(如CreatureGameObject),初始化其属性(位置、方向、状态、AI 脚本等)。
    • 绑定网格对象(GridObject):为每个世界对象创建对应的GridObject(网格对象),作为其在 Grid 中的 “代理”,并将GridObject添加到 Grid 的对象列表(Grid::m_objects)中。
    • 通知周边系统:对象加载完成后,通知视野管理模块(让附近玩家可见)、AI 系统(启动 NPC 巡逻 / 战斗逻辑)、事件系统(注册交互事件,如点击 NPC 触发对话)。

        三、活跃状态管理:维持对象交互与更新

        Grid 处于活跃状态时,核心任务是实时管理其内对象的状态和交互,确保游戏逻辑正常运行,主要包括以下操作:

  1. 定期逻辑更新
    Grid 会随服务器的逻辑帧(通常每 100ms 一次)执行Grid::Update()方法,完成:

    • 对象状态同步:更新世界对象的位置、血量、状态(如 NPC 的巡逻路径进展、GameObject 的开关状态)。
    • AI 与行为驱动:触发 NPC 的 AI 逻辑(如检测玩家进入仇恨范围、执行技能)、物品的定时消失(如掉落的装备过期)。
    • 事件检测:检查对象间的交互(如玩家点击门、拾取物品),触发对应的游戏事件(如任务进度更新、成就解锁)。
  2. 对象跨 Grid 移动处理
    当世界对象(如玩家、移动的 NPC)从当前 Grid 进入相邻 Grid 时,触发对象转移流程

    • 旧 Grid 移除对象:原 Grid 通过Grid::RemoveObject()方法,将对象的GridObject从自身列表中移除,并通知旧 Grid(若此时旧 Grid 内无玩家,开始失活倒计时)。
    • 新 Grid 添加对象:新 Grid 检测到角色进入后,若自身处于非活跃状态则立即激活,然后通过Grid::AddObject()方法创建新的GridObject,将对象纳入管理,并同步其状态到新 Grid 及周边系统。
  3. 动态对象生成与销毁
    对于临时产生的对象(如玩家召唤的宠物、技能创建的幻象、任务触发的怪物),Grid 会在其生成时立即创建GridObject并纳入管理;当对象过期(如宠物消失、幻象时间结束)或被销毁(如怪物被击杀)时,Grid 会移除其GridObject并回收内存。

        四、Grid 失活与资源回收:从 “活跃” 到 “休眠”

        当 Grid 内不再有角色活动时,系统会逐步卸载资源,释放服务器内存和 CPU 占用。

  1. 失活触发条件

    • 所有角色离开该 Grid(如移动到其他 Grid、下线、传送);
    • Grid 内无角色的时间超过阈值(默认约 5 分钟,可通过配置调整)。
      满足条件后,Grid 被标记为 “待失活状态”,触发Grid::Deactivate()方法。
  2. 对象筛选与卸载
    Grid 会先筛选可卸载的对象,保留必要数据:

    • 不可卸载对象:角色(Player)本身不会随 Grid 失活卸载(其生命周期与登录状态绑定);带有 “永久保存” 标记的对象(如玩家放置的营地)会保留状态。
    • 可卸载对象:大部分 NPC、GameObject、临时物品等,会先将状态同步到数据库(如 NPC 的刷新时间、已打开的箱子状态),然后销毁其实例和对应的GridObject
  3. Grid 资源回收

    • 清空 Grid 的对象列表,释放与对象相关的临时数据(如视野缓存、AI 状态)。
    • Grid 从 “活跃 Grid 列表” 中移除,回到 “非活跃状态”,仅保留基础坐标信息,进入 “休眠”。
    • 若后续有角色再次进入该 Grid,重复 “激活→加载” 流程。

        五、特殊场景的补充处理

        Grid 系统针对特殊需求做了优化,确保极端场景下的稳定性:

  • 强制激活 / 失活:GM 可通过指令(如.go grid.grid activate)强制激活某 Grid,用于调试或事件触发;也可强制失活 Grid 以快速释放资源。
  • 超大对象处理:对于跨多个 Grid 的大型对象(如团队副本的 Boss 场地),系统会将其关联到多个 Grid,确保在任何相关 Grid 激活时都能正确加载。
  • 动态地图(如副本):副本地图的 Grid 生命周期与副本实例绑定,当副本内所有玩家离开并超过超时时间后,整个副本的 Grid 系统会被彻底销毁,而非仅失活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93560.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93560.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93560.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文搞懂LLM大模型!LLM从入门到精通万字长文(2024.12月最新)

LLM从入门到精通精品文章 目录 一、LLM基本概念 二、LLM发展历程 三、LLM大模型的分类 四、LLM主流大模型类别 五、LLM大模型建立的流程 六、Fine-Tuning 七、Prompt-Tuning 八、超大规模参数模型Prompt-Tuning方法 8.1上下文学习 In-Context Learning 8.2.指令学习 …

Next.js跟React关系(Next.js是基于React库的全栈框架)(文件系统路由、服务端渲染SSR、静态生成SSG、增量静态再生ISR、API路由)

文章目录**1. React 是基础&#xff0c;Next.js 是扩展****2. Next.js 解决了 React 的哪些痛点&#xff1f;****3. 核心区别****4. Next.js 的核心特性**1. **文件系统路由**2. **服务端渲染&#xff08;SSR&#xff09;**3. **静态生成&#xff08;SSG&#xff09;**4. **增量…

Nightingale源码Linux进行跨平台编译

最近使用Nightingale 需要实现对服务的监测&#xff0c;想要在Windows 系统中使用&#xff0c;看官方文档中并不直接提供执行程序&#xff0c;原文如下&#xff1a; 准备工作 本地环境 本地已经安装git 本地安装git 便于后续下载源码并进行自动编译。 Linux操作系统环境&…

抽丝剥茧丨PostgreSQL 系国产数据库%SYS CPU newfstatat() high 调优一例(二)

续接上回《PostgreSQL 系国产数据库%SYS CPU newfstatat() high 调优一例&#xff08;一&#xff09;》&#xff0c;这个问题还在持续&#xff0c;并且原因并不只是一个&#xff0c;从调了文件系统级atime&#xff0c;到调整wal size减少日志被动清理&#xff0c;还有在验证tem…

【新手入门】Android Studio 项目结构拆解,快速理解文件作用!

目 录 一、【Project】视图下项目结构&#xff08;真实目录&#xff09; 二、【Android】视图下项目结构 三、【app/】下重要文件解析 1、 build.gradle 2、AndroidManifest.xml 3、res/ 作为刚刚接触Android开发的小白&#xff0c;使用Android Studio创建项目后&…

Python实现点云Kmeans、欧式和DBSCAN聚类

本节我们分享点云处理中的三种常见聚类方法&#xff0c;分别是K-means、欧氏与 DBSCAN聚类。具体介绍如下&#xff1a;1. K-means 聚类定义&#xff1a;一种基于距离度量的无监督学习算法&#xff0c;将数据划分为 K 个紧凑的簇&#xff0c;使簇内数据相似度高、簇间差异大。算…

【Java后端】MyBatis-Plus 原理解析

MyBatis-Plus 原理解析 其实 MyBatis-Plus 的 Service 层设计就是为了让开发者不用重复写很多样板代码。我们来一点点剖析 UserServiceImpl、IService、UserService、ServiceImpl 之间的关系和调用链。1. 类/接口关系图IService<T>▲│UserService (接口) <-- 自定义…

Nacos 注册中心学习笔记

&#x1f389; Alibaba微服务组件 Nacos 注册中心超详细学习笔记 &#x1f389; &#x1f4cc; 写在前面&#xff1a;本文基于官方PDF文档与实战经验&#xff0c;整理了Nacos注册中心的核心知识点、部署流程与实战技巧&#xff0c;力求图文并茂、通俗易懂&#xff0c;适合收藏反…

java 策略模式 demo

策略模式介绍策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列算法&#xff0c;将每个算法封装起来并使它们可相互替换。策略模式让算法的变化独立于使用算法的客户端&#xff0c;从而实现灵活的算法切换。核心角色&#xff1…

SAP Valuation Category在制造业成本核算中的使用场景与配置方案

Valuation Category在制造业成本核算中的使用场景与配置方案一、核心使用场景&#xff08;制造业特有&#xff09;1. 内制 vs 外购成本分离业务需求&#xff1a;同一物料可能通过内部生产&#xff08;成本含料工费&#xff09;或外部采购&#xff08;成本含采购价运费&#xff…

我的 LeetCode 日记:Day 36 - 动态规划,背包问题的千变万化

昨天&#xff0c;我初步掌握了 0/1 背包问题的理论基础和标准解法。今天&#xff0c;我将这种思想应用到了更广泛的场景中。今天的几道题&#xff0c;乍一看和背包没什么关系&#xff0c;但通过巧妙的数学转化&#xff0c;它们的核心都变成了 0/1 背包问题。 这让我深刻体会到…

本地处理不上传!隐私安全的PDF转换解决方案

PDF能锁定排版、字体、图片位置&#xff0c;无论在什么设备打开都保持一致。它是无广告、简洁高效的专业PDF处理工具。功能丰富&#xff0c;支持批量操作&#xff1a;只需将文件拖入界面&#xff0c;选择目标格式&#xff08;如Word、PPT、Excel、图片等&#xff09;&#xff0…

Docker build创建镜像命令入门教程

一、核心概念Dockerfile 定义镜像构建步骤的文本文件&#xff0c;包含一系列指令和配置&#xff0c;用于自动化创建镜像。镜像层&#xff08;Layer&#xff09; Docker 镜像由多层只读层叠加而成&#xff0c;每个指令&#xff08;如 RUN、COPY&#xff09;会生成一个新的层。层…

Redis 是单线程模型吗?

最近在面试中经常被问到这个问题&#xff1a;"Redis是单线程的吗&#xff1f;"很多同学都会脱口而出&#xff1a;"是的&#xff01;"但其实这个答案并不完全正确。今天我们就来聊聊Redis的线程模型&#xff0c;把这个问题彻底搞清楚。 先说结论 Redis的线程…

Hologres实战:路径分析函数

前言 Hologres提供了一套高效的路径分析函数&#xff0c;包括路径明细计算和结果解析功能&#xff0c;能够帮助用户深入理解用户行为路径&#xff0c;并通过桑基图实现数据可视化。 一、核心功能 路径明细计算&#xff1a;精确记录用户在产品或功能中的完整访问路径结果解析…

产品开发实践(常见的软硬结合方式)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】前面说过&#xff0c;传统的纯软件开发&#xff0c;在国内的大背景下面是很难存活的。但是如果是把软件&#xff0c;构建在硬件基础之上&#xff0c…

Linux | i.MX6ULL网络通信-套字节 UDP(第十八章)

01 Linux | i.MX6ULL网络通信-套字节 TCP(第十七章) 02 iTOP-IMX6ULL 实现基于 UDP 的 socket 编程。

学习嵌入式第三十天

文章目录进程和线程&#xff08;续&#xff09;线程1.线程传参2.线程属性3.线程间通信1.概念2.方式3.互斥锁4.死锁5.信号量习题 进程和线程&#xff08;续&#xff09; 线程 1.线程传参使用第四个参数实现对线程内部的传参 代码实现&#xff1a; #include <stdio.h> #inc…

GaussDB 数据库架构师修炼(十三)安全管理(3)-行级访问控制

1 背景行级访问控制特性将数据库的访问控制精确到数据表行级别 &#xff0c;只允许用户查看 、更新或删除特定的行数据。2 实例场景实例以医生只能看到治疗的病人&#xff0c;不能看其它医生的病人为例&#xff1a;1)医院病人的信息表pat_info&#xff1a;csdn> set search_…

Wi-Fi 与蜂窝网络(手机网络)的核心区别,以及 Wi-Fi 技术未来的发展方向

在日常生活中&#xff0c;我们既离不开家里的 Wi-Fi&#xff0c;也离不开手机的 4G/5G 网络。它们都能把我们连接到互联网&#xff0c;但底层的工作方式却大不相同。一、设计初衷的不同Wi-Fi诞生于 1997 年的 IEEE 802.11 标准&#xff0c;定位是局域网无线替代。它的目标是让电…