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 根目录自动发现 .venv 和 venv,优先检查 .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 异常契约,例如抛出 TypeError、ValueError 或 RuntimeError,而不是只打印错误后返回一个看似成功的值。

业务代码不应使用宽泛的 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 范围表达需求,避免依赖内部实现细节。

导航中的 maxSearchDistance 和 maxMoveDistance 有什么区别? ​

二者职责不同:

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

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

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

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

不要在上层用每帧手动推进控制器掩盖停顿。这会破坏正常 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 ... 更重要。