BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。
模组:制作指南/APIs/Data
← 模组:目录
此数据接口使得您能够存储任何数据并在稍后取回它。例如,您可以使用此接口来存储玩家进度、游戏无法存档的自定义物品等。
存储选项
JSON文件
您可以将数据存储在模组文件夹的任意 .json 文件中。注意,如果玩家删除了这些文件(例如模组升级),相应数据就会丢失。因此主要使用此方法来存储打包文件、缓存文件等。
- 创建数据模型。
- 您可以在模组代码中使用相应的辅助类来读/写指定名称的文件。下面的例子假设您创建了一个名为 ModData 的类,但您也可以使用不同的名称:
// read file var model = this.Helper.Data.ReadJsonFile<ModData>("data.json") ?? new ModData(); // save file (if needed) this.Helper.Data.WriteJsonFile("data.json", model);
注意,如果文件不存在,ReadJsonFile 会返回 null。上面的例子中,如果返回 null,则创建一个默认实例。如果您不希望创建默认实例,只需删除
?? new ModData()
。
通过改变指定的文件路径,您可以:
- 将 JSON 文件存储在子文件夹中。这可以通过相对路径来实现(例如
"data/some-file.json"
)。如有需要,SMAPI 会自动创建子文件夹。 - 如需为每个存档创建独立的 JSON 文件,则可在文件名中添加存档ID,例如
$"data/{Constants.SaveFolderName}.json"
。
存储数据
您可以在当前存档文件中存储任意数据。这主要用于针对存档的数据,例如玩家进度和自定义物品。向存档存入数据会受到以下限制:存档文件必须已加载(例如,不能在标题界面写入存档数据)、农场帮手不能向存档中存入数据(可以用 Context.IsMainPlayer 判断是否为农场帮手)、当玩家没有存档便退出游戏时,所作的更改会丢失。如果需要在存档完成前写入数据,GameLoop.Saving 事件是一个好时机。
- 创建数据模型。
- 选择数据键。
- 在模组代码中,使用数据接口来读写具有指定名称的条目。下面的示例假定您的数据模型为 ModData,数据键为 example-key,但您可以使用其他的名称。
// read data var model = this.Helper.Data.ReadSaveData<ModData>("example-key"); // save data (if needed) this.Helper.Data.WriteSaveData("example-key", model);
注意如果数据不存在则 ReadSaveData 会返回 null。此外,ReadSaveData 作用域仅限于您的模组,因此不用加模组ID作为前缀。
全局应用数据
您可以在本地计算机上存储任意数据,如有需要,还可令 GOG/Steam 同步之。此方式存储的数据是全局的(而不是每个存档独立的),且会立即生效。
- 创建数据模型。
- 选择数据键。
- 在模组代码中,使用数据接口来读写具有指定名称的条目。下面的示例假定您的数据模型为 ModData,数据键为 example-key,但您可以使用其他的名称。
// read data var model = this.Helper.Data.ReadGlobalData<ModData>("example-key"); // save data (if needed) this.Helper.Data.WriteGlobalData("example-key", model);
注意如果数据不存在则 ReadGlobalData 会返回 null。
数据模型
创建数据模型
数据模型 是您创建的一个 C# 类,其中的属性就是您希望存储的数据。它既可以存储几个布尔字段,也可以存储复杂的对象图。下面是一个简单的数据模型:
public sealed class ModData
{
public bool ExampleBoolean { get; set; }
public int ExampleNumber { get; set; }
}
如果您将此模型存储到 JSON 文件,则后者会如下所示:
{
"ExampleBoolean": false,
"ExampleNumber": 0
}
只有公共的属性和字段会被序列化,且您的类需要一个无参数的构造函数。SMAPI 使用 NewtonSoft 来序列化这些模型,因此如果您需要更精细化地操控序列化,请使用 NewtonSoft 注释。
默认值
您可以酌情在数据模型种设置默认值:
class ModData
{
public bool ExampleBoolean { get; set; } = true;
public int ExampleNumber { get; set; } = 5;
}
也可通过构造函数设置默认值:
class ModData
{
public bool ExampleBoolean { get; set; }
public int ExampleNumber { get; set; }
public ModData()
{
this.ExampleBoolean = true;
this.ExampleNumber = 5;
}
}
数据键
数据键是您数据的表示,它使得您在稍后仍能访问相应数据。在您的模组中,不同数据键不应重名,但不同模组之间的数据键可以重名(SMAPI 内部会自动添加命名空间)。数据键只能包含字母、数字、下划线、连字符、英文句号。
删除
如果希望删除某个条目或文件,只需向数据模型传入 null
。这适用于任何 Write* 方法:
// delete entry (if present)
this.Helper.Data.WriteSaveData<DataModel>("example-key", null);
另请参阅
模组数据
您也可以向有 modData 字典字段的独立游戏实体存入自定义数据。这些实体包括 NPC 和玩家(Character)、GameLocation、Item 和 TerrainFeature。这种数据会被持久化存储到存档文件中并在多人游戏中被同步。
实用的说明:
- 为避免模组冲突,强烈建议您在数据字段前加上您的模组ID(参见下面的例子)。
- 当您拆分一个物品堆叠时,新的堆叠会复制原堆叠的 modData 字段;当把它合并到另一个物品堆叠时,它会使用目标堆叠的模组数据。除此之外,模组数据对于物品拆分/合并逻辑并无影响(例如,您可以堆叠模组数据不同的物品)。
下面的例子向一个物品写入自定义的“年龄”值,然后读取这个值:
// write a custom value
item.modData[$"{this.ModManifest.UniqueID}/item-age"] = "30";
// read it
if (item.modData.TryGetValue($"{this.ModManifest.UniqueID}/item-age", out string rawAge) && int.TryParse(rawAge, int age))
...