Help:Cargo/zh-hans

From Heroes of Might and Magic: Olden Era Official Wiki
Revision as of 04:43, 22 July 2026 by Zerodys (talk | contribs) (Created page with "{{Loc}} '''Cargo''' 是一个扩展,允许我们配置数据库表并在其中存储数据。[https://www.mediawiki.org/wiki/Extension:Cargo 在此处查看扩展文档]。在 HOMMOE 百科上,有数百个数据页面,定义了与各种 HOMMOE 游戏概念相关的 Cargo 表,包括单位、英雄、法术、阵营等。 百科上的每个页面都经过精心设计,通过数据页面来引用程序化的游戏内容。这有两个主要目的: * 百科的...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)


Cargo 是一个扩展,允许我们配置数据库表并在其中存储数据。在此处查看扩展文档。在 HOMMOE 百科上,有数百个数据页面,定义了与各种 HOMMOE 游戏概念相关的 Cargo 表,包括单位、英雄、法术、阵营等。

百科上的每个页面都经过精心设计,通过数据页面来引用程序化的游戏内容。这有两个主要目的:

  • 百科的其他语言版本无需重复管理共享游戏对象的属性和特征等繁琐工作。
  • 当发布补丁时,可以修改内部数据,所有引用该数据的页面将自动更新。

每次补丁的更新工作由 Obelisk Bot 处理;当发布新补丁时,百科维护者将运行机器人将新数据导入百科,之后可以逐个检查被修改的概念并手动更新,以修复过时的文章。

但所有这些都得益于 Cargo 的使用。

Cargo 表

数据库是一个花哨的词,简单说就是电子表格:"表"是指某人决定某些数据应该有"列",然后开始添加符合这些列的"行"数据。可以有许多表,每个表包含不同类型的数据,以及表与表之间的各种关系。其中比较著名的数据库引擎是 SQL,它位于运行本百科的软件核心,也是 Cargo 借以存储附加数据的基础。

要让 Cargo 表在百科上发挥作用,必须完成四件事:

  • 使用 #cargo_declare 定义一个表,在其中指定该表的用途,即决定该表有哪些列以及每个列的形状。
  • 使用 #cargo_store 填充表,用相关数据填入表中。
  • 使用 #cargo_query 从表中检索数据,从中提取有用信息。
  • 使用模板转换数据,以便于向用户展示。

每个 Cargo 命令的具体操作可能很复杂,但一旦建立起来,它就是一个强大的工具,可以生成各种有趣的显示和可视化辅助,而无需随着游戏变化手动维护它们。请参阅详尽的官方文档了解更多。

步骤 1:声明

定义 Cargo 表时,将为每个列指定一个名称供引用,并指定一个类型来限制它只能包含某些数据:例如,如果我们定义一列为整数,则之后如果试图放入数字以外的内容,操作将失败。

选择包含哪些列(以及省略哪些)与其说是科学,不如说是艺术,但系统是灵活的:如果我们之后决定需要添加或修改列,可以放心进行,因为百科上的所有数据定义都永久存储在文章中,一旦数据库重建将自动重新填充。(这个过程可能很慢,但很可靠。)

让我们查看 Faction 表作为参考:

{{#cargo_declare:_table=Faction
| id = String (allowed values=human,undead,dungeon,nature,demon,unfrozen)
| name = String
| desc = Wikitext


| icon = String
| icon_faction_laws = String


| biome = String
| resource = String


| name_sid = String
| desc_sid = String


| source_path = String
}}

这里有几个细节需要注意;首先,在 Cargo 命令中我们做的第一件事是决定我们引用的表名,在这个例子中是 Faction。与大多数 MediaWiki 概念不同,这些名称不能包含空格;事实上,在大多数(如果不是全部)Cargo 操作中都应避免使用空格。

这是一个相对简单的表,有少量开放式列定义了阵营的各种特征:对于最终用户来说,几乎所有相关内容是:名称、简要官方描述、所属生物群系以及主要资源。其他列供内部使用:代表它的图标名称、律法图标、内部定义它的游戏源文件路径,以及其名称和描述的 SID。

SID 是用于标记特定概念的内部名称,这些概念将被翻译成多种语言,它可能是"字符串标识符(String IDentifier)"的缩写。SID 将出现在我们的许多表中,因为大多数表都会有一行 Translation 表或专门的 XTranslation 表。无论哪种情况,特定概念(如阵营)的 SID 都将在这些其他行中具有相同 SID 的条目,这是其他语言百科可以用来轻松检索该概念本地化术语的方法,而无需自己重写整个内容。

在我们的所有表中,默认包含游戏内部件的英文名称和描述,以便提供回退方案。

你可能注意到 ID 使用的术语与发布版本游戏中的不尽相同,那是因为内部工作名称通常不值得在表面名称更改时冒着可能破坏游戏的风险去更新它们;俗话说,临时术语永远是最持久的。因此阵营内部称为"unfrozen"而不是 Schism,"human"而不是 Temple,等等。我们在这些 Cargo 表中使用的数据将主要使用这些内部术语,因为这使得补丁之间的更改更容易检测,因为我们不会在每个步骤都更改术语。

在确定了表中包含哪些列之后,我们将 #cargo_declare 定义包含在一个方便的文章中,它将在处理后生成一个我们可以交互的表。

步骤 2:存储

一旦有了一个可用的表,就该用数据填充它了。我们输入的每组数据称为"行",每个字段对应表中的一个列。并非所有列都是必需的,但我们仍必须确保数据符合表的预期。

表插入使用 #cargo_store 命令执行:

{{#cargo_store:
_table = Faction
| id = human
| name = Temple
| desc = The Church of the Sun strives to forge the best version of oneself. Its well‑rounded troops gain extra benefits from buffs.
| icon = fraction_human
| icon_faction_laws = Scroll_Faction_Human
| biome = Grass
| resource = gemstones
| name_sid = human_name
| desc_sid = human_desc
| source_path = DB/fractions/1_human.json
}}

这是一个对应于我们在上一节定义的 Faction 表的 #cargo_store。这里我们提供了表所期望的所有不同列,全部使用 Obelisk Bot 从游戏文件中自动提取。

但是呃哦,我们可以看到一个小拼写错误!"icon"字段被称为"fraction_human"!这肯定是个错误。但是,虽然看起来快速修复这个拼写错误很容易,但我们必须明确:

不要修复数据声明中的拼写错误

这不是百科上的拼写错误,这是游戏文件中的拼写错误。而且这是一个非常普遍的拼写错误!许多系统和子系统都期望这个拼写错误存在,如果你在这里修复它,你在后续导致意想不到的问题。例如,这个字段告诉我们稍后在别处查找名为"fraction_human"的图标。如果我们在这里修复了拼写错误,那么之后当我们尝试查询时,我们可能试图找到"faction_human.png"并因此找不到文件。

你可能认为,好吧,你将修复拼写错误并且修复文件名,虽然这可以暂时工作,但下次发布补丁我们使用 Obelisk 机器人重新导入数据时,你所有的辛勤工作都会崩溃。

所以不要这样做。

当 Obelisk 运行时,它会上传数百个数据文章,所有这些最终都会终止于一个或多个 #cargo_store 调用来填充我们的内部表。在大多数情况下,我们不需要干预这个过程(事实上,在 Obelisk 中修复 bug 比手动修改数据文章要好得多!)。

步骤 3:查询

现在我们得到了 Cargo 的真正力量。在数据被定义和存储之后,我们终于得到了经历所有这些麻烦的原因:现在我们查询数据,将其检索出来。

查询使用 #cargo_query 执行:

{{#cargo_query:
tables=table1=tableAlias1, table2=tablesAlias2, etc.
|join on=table1.fieldA = table2.fieldB,table2.fieldC=table3.fieldD, etc.
|fields=field1=fieldAlias1,field2=Alias2, etc.
|where=table1.fieldE='some value' AND/OR etc.
|group by=table1.fieldG
|having=table1.fieldG='some value', etc.
|order by=table2.fieldF, etc.
|limit=some number
|offset=some number
|intro=some text
|outro=some text
|default=some text
|more results text=some text
|no html
|max display chars=some number
|format=format
...additional format-based parameters
}}

如果这看起来有很多选项,那是因为这确实将许多不同的 SQL 操作编码到我们可以在百科上使用的模板中。举一个简单的例子,如果我们想获取所有存在的阵营列表,我们通常在 SQL 中这样做:

SELECT name
FROM Faction

也就是说,从 Faction 表中检索"name"列中的所有内容。这对很多事情都很有用,但真正的亮点在于限制返回的数据:

SELECT description
FROM Faction
WHERE id = 'human'

现在我们只检索与 WHERE 子句中条件匹配的每个阵营的描述,在本例中只获取 id 为'human'的阵营;没有 Hive 或 Schism 或其他。

我们可以编写与这两个 SQL 查询等效的 Cargo 查询:

{{#cargo_query:
tables=Faction=F
|fields=name
|format=list
}}

这里我们定义了表(Faction)和我们想要的字段(name),并告诉 Cargo 我们希望将这些名称以项目符号列表的形式返回。现在让我们做另一个:

{{#cargo_query:
tables=Faction=F
|fields=desc
|where=F.id='human'
|format=list
}}

在这个例子中,WHERE 简单地转换为'where'字段,其他都很直接。我们为 Faction 表指定了一个方便的别名"F",这样我们就可以在之后使用"F.id"而不必再次输入整个表名。在本例中它没有为我们节省多少空间,但如果要拉取 20 列,就会很快变得乏味。

cargo_query 提供了多种帮助我们显示信息的方法;如果你看之前的例子,你会发现引用"intro"和"outro"的字段,这些通常用于设置和结束表格。你也可以在"format"字段中指定结果应该传入另一个模板进行格式化。扩展文档可以帮助你了解可用的工具。这可能变得复杂,但幸运的是,我们可以解决"处理大量模板"的问题,答案是——你猜对了——更多模板!

步骤 4:转换

事实证明,以稳健的方式编写 #cargo_query 语句可能非常精确和耗时。所以像所有优秀的百科维护者一样,我们将把这个困难的任务打磨掉,制作出一个为我们完成大部分工作的模板。例如,我们可能会写一个 Faction 模板,可以这样调用:

{{Faction|lang=zh-hans|id=human}}

这个模板随后会获取它的两个参数(语言和要查询的 ID)并知道如何操作它们,将它们插入更复杂的 #cargo_query 中,这可能做的不仅仅是语言查询——例如,它可能自动查询要使用的图标,以便自动为我们生成类似"Schism"的输出。

这没有尽头。随着时间推移,我们将有模板调用模板调用模板,虽然这听起来很可怕,但实际上只是意味着我们正在利用软件为我们做大量工作。

你会在许多类似表格的 Cargo 模板中发现一种常见模式:

  • 一篇文章决定显示所有以"D"开头的单位列表
  • 该文章调用一个顶级概念简单的模板,如 UnitTable
  • UnitTable 定义自己的 #cargo_query,过滤掉不以"D"开头的单位,但输出被传送到 UnitTableRow 模板
  • UnitTableRow 知道如何获取 #cargo_query 的"fields"产生的所有数据,并将它们转换为一个格式良好的表格单行
  • UnitTable 将所有 UnitTableRow 条目夹在 #cargo_query 的"intro"和"outro"之间
  • 原始文章渲染出一个格式良好、精心设计的列表,只显示所有以"D"开头的单位

当然,从 Cargo 拉取的数据展示并不限于表格形式。文章信息框也会查询数据,拉取数十个字段并将它们排列成特定形式。天空是极限。