AzerothCore-WoTLK 自定义 GM 指令实战:ChatCommand 框架完整拆解

发布时间:2026/9/19 19:41:09
AzerothCore-WoTLK 自定义 GM 指令实战:ChatCommand 框架完整拆解
AzerothCore-WoTLK 自定义 GM 指令实战ChatCommand 框架完整拆解【免费下载链接】azerothcore-wotlkComplete Open Source and Modular solution for MMO项目地址: https://gitcode.com/GitHub_Trending/az/azerothcore-wotlk给私服加一条默认命令表里没有的 GM 指令你得先想清楚三件事权限挂在哪一级、参数怎么从字符串变成强类型、新命令又该注册进哪张表。AzerothCore-WoTLK 的 ChatCommand 框架src/server/game/Chat/ChatCommands/就是为 GM 指令扩展准备的命令、权限、参数解析各归各位自定义命令开发不需要碰路由层。心智模型先建立直觉一张ChatCommandTable就是一棵平铺的命令树。每个条目要么指向一个处理函数附权限与是否允许控制台要么指向一张子表// [src/server/game/Chat/ChatCommands/ChatCommand.h](https://link.gitcode.com/i/600169f767a002d569503bfc11fed8ba) using ChatCommandTable std::vectorChatCommandBuilder; struct ChatCommandNode { // ... 省略 ... std::string _name; CommandInvoker _invoker; // 处理函数包装 CommandPermissions _permission; // 所需权限等级 是否允许控制台 std::mapstd::string_view, ChatCommandNode, StringCompareLessI_T _subCommands; };CommandScript的GetCommands()交出表LoadCommandMap()把它展开成ChatCommandNode树之后每次输入/xxx都走这棵树。跟着源码走一遍以/teleport name npc id 100为主线按事件发生顺序看它是怎么被执行的。玩家消息带着/前缀到达 src/server/game/Chat/Chat.cpp经ChatHandler转发给TryExecuteCommand。命令树由节点 map 构成_subCommands让路由天然支持任意层级// [ChatCommandNode](https://link.gitcode.com/i/600169f767a002d569503bfc11fed8ba) static bool TryExecuteCommand(ChatHandler handler, std::string_view cmd); std::mapstd::string_view, ChatCommandNode, StringCompareLessI_T _subCommands;路由就是逐级find先取第一个词查顶层表命中节点后若还有剩余参数就进_subCommands继续查直到命中叶子节点且参数恰好耗尽。命令树怎么来的cs_tele.cpp 把四层表嵌套起来// [cs_tele.cpp](https://link.gitcode.com/i/00624a43fcd6f27f3cc47d9e06b96d18) static ChatCommandTable teleCommandTable { { add, HandleTeleAddCommand, rbac::RBAC_PERM_COMMAND_TELE_ADD, Console::No }, { del, HandleTeleDelCommand, rbac::RBAC_PERM_COMMAND_TELE_DEL, Console::Yes }, { name, teleNameCommandTable }, { group, HandleTeleGroupCommand, rbac::RBAC_PERM_COMMAND_TELE_GROUP, Console::No }, { , HandleTeleCommand, rbac::RBAC_PERM_COMMAND_TELE, Console::No } };注意那个空串键teleport后面不跟任何词时落到HandleTeleCommand这就是框架支持的裸命令写法。命中叶子节点后CommandInvoker接管参数解析全程由模板元编程完成没有手写strtok// [CommandInvoker](https://link.gitcode.com/i/600169f767a002d569503bfc11fed8ba) using Tuple TupleTypeTypedHandler; Tuple arguments; std::get0(arguments) chatHandler; ChatCommandResult result ConsumeFromOffsetTuple, 1(arguments, chatHandler, argsStr); if (result) return std::apply(reinterpret_castTypedHandler*(handler), std::move(arguments));每个参数类型对应ArgInfoT特化逐个吃掉行首 token 并把剩余串传给下一个参数整行必须被吃干净否则判失败并回显用法。这就是处理函数签名即参数声明——类型写对解析自动完成。最后进处理函数本体Variant让同一个参数同时接受普通 ID 与超链接形式// [cs_tele.cpp](https://link.gitcode.com/i/00624a43fcd6f27f3cc47d9e06b96d18) static bool HandleTeleNameNpcIdCommand(ChatHandler* handler, PlayerIdentifier player, VariantHyperlinkcreature_entry, uint32 creatureId) { // ... 省略遍历 sObjectMgr-GetAllCreatureData() 找出生点 if (!spawnpoint) { handler-SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND); return false; } // ... 省略TeleportTo 到目标出生点 }PlayerIdentifier支持玩家名或 GUID 两种写法框架自动解析成同一类型返回值决定这条命令记不记成功。注册侧很轻。每个cs_*.cpp底部都有一个AddSC_*工厂函数new出的脚本实例在 CommandScript 构造函数 里自动登记// [CommandScript.cpp](https://link.gitcode.com/i/d6a80780efd6f405f5621a2744fbc804) CommandScript::CommandScript(char const* name) : ScriptObject(name) { ScriptRegistryCommandScript::AddScript(this); }启动时LoadCommandMap()遍历全部注册实例、合并各脚本的GetCommands()再叠加数据库command表的 help 与权限覆写命令树即告就绪。你自己动手从零到可运行克隆仓库到本地工作区git clone https://gitcode.com/GitHub_Trending/az/azerothcore-wotlk按 install.sh 完成环境安装与数据库初始化。在src/server/scripts/Commands/下规划一个新命令文件命名沿用cs_前缀阅读 cs_template.cpp 的骨架。写一个static bool处理函数第一参固定为ChatHandler*后面跟需要的参数类型uint32、float、std::string、PlayerIdentifier等均可。写CommandScript子类GetCommands()返回你的命令表权限用rbac::RBAC_PERM_*或SEC_*宏并指定Console::Yes/No。把该文件的AddSC_*登记进脚本加载列表src/server/scripts/ScriptScriptLoader.h重新编译 worldserver。验证用 GM 账号执行/help你的新命令应出现在列表再实际执行一次处理函数内用handler-PSendSysMessage(...)回一句提示收到即跑通权限不足的账号则应看不到该命令。你会踩的坑 怎么绕过去权限不生效/help里看不到命令多半是权限宏给低了——GM 的安全等级必须不低于命令要求。检查点/help列表里有没有它没有就是权限过滤掉了。命令根本没注册新文件写对了但执行提示未知命令通常是AddSC_*没进加载列表或文件没被编译进去。检查点在 src/server/scripts/ 下grep你的AddSC_函数名确认它在加载清单里。参数解析总报错框架要求整行参数被吃干净尾部多一个词就会失败Variant、OptionalT写反了顺序也会让提示变得莫名其妙。检查点对照处理函数签名逐字核对命令输入的参数顺序与个数。help 文案不显示/help 命令没输出说明构建条目时没带 help 字符串或忘了在数据库command表里覆写。检查点看command表里对应名字的行是否存在。往深了走进阶扩展点 在 ChatCommandArgs.h 里为新类型加ArgInfo特化让处理函数直接收强类型坐标、物品条目、公会名都可行。 通过GetAutoCompletionsForChatCommand.h接入 Tab 补全输入/tele时给出候选子命令。 文案统一走LANG_*宏Language.h多语言 help 与报错一条不改。 自定义逻辑挂在自己的CommandScript子类里按模块拆文件、互不干扰基类见 CommandScript.h。 回消息时用Hyperlink标签拼出可点击的 NPC/物品链接解析与发送两头都在 ChatCommandArgs.h 里。收尾资源与下一步命令树、路由与参数解析核心ChatCommand.h命令脚本注册基类CommandScript.h标准命令实现照抄结构cs_tele.cpp命令树不深参数解析不玄——动手写一条试试。【免费下载链接】azerothcore-wotlkComplete Open Source and Modular solution for MMO项目地址: https://gitcode.com/GitHub_Trending/az/azerothcore-wotlk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考