跳转到内容

制作 Mod.zip

  • 给自己的mod命名
  • 以mod名字组织自己的mod
  • 编写mod的引导描述文件 boot.json 文件
  • 格式如下(样例 src/insertTools/MyMod/boot.json):
{
"name": "MyMod", // (必须存在) mod名字
"version": "1.0.0", // (必须存在) mod版本
"scriptFileList_inject_early": [ // (可选) 提前注入的 js 脚本 , 会在当前mod加载后立即插入到dom中由浏览器按照script的标注执行方式执行
"MyMod_script_inject_early_example.js"
],
"scriptFileList_earlyload": [ // (可选) 提前加载的 js 脚本 , 会在当前mod加载后,inject_early脚本全部插入完成后,由modloader执行并等待异步指令返回,可以在这里读取到未修改的Passage的内容
"MyMod_script_earlyload_example.js"
],
"scriptFileList_preload": [ // (可选) 预加载的 js 脚本文件 , 会在引擎初始化前、mod的数据文件全部加载并合并到html的tw-storydata中后,由modloader执行并等待异步指令返回, 可以在此处调用modloader的API读取最新的Passage数据并动态修改覆盖Passage的内容
"MyMod_script_preload_example.js" // 注意 scriptFileList_preload 文件有固定的格式,参见样例 src/insertTools/MyMod/MyMod_script_preload_example.js
],
"styleFileList": [ // (必须存在) css 样式文件
"MyMod_style_1.css",
"MyMod_style_2.css"
],
"scriptFileList": [ // (必须存在) js 脚本文件,这是游戏的一部分
"MyMod_script_1.js",
"MyMod_script_2.js"
],
"tweeFileList": [ // (必须存在) twee 剧本文件
"MyMod_Passage1.twee",
"MyMod_Passage2.twee"
],
"imgFileList": [ // (必须存在) 图片文件,尽可能不要用容易与文件中其他字符串混淆的文件路径,否则会意外破坏文件内容
"MyMod_Image/typeAImage/111.jpg",
"MyMod_Image/typeAImage/222.png",
"MyMod_Image/typeAImage/333.gif",
"MyMod_Image/typeBImage/111.jpg",
"MyMod_Image/typeBImage/222.png",
"MyMod_Image/typeBImage/333.gif"
],
"additionFile": [ // (必须存在) 附加文件列表,额外打包到zip中的文件,此列表中的文件不会被加载,仅作为附加文件存在。
// 请注意,这里的文件会以被当作文本文件以utf-8编码读取并保存
"readme.txt" // 第一个以readme(不区分大小写)开头的文件会被作为mod的说明文件,会在mod管理器中显示
],
"additionBinaryFile": [ // (可选) 附加二进制文件
"xxxx.zip" // 如果有需要附加的二进制文件,编写在这里时 `packModZip.ts` 会将其以二进制格式保存
],
"additionDir": [ // (可选) 附加文件夹
"xxxx" // 如果有需要附加的文件夹,编写在这里时 `packModZip.ts` 会将其下所有文件以二进制格式保存
],
"addonPlugin": [ // (可选) 依赖的插件列表,在此声明本mod依赖哪些插件,在此处声明后会调用对应的插件,不满足的依赖会在加载日志中产生警告
{ // 需要首先由提供插件的mod在EarlyLoad阶段注册插件,否则会找不到插件
"modName": "MyMod2", // 插件来自哪个mod
"addonName": "addon1", // 在那个mod中的插件名
"modVersion": "1.0.0", // 插件所在mod的版本
"params": [] // (可选) 插件参数
}
],
"dependenceInfo": [ // (可选) 依赖的mod列表,可以在此声明此mod依赖哪些前置mod,不满足的依赖会在加载日志中产生警告
{
"modName": "ModLoader DoL ImageLoaderHook", // 依赖的mod名字
"version": "^2.0.0" // 依赖的mod版本
// 对于版本号声明格式的简单说明:
// 版本号是以逗号为分隔的数字,比较时从左往右逐个逗号进行比较。
// 通常是3个数字组成,第一个数字表示大版本,出现破坏性(不向前兼容的)变更时数值加一,第二个数字表示小版本,有新功能时数值加一,第三个数字表示修订版本,修复bug时数值加一。
// "^"开头表示从此大版本开始到下一个大版本结束的范围,这是推荐的默认依赖写法。
// "="或不带任何前缀表示只依赖指定的版本号。
// "> < >= <="这种不等式写法符合对应的数学语义。
//
},
{
"modName": "ModLoaderGui",
"version": "^1.0.8" // 依赖的mod版本,使用(https://www.npmjs.com/package/semver)检查版本号,符合`语义化版本控制规范` (https://semver.org/lang/zh-CN/)
},
// 除了以上的方法可以声明对普通Mod的依赖,还有下面两个特殊的对 ModLoader 版本和 游戏版本 的依赖声明
{
"modName": "ModLoader", // 部分Mod可能需要依赖从特定ModLoader版本开始才添加进ModLoader的API,例如大部分AddonMod,可以像这样声明对ModLoader版本的依赖
"version": "^1.6.0"
},
{
"modName": "GameVersion", // 部分Mod只能在特定游戏版本下才能正常工作,可以像这样声明对游戏版本的依赖。特别注意这里以等号开头表示只匹配特定版本的游戏。此处比较时只会比较游戏的本体版本号,忽略第一个"-"开始的所有后缀。
"version": "=0.4.2.7"
}
]
}

最小 boot.json 文件样例:

{
"name": "EmptyMod",
"version": "1.0.0",
"styleFileList": [
],
"scriptFileList": [
],
"tweeFileList": [
],
"imgFileList": [
],
"additionFile": [
"readme.txt"
]
}

注意事项

  1. boot.json 文件内的路径都是相对路径,相对于zip文件根目录的路径。
  2. 图片文件的路径是相对于zip文件根目录的路径。
  3. 同一个mod内的文件名不能重复,也尽量不要和原游戏或其他mod重复。与原游戏重复的部分会覆盖游戏源文件。
  4. 具体的来说,mod会按照mod列表中的顺序加载,靠后的mod会覆盖靠前的mod的passage同名文件,mod之间的同名css/js文件会直接将内容concat到一起,故不会覆盖css/js等同名文件。
  5. 加载时首先计算mod之间的覆盖,(互相覆盖同名passage段落,将同名js/css连接在一起),然后将结果覆盖到原游戏中(覆盖原版游戏的同名passage/js/css)
  6. 当前版本的mod加载器的工作方式是直接将css/js/twee文件按照原版sc2的格式插入到html文件中。

对于一个想要修改passage的mod,有这么4个可以修改的地方

  1. scriptFileList_inject_early , 这个会在当前mod读取之后,“立即”插入到script脚本由浏览器按照script标签的标准执行,这里可以调用ModLoader的API,可以读取未经修改的SC2 data (包括原始的passage)
  2. scriptFileList_earlyload ,这个会在当前mod读取之后,inject_early 脚本插入完之后,由modloader执行并等待异步指令返回,这里可以调用ModLoader的API,可以执行异步操作,干一些远程加载之类的活,也可以在这里读取未经修改的SC2 data(包括原始的passage)
  3. tweeFileList ,这个是mod的主体,会在modloader读取所有mod之后,做【1 合并所有mod追加的数据,2 将合并结果覆盖到原始游戏】的过程应用修改到原始游戏SC2 data上
  4. scriptFileList_preload , 这个会在mod文件全部应用到SC2 data之后由modloader执行并等待异步操作返回,这里可以像earlyload一样做异步工作,也可以读取到mod应用之后的SC2 data

上面的步骤结束之后SC2引擎才会开始启动,读取SC2 data,然后开始游戏,整个步骤都是在加载屏幕(那个转圈圈)完成的。


另,由于SC2引擎本身会触发以下的一些事件,故可以使用jQuery监听这些事件来监测游戏的变化

// 游戏完全启动完毕
:storyready
// 一个新的 passage 上下文开始初始化
:passageinit
// 一个新的 passage 开始渲染
:passagestart
// 一个新的 passage 渲染结束
:passagerender
// 一个新的 passage 准备插入到HTML
:passagedisplay
// 一个新的 passage 已经处理结束
:passageend

可以以下方法监听jQuery事件

$(document).one(":storyready", () => {
// ....... 触发一次
});
$(document).on(":storyready", () => {
// ....... 触发多次
});