VCMI 模组开发实战:用 wikiGlossary.json 为游戏内 Wiki 添加 Glossary 词条与 Markdown 百科页面

发布时间:2026/10/12 1:55:23
VCMI 模组开发实战:用 wikiGlossary.json 为游戏内 Wiki 添加 Glossary 词条与 Markdown 百科页面 游戏开发【免费下载链接】vcmiOpen-source engine for Heroes of Might and Magic III项目地址https://gitcode.com/gh_mirrors/vc/vcmi点击查看免费下载本指南面向 VCMIHeroes of Might and Magic III 的开源引擎模组作者讲解如何通过wikiGlossary.json为游戏内 Wiki 窗口Glossary 分类声明自由格式的百科词条并利用内置的 Markdown 渲染器编排标题、列表、图片、表格、动画、视频与交叉链接。读完本文你将掌握词条/分类的 JSON 声明格式、翻译键绑定、条目排序与 wiki 链接语法并能结合仓库源码理解其合并加载与运行时渲染机制。1. 背景游戏内 Wiki 窗口与 Glossary 分类VCMI 客户端内置一个 Wiki 窗口以三栏式布局展示百科内容分类列表 | 词条列表 | 内容区代码位于 client/windows/wiki/WikiWindow.cpp。窗口左侧的分类列除了内置分类glossary、town、hero、creature、artifact、spell、skill、terrain、mod见源码中的BUILTIN_CATEGORY_MAP还允许任何模组通过wikiGlossary.json声明额外的自定义分类并为内置 Glossary 分类补充自由格式词条且多个模组之间互不冲突、可以共存。Glossary 词条是“自由格式”的其正文不受固定字段约束而是由模组作者用 Markdown 子集编写渲染器将其转换为可滚动的图文混排页面见 client/windows/wiki/WikiMarkdown.h 中的buildMarkdownContent。Glossary 与自定义分类的词条使用同一套 Markdown 渲染管线。2. 文件位置与加载机制词条统一声明在模组的Content 目录下的固定路径mod_root/Content/config/wikiGlossary.json其中mod_root是模组根目录Content是该目录中会被挂载为虚拟文件系统根的文件夹。在 VCMI 的 mod 系统中模组根目录下的Content/对应虚拟路径/因此该文件在运行时以config/wikiGlossary.json这一虚拟路径被访问。运行时客户端通过JsonUtils::assembleFromFiles(config/wikiGlossary.json)一次性收集所有已激活模组提供的同名文件并做深合并源码见 client/windows/wiki/WikiWindow.cpp 与 lib/json/JsonUtils.cpp。assembleFromFiles遍历资源系统中所有匹配该路径的资源逐个解析 JSON 后调用merge合并。由于categories与entries都是 JSON 对象而非数组不同模组的同名 key 会按需合并或覆盖因此多模组可以安全地各自贡献词条。此外每个词条引用两个翻译键name与description这两个键必须存在于模组的翻译文件中例如config/translations/english.json。翻译文件的路径由模组的mod.json中translations字段声明参考核心模组 Mods/vcmi/mod.json 的写法多语言时可按语言代码分别声明加载逻辑见 lib/modding/CModHandler.cpp。3. wikiGlossary.json 完整格式{ categories: { mymod.mycategory: { name: mymod.mycategory.name } }, entries: { mymod.wiki.myentry: { name: mymod.wiki.myentry.name, description: mymod.wiki.myentry.description }, mymod.wiki.myentry.custom: { name: mymod.wiki.myentry.custom.name, description: mymod.wiki.myentry.custom.description, category: mymod.mycategory, order: 1 }, mymod.wiki.myentry.custom2: { name: mymod.wiki.myentry.custom2.name, description: mymod.wiki.myentry.custom2.description, category: mymod.mycategory, order: 2 } } }顶层只有两个可选/必选块categories可选与entries必选至少要有一个词条才有意义。3.1categories块可选声明出现在分类列中的额外 Wiki 标签页与内置标签页并列。每个 key 是该分类的唯一字符串 ID会用于 wiki 链接中且不得与内置保留 ID 冲突内置 IDglossary、town、hero、creature、artifact、spell、skill、terrain、mod。冲突时运行时会被记录为错误并跳过——源码中对应逻辑为 client/windows/wiki/WikiWindow.cpp 的logGlobal-error(...)分支。字段必填说明name是分类标签页标题对应的翻译键显示在分类列表中。自定义分类中的词条始终以 Markdown 渲染与 Glossary 使用同一渲染器。3.2entries块entries是JSON 对象不是数组。每个 key 是该词条的唯一标识符用于 wiki 链接中value 是包含下列字段的对象字段必填说明name是词条在左侧面板列表中显示的标题对应的翻译键。description是右侧内容区完整文章正文对应的翻译键。该值支持下文描述的 Markdown 语法。category否该词条所属分类的字符串 ID。缺省时默认为glossary。必须匹配categories中的某个 key 或glossary。order否控制词条在所属分类列表中的位置的整数。词条按order升序排列未写order的词条排在所有有序词条之后并在彼此之间按字母序排列。由于categories与entries都是 JSON 对象assembleFromFiles能正确合并所有激活模组的贡献。从源码看加载词条时先读取category字段缺省为glossary再通过customCategoryIds映射找到目标分类若引用了未知分类会被警告并放回 Glossary见 client/windows/wiki/WikiWindow.cpp 的logGlobal-warn(...)分支。3.3 条目排序规则Entry ordering:Glossary词条按显示名翻译后的name字母序排序order字段对内置 Glossary 分类无效。自定义分类词条按order整数排序省略order的词条被视为order为999999排在最后彼此之间按字母序。只要一个分类包含多于一个词条就强烈建议显式给出order值因为 JSON 对象在不同平台上不保证稳定的迭代顺序。源码实现印证了这一点Glossary 分类的词条在加载后被std::sort按a.name b.name排序而自定义分类的词条先按order缺省值 999999做std::stable_sort再插入见 client/windows/wiki/WikiWindow.cpp。3.4 链接到自定义分类词条自定义分类的链接格式如下其中 URI 的 category 部分就是该自定义分类的字符串 IDdisplay text运行时点击后handleWikiLink会解析wiki:前缀、按/切分分类与词条 ID、再按#切分锚点最后在BUILTIN_CATEGORY_MAP与customCategoryIds中查找到目标并导航见 client/windows/wiki/WikiWindow.cpp。4. description 的 Markdown 语法description的值是 JSON 字符串换行用\n表示。渲染器支持以下语法构造声明于 client/windows/wiki/WikiMarkdown.h 并实现在 client/windows/wiki/markdown 目录中。4.1 标题Headings# Heading level 1 ## Heading level 2 ### Heading level 3标题默认左对齐可用下方的对齐标签改变对齐方式。4.2 水平线Horizontal rule---一行内连续三个或更多-、_或*字符即可构成水平线。4.3 段落Paragraphs空行\n\n结束当前段落并开始新段落。4.4 列表Lists无序列表——以-或*加空格开头- First item\n- Second item有序列表——以整数、句点、空格开头如1.1. First step\n2. Second step4.5 对齐Alignment将对齐标签包裹一个或多个块级元素标题、图片、动画、视频即可控制其对齐方式开标签闭标签效果left/left左对齐。center/center居中对齐。right/right右对齐。对齐作用于开闭标签之间所有块级元素闭标签会将对齐重置为元素默认值。标题默认左对齐图片、动画、视频默认左对齐。4.6 图片、动画与视频Images / Animations / Videosalt text文件扩展名决定资源以何种方式加载扩展名渲染方式.png.pcx.bmp或任何非动画图片静态图片宽度超过视口时等比缩小。.def.json不带#N后缀动画所有帧以约 6 fps 循环播放。.def.json#N动画的第 N 帧静态显示。.bik.smk.webm.mp4循环视频过宽时自动缩小。资源系统在加载时会去掉扩展名因此CPRSMALL.DEF与CPRSMALL解析到同一资源但写 Markdown 时务必带上扩展名渲染器需要靠它判断媒体类型。若alt text非空右键点击图片、动画或视频会弹出 tooltip 显示该文本。示例Static image: Background Animation loop (all frames): Creature portraits Single animation frame: Portrait 0 Video (looped): Battle intro Centred animation: center Centred portrait /center Animation with right-click tooltip: This text appears on right-click4.7 表格Tables支持 GFM 风格的管道表格。第一行自动渲染为表头黄色、深色背景第二行必须是分隔行|---|---|| Column A | Column B | |----------|----------| | Cell text | More text |单元格内容可以是任意媒体语法| Creature | Icon | |----------|------| | Frame 0 | f0 | | Animated | loop |列宽平均分配文本单元格自动换行。4.8 VCMI 颜色标签所有文本段落、列表、表格单元格、标题都会经过 VCMI 的 label 渲染器因此{highlighted text}颜色标签处处可用The {Fire Wall} spell deals {direct damage}.4.9 链接LinksWiki 链接点击后跳转到另一词条渲染为蓝色下划线文本。文本链接display text可独占一行也可内联在段落中。图片链接被链接包裹的图片、动画或视频在左键点击时导航alt text右键点击图片链接仍照常显示 alt 文本 tooltip。分类与标识符对照表分类字符串内容glossary手工编写的 Glossary 词条creature生物列表spell法术列表hero英雄列表town城镇 / 阵营列表artifact宝物列表skill辅助技能列表terrain地形类型列表mod已安装模组Glossary 词条标识符——即wikiGlossary.json的entries对象中的 keyentries: { mymod.wiki.myfeature: { ... } } → wiki:glossary/mymod.wiki.myfeature游戏实体标识符——即实体经getJsonKey()返回的 JSON key。对核心内容通常就是未加作用域前缀的名字wiki:creature/imp (matches core:imp) wiki:spell/fireball wiki:skill/eagleEye带作用域形式core:imp与不带作用域形式imp都被接受。源码中内置分类生物、法术、英雄等的条目正是通过各实体的getJsonKey()生成标识符后填充进categoryEntries的例如 client/windows/wiki/WikiWindow.cpp。4.10 锚点Anchors不可见锚点标记页面内位置使链接能直接跳转到该位置。锚点本身从不渲染只记录其 Y 偏移。独立锚点——独占一行该行不能有其他内容a idmy-anchor /id与name属性均可。锚点名区分大小写推荐使用小写字母、数字与连字符。标题内嵌锚点——把锚点标签前缀或后缀在同一行 Markdown 里## a idmy-section /Section Title ## Section Titlea idmy-section /渲染标题前会剥离锚点标签可见标题文本不受影响。链接到锚点——在任意 wiki 链接的词条标识符后追加#anchornameJump to my section导航会先加载目标词条再把页面滚动到锚点位置。运行时锚点名称到 Y 偏移的映射由渲染器回填到glossaryAnchorMap随后scrollToY完成滚动见 client/windows/wiki/WikiWindow.cpp。5. 最小可运行示例config/wikiGlossary.json模组 Content 目录下{ entries: { mymod.wiki.myfeature: { name: mymod.wiki.myfeature.name, description: mymod.wiki.myfeature.description } } }config/translations/english.json模组翻译文件路径需在mod.json的translations字段中声明{ mymod.wiki.myfeature.name: My Feature, mymod.wiki.myfeature.description: ## Overview\n\nDescribe the feature here.\n\n---\n\n## Details\n\n- Point one\n- Point two }启用该模组后词条会出现在 Wiki 窗口的Glossary列表中按显示名首字母排序此例为字母M点击后右侧渲染出对应的 Markdown 正文。6. 进阶自定义分类 完整词条组合结合前面的完整 JSON 示例一个更实用的模组可以同时声明一个自定义分类和若干分类内词条并在词条正文中互相引用{ categories: { mymod.lore: { name: mymod.lore.name } }, entries: { mymod.lore.overview: { name: mymod.lore.overview.name, description: mymod.lore.overview.description, category: mymod.lore, order: 1 }, mymod.lore.history: { name: mymod.lore.history.name, description: mymod.lore.history.description, category: mymod.lore, order: 2 } } }正文示例注意\n换行、颜色标签、媒体与交叉链接混排## a idintro /序言 本条目属于 {自定义分类} 示例。 - 要点一 - 要点二 center Centred portrait /center | 章节 | 跳转 | |------|------| | 历史 | 前往历史 | 详细说明参见 Glossary 词条。7. 常见错误与注意事项保留 ID 冲突自定义分类不得使用内置分类 IDglossary、town、hero、creature、artifact、spell、skill、terrain、mod。冲突的分类会被跳过并在日志中输出错误。未知分类引用词条的category若既不是glossary也不是任何已注册的自定义分类会被警告并放回 Glossary。翻译键缺失每个词条必须同时提供name与description两个翻译键且要保证在模组翻译文件中存在缺失时词条可能显示为未翻译的 key 字符串。不支持的内联语法受 H3 位图字体限制渲染器不支持**bold**、*italic*、code、围栏代码块、 quote引用块、p与br标签遇到这些语法时只记录一次警告并尽量将内部文本渲染为普通段落见 client/windows/wiki/WikiMarkdown.h。排版请改用标题、水平线与空行分段。必须写文件扩展名媒体引用图片、动画、视频必须带扩展名渲染器依赖扩展名判断媒体类型。依赖稳定排序就写orderJSON 对象键序在不同平台不稳定自定义分类内多词条务必显式排序。8. 小结wikiGlossary.json是 VCMI 模组向游戏内 Wiki 贡献百科内容的统一入口categories声明自定义分类entries声明词条默认归入 Glossary两者都通过assembleFromFiles从所有激活模组合并天然支持多模组共存。词条正文由专用 Markdown 渲染器呈现支持标题、列表、对齐、静态图/动画/视频、表格、颜色标签、跨词条链接与页面内锚点。掌握这套声明与语法即可为模组的生物、法术、宝物、城镇乃至自定义世界观编写图文并茂的游戏内百科页面。更多细节可继续阅读仓库中的 docs/modders/Wiki_Glossary.md并对照 client/windows/wiki/WikiWindow.cpp 与 client/windows/wiki/WikiMarkdown.h 的实际实现。赞分享游戏开发【免费下载链接】vcmiOpen-source engine for Heroes of Might and Magic III项目地址https://gitcode.com/gh_mirrors/vc/vcmi点击查看免费下载相关推荐QtScrcpy 新手实用指南USB 或 Wi-Fi 把 Android 投屏到电脑键鼠控制一次搞定QtScrcpy 新手实用指南USB 或 Wi Fi 把 Android 投屏到电脑键鼠控制一次搞定 QtScrcpy 是一款基于 C 和 Qt 的 A桌面应用音视频VCMI Lua 脚本开发BonusDescriptor 完整指南——用 Lua 为部队与战场动态添加增益VCMI Lua 脚本开发BonusDescriptor 完整指南——用 Lua 为部队与战场动态添加增益 BonusDescriptor 是 VCMI 脚本游戏开发Playnite游戏库管理器指南整合20游戏平台与70种模拟器的统一界面Playnite游戏库管理器指南整合20游戏平台与70种模拟器的统一界面 Playnite是一款开源免费的游戏库管理器它把 Steam、Epic、GOG、桌面应用游戏开发上一篇CANN/pypto的relu函数API文档下一篇CANN反射填充2D反向传播算子创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询