Skip to content

KBEngine Nex FAQ

本页回答使用 Nex 3.x 时最常见的设计和迁移问题。遇到具体启动或运行错误,请同时查看 常见错误

版本与兼容性

KBEngine Nex 与原版 KBEngine 是什么关系?

KBEngine Nex 是社区持续维护和现代化演进的 KBEngine 分支。它保留 Entity、Base/Cell/Client、EntityCall、Space、Witness 和 EntityDef 等核心编程模型,并升级了 Python、网络、数据库、构建系统、跨平台支持、测试和开发工具。

详见 关于 KBEngine Nex引擎介绍

为什么 Nex 3.x 切回 KBEngine 1.x 基线?

目的是让服务端、客户端 SDK、EntityDef 和已有 1.x Assets 使用一致的协议语义。早期 Nex 基于 2.x 分支继续开发,和大量仍使用 1.x 协议的项目、SDK 存在消息编号或数据布局差异。

Nex 3.x 从代码和协议基线解决这类混用问题,同时保留后续加入的性能、安全、数据库、平台和工具链能力。

原版 KBEngine 1.x Assets 可以直接迁移吗?

EntityDef 与脚本模型以 1.x 为基线,迁移成本显著低于跨协议分支迁移,但仍不能假设整个项目无需检查。至少应验证:

  • Python 3.7 到 3.12 的语法和第三方包兼容性;
  • 已废弃或行为调整的引擎 API;
  • 自定义 C++ 扩展的 Python ABI 和编译器 ABI;
  • 数据库驱动、认证方式与表结构同步;
  • 客户端 SDK 是否由当前 Assets 重新生成;
  • 配置中的 management token、网络接口和端口。

建议先复制数据库和 Assets,在隔离环境完成启动、登录、进 Space、RPC、写库、重连和关服回归,再替换正式环境。

早期 Nex 2.x 项目可以直接升级到 Nex 3.x 吗?

可以

修改哪些内容需要更新客户端 SDK?

下列客户端可见协议变化需要重新生成并发布 SDK:

  • 新增、删除或修改客户端可见属性;
  • 修改 ClientMethods;
  • 修改带 Exposed 的 BaseMethods 或 CellMethods;
  • 修改上述成员使用的数据类型、组件或协议 UType;
  • 增加会进入客户端协议的 Entity 或插件 EntityDef。

只修改纯服务端 Base/Cell 方法、内部属性或 Python 实现,不应改变客户端 EntityDef 摘要。详见 SDK 自动生成

为什么客户端仍然提示 EntityDef MD5 不一致?

说明客户端持有的可见协议与当前服务器不同。常见原因依次是:SDK 没有重新生成、客户端工程仍打包旧文件、连接到了另一套服务器、插件 EntityDef 发生变化,或显式 UType/类型定义不一致。

不要绕过摘要校验。应确认生成 SDK 时使用的 KBE_RES_PATH、Assets 和插件清单与目标服务器完全一致,再清理客户端构建缓存。

Python 与脚本

当前使用哪个 Python 版本?需要安装系统 Python 吗?

当前嵌入式运行时是 Python 3.12。服务端发布目录携带匹配的动态 Python 运行库,因此启动服务器不依赖系统 Python。

创建 VENV、安装第三方包和执行开发工具时仍需要可用的 Python/pip 工具。它们的主次版本必须与引擎的 Python 3.12 一致。

为什么全平台使用动态 Python?

动态运行时便于加载原生扩展,统一部署模型并减少引擎内静态 Python 与扩展模块之间的符号和运行库冲突。Windows 的 .pyd、Linux/macOS 的原生扩展都必须与 Python 3.12 ABI、目标架构和平台匹配。

发布时要保留可执行文件旁的 Python 动态库和标准库,不能只复制服务端可执行文件。

为什么 Debug 引擎也链接 Release Python?

Python 生态中的第三方二进制包通常只提供 Release ABI。Debug 引擎若强制链接 Python Debug ABI,会导致大量 .pyd 或原生扩展无法加载。

Nex 的 Debug/Release 引擎统一链接 Release Python。这不影响调试引擎 C++ 代码,但原生扩展本身仍需使用兼容的 C/C++ 运行库、架构和 Python 3.12 ABI。

VENV 文件夹必须叫 .venv 吗?

不是。当前引擎会在项目 Assets 根目录自动发现 .venvvenv,优先检查 .venv;也可以通过 KBE_VENV_PATH 显式指定 VENV 根目录或兼容的 site-packages 路径。

引擎会读取 pyvenv.cfg 校验 Python 主次版本。不是 Python 3.12 的环境会被忽略,以避免错误加载 cpXY 二进制扩展。详见 VENV 虚拟环境

VENV 中的包为什么导入失败?

依次检查:

  1. 启动日志中的 KBE_VENV_PATH 是否指向预期环境;
  2. pyvenv.cfg 是否声明 Python 3.12;
  3. 包是否安装到了该 VENV,而不是系统 Python;
  4. 二进制扩展的架构和 ABI 是否匹配;
  5. 包是否依赖发布目录中不存在的其他动态库。

纯 Python 包通常只涉及搜索路径,原生包还涉及系统动态加载器和 C/C++ ABI。

支持脚本热更新吗?

支持使用 KBEngine.reloadScript() 或配套工具触发逻辑脚本重载。热更新适合修正函数实现和部分运行逻辑,不等同于重新启动解释器或重建整个 EntityDef 系统。

修改 EntityDef 结构、属性类型、方法签名、插件清单、C++ 模块或进程级初始化逻辑后,应重启相关服务并按需重新生成客户端 SDK。详见 脚本热更新

支持 asyncio 吗?会不会脱离游戏 Tick?

支持。asyncio 事件循环由底层 Dispatcher 的定时任务推进,不需要额外的 Python 调度线程。

但协程回调最终仍在组件调度线程执行,不能理解为“不受 Tick 约束”。等待网络或定时事件可以让出执行权;CPU 密集循环、同步 IO 和一次处理过多结果仍会阻塞 BaseApp/CellApp Tick。详见 asyncio 支持

Python 异常会怎样影响引擎 API?

引擎 API 在参数、状态或生命周期不合法时会遵循 Python 异常契约,例如抛出 TypeErrorValueErrorRuntimeError,而不是只打印错误后返回一个看似成功的值。

业务代码不应使用宽泛的 except Exception: pass 吞掉错误。日志中的 traceback、Entity ID、组件和调用参数是定位 Python 到 C++ 数据转换问题的重要依据。

Entity、Space 与导航

Base、Cell 和 Client 逻辑分别放什么?

  • Base:账户、背包、社交、匹配、排行榜、持久化、客户端会话;
  • Cell:位置、移动、战斗、AI、AOI、触发器、导航和 Space 内交互;
  • Client:表现、输入、客户端 Entity 状态和服务端回调处理。

判断标准是数据生命周期和执行位置,不是文件数量。需要高频读取空间邻居的逻辑应靠近 Cell,需要长期保存和跨 Space 存在的状态通常放在 Base。

Proxy 只有 Base 部分吗?

不是。Proxy 是与客户端连接关联的特殊 Base Entity;当玩家进入 Space 时,同一个 Entity 可以创建 Cell 部分。它随后同时承担 Base、Cell 与客户端协议中的职责。

EntityCall 是可靠的本地对象引用吗?

不是。EntityCall 是远程对象引用,调用会经过序列化、网络和目标组件队列。目标 Entity 可能已经销毁、迁移或断线。

涉及重要状态变更时,应设计超时、幂等、结果确认和失败回收,不要假设远程调用立即完成,也不要无限期保存未经验证的 EntityCall。

Timer 可以承担保存、清理或关服状态推进吗?

Timer 可以触发普通业务任务,但不应成为唯一的持久化保证或关闭状态机。Entity 销毁、组件关闭、异常退出和 Tick 堵塞都可能让 Timer 无法按预期执行。

关键保存应接入明确的生命周期和回调;关闭流程应由组件状态推进并设置超时。Timer 更适合周期刷新、延迟行为和可重试业务,不适合承诺“必定执行一次”的语义。

DetailLevel 的 radius 是绝对距离吗?

Nex 3.x 的 DetailLevel radius 使用绝对距离语义。每一级阈值都直接表示与观察者的距离边界,便于阅读、配置和工具展示。

DetailLevel 只影响相应客户端可见属性的同步精度或策略,不替代 View/AOI 范围。配置时应保证各级距离有序,并结合真实玩家密度与网络包量测试。

witness_volatile_lod 应该在逻辑层使用吗?

它属于底层 Witness/易变属性同步策略,普通业务脚本通常不需要直接操作。逻辑层应通过 EntityDef 的同步标志、DetailLevel 和 View 范围表达需求,避免依赖内部实现细节。

导航中的 maxSearchDistancemaxMoveDistance 有什么区别?

二者职责不同:

  • maxSearchDistance 限制在目标附近寻找可用导航点的范围;
  • maxMoveDistance 限制本次导航控制器允许推进的总移动距离。

前者决定目标能否映射到导航网格,后者决定已经取得路径后最多移动多远。调用时应根据“容许目标偏离 navmesh 的范围”和“本次 AI 行为距离”分别配置。

导航到转角停顿或卡住怎样排查?

先确认服务端实际生成的路径点、当前位置和目标高度,再检查 navmesh 连通性、层、Agent 半径、转角精度、maxSearchDistancemaxMoveDistance 以及是否有业务反复创建和取消移动控制器。

不要在上层用每帧手动推进控制器掩盖停顿。这会破坏正常 Tick 调度和生命周期,容易造成重复移动或结束回调异常。详见 导航网格常见错误

数据库

支持哪些数据库?

当前支持 MySQL、MongoDB 和 PostgreSQL。MariaDB 可按 MySQL 协议评估,但驱动、认证和具体版本行为仍需由项目自行验证,不能把“协议兼容”视为所有版本无差异。

可以直接执行原生数据库命令吗?

可以使用相应原生命令接口处理 Entity 映射不适合表达的查询。默认配置包含危险命令限制,但这不是完整的权限系统。

生产环境仍应使用最小权限数据库账号、参数化查询、业务权限校验、超时和结果大小限制。高耗时命令会占用数据库任务资源并放大回调延迟。

异步写库是否意味着不会影响 Tick?

数据库执行不会直接占用 BaseApp/CellApp 等待 IO,但请求序列化、消息发送、DBMgr 排队、结果反序列化和脚本回调仍有成本。大量高频写库也会增加内存、网络和数据库 IO。

应合并可合并的状态、选择明确的保存时机,并监控任务队列和写入延迟。

构建与部署

支持哪些开发和运行平台?

项目使用 CMake、Ninja 和 vcpkg 支持 Windows、Linux、macOS,并覆盖 x64、ARM64 和 Apple Silicon 等构建环境。具体编译器与系统版本以当前 CI 配置和 安装与启动 为准。

通常使用 Windows/macOS 进行本地开发,Linux 作为正式服务端环境。正式选型仍需以项目自己的稳定性和压力测试为依据。

编译后的引擎目录可以整体移动吗?

可以,前提是完整移动发布目录。Windows 从可执行文件目录加载 Python DLL 等依赖;Linux 使用相对 $ORIGIN;macOS 使用 @loader_path。这些设置避免运行时依赖构建机绝对路径。

只复制单个可执行文件、删除 Python 标准库或漏掉第三方动态库,仍会导致启动失败。

为什么 vcpkg 要固定 baseline 和版本?

baseline 和 manifest 版本共同描述一组可复现依赖。固定它们可以减少开发机与 CI 因端口更新而得到不同库版本、补丁或 ABI 的风险。

升级依赖应作为一次明确变更处理:更新 baseline/版本后,清理受影响的二进制缓存,完成 Windows、Linux、macOS 构建与测试,再提交锁定结果。

配置不同环境的推荐方式是什么?

项目配置应只覆盖与默认值不同的部分,并使用 --prop--location 选择开发、测试、生产配置。数据库密码、management token 和证书不应硬编码进公开仓库。

详见 启动参数与多环境配置配置覆盖

management token 有什么用途?

它用于校验远程运行标志等特权管理请求,Machine 转发请求后,目标组件还会再次校验 token。

生产环境必须覆盖默认值,管理入口只允许受信网络访问。token 不替代网络隔离、操作审计和管理端身份体系。

--dev 模式为什么看不到 Bots 组件?

这是预期行为。Bots 是开发与压测工具,非开发模式下不应作为普通服务组件向 Machine 上报,避免生产组件列表和管理面暴露无关工具状态。

需要观察 Bots 时以开发模式启动,并结合自身日志和压测指标排查。

客户端与工具

SDK 生成器支持哪些目标?

当前 kbcmd --clientsdk 提供 C#、C++、TypeScript、GDScript 等生成目标。Unity、Godot、Cocos、LayaAir、Unreal 等客户端通常在对应基础 SDK 上集成。

生成命令、输出目录和客户端工程接入方式见 SDK 自动生成客户端入门

插件模块会加入 SDK 和客户端 MD5 吗?

会。启用插件提供的类型、Entity、组件和客户端可见方法会进入统一 EntityDef 协议表;SDK 生成器还会检查插件 Entity 是否完整加载,客户端摘要基于合并后的客户端可见协议生成。

因此调整插件清单、加载顺序或客户端可见定义后,也要重新生成 SDK。

SDK 事件系统中的 In 和 Out 是什么?

  • Out:SDK 向游戏层派发服务端事件,游戏层注册监听;暂停时可以进入 SDK 事件队列。
  • In:游戏层向 SDK 发起登录、移动等操作,由 SDK 处理并发送网络请求。

暂停 Out 事件不等于暂停底层网络或 In 操作。场景切换期间应明确哪些服务端事件可以延迟,避免恢复后一次性处理过多过期事件。详见 事件系统

遇到问题应该先收集什么?

至少保留:引擎 commit/version、操作系统与架构、构建配置、数据库版本、完整启动参数、相关组件从启动开始的日志、最小 EntityDef/脚本、客户端 SDK 摘要以及可复现步骤。

只截取最后一条错误往往会丢失真正的根因。组件启动失败时,第一个 ERROR 或 Python traceback 通常比后续的 finding ... 更重要。