编号:583 作者:望山
发布于2023-05-21 07:25:50,编辑于2023-12-06 14:18:18


简介:
这个帖子依然是一个基础向的帖子,主要是通过简述老滚引擎的部分机制来讲述一些我们在安装模组以及游戏过程中的注意事项,纠正一些错误教程的带来的错误观点,比如:
https://www.bilibili.com/video/BV1FM4y1w77Y/?vd_source=22a734e2f11413748363f2e194cb73f4中让你没事拿出脚本清理工具“维护”存档(不要这样做,相信我)。
通过对老滚引擎的部分机制的介绍来帮助大家掌握“论esp转esl、代码跳任务、为什么不要在存档中开关mod、baseid与prid、存档脚本清理”这些游戏使用小技巧,并理解其原因。
在开始看这个教程时你需要先掌握:基础向-你在安装模组中应该掌握的最基础的实用小技能(如何使用正版本体、MO2功能与原理简介、手动排序、汉化、刷动作)中的“MO2原理与功能详解”的部分。
老滚引擎的id简述:
当我们打开mo时我们会发现右边有这样一个框,标记着每一种插件的数量:esm、esp、esl、esm+esl

如果你平时使用代码获取物品(如:player.additem f 99999)或者用sseedit时观察物品id就会发现

老滚的id是由8位16进制数组成的(16进制:逢16进1位,用A-F表示10到15),包括我们的存档也是如此

再详细观察这些id的结构我们会发现id组成为这两部分:
[2位数的排序序号(你在mo2插件上可以看见的mod索引号)]+[6位模组内序号(即FormID)]
比如黎明守卫dlc的内容id肯定为以下格式:
02xxxxxx
再比如你安装的某某模组排序为35,那插件内的id肯定为
35xxxxxx
那么这样就带来了一个问题,因为只有两位用来表示排序索引,因此老滚引擎插件支持的最大数就只有16x16即256个。也就是说理论上esp+esm最大只能有256个(实际上因为其他原因,只能有255个即00—FE)。那如果我有很多插件,比如很多补丁怎么办,那么就使用esl或espfe(标记为esl的esp)。
先来简述以下esl的原理,你仔细观察esl或者espfe,他们的序号都是FE:XXX。
因此,esl的原理就是在esp的基础上向那“6位模组内序号”借3位出来,用于作为新的索引,老滚选择的方法是从原来的序号中,选出最后一位FE(即十进制的254)最为esl的标记,然后再拿3位作为esl的内部序号,如FE:001,FE:00。因为这个原因,esl的数量就可以很多,理论上可以达到16x16x16即4096个。与之对应的,因为被借走了3位,esl的组内序号也就只剩下8-2-3即3位,这3位只能存储4096个FormID。而esp和esm可以存储5位的FormID(1048576个)。(实际情况更复杂,esl的ID最小地址其实是800即十位数的2048开始,因此ESL、ESPFE的非引用FormID数量上限是2048,注:非引用FormID即ESL中自带而非引用的其他插件中的那些东西)
最后区分一下FormID和Records(记录):
Record和FormID是Creation Kit中表示和识别游戏资源的两大基本概念。Record代表资源,FormID代表Record的ID。
在Creation Kit中:
Records(记录)是对游戏资源的抽象,它代表一个完整的游戏元素,如一个武器,一个NPC,一个CELL等等。每个记录都有一个FormID来唯一标识它。
FormID(形式ID)就是记录的ID号,它是一个4字节(8位)的16进制数,最大可以达到$FFFFFF(16777215)。每个新添加的记录都需要一个唯一的FormID来标识。
所以,简而言之:
Records 是游戏资源的抽象,代表一个具体的元素。
FormID 是Records的ID标识,用于唯一确定一个Record。
举例来说:
我们要添加一个新武器“铁剑”。
首先,我们需要创建一个WEAP(武器)类型的Record来表示这个武器。这个Record就代表这个“钢铁之剑”这个游戏元素。
然后,我们需要给这个Record分配一个唯一的FormID,比如$000ABCDE。
所以最终,我们有:
Record(“铁剑”,WEAP) with FormID $000ABCDE
这个Record包含这个新武器的所有数据,用FormID $000ABCDE唯一标识。
在游戏中,所有对“钢铁之剑”的引用,都是通过FormID $000ABCDE来找到对应的Record,然后获取其数据,如3D模型,伤害值,名称等信息。
esp转esl:
了解到上文的内容后,掌握esp转esl就会轻松很多,打开SSEedit(下载地址),这是一个轻量简单的老滚编辑器,可以帮助我们做一些小东西。
等待你的模组列表加载完了后,随便找一个插件,右击然后选择Apply Script....

找到这个脚本:“Find ESP plugins which could be turned into ESL”

这个脚本作用如下:
它会迭代所有加载的插件(除了主文件),检查哪些非ESL插件可以转换为ESL。
它有以下检查:
1. 插件中的记录数不能超过800 H (ESL的最大记录数) //注:还记得前文说esl的Formid不能超过800H吗?
2. 插件中的最大FormID不能超过FFF H (ESL允许的最大FormID)
3. 如果插件中有新的CELL记录,会产生警告,因为游戏bug会导致ESL插件被其他模组覆盖后CELL不工作。
如果插件通过这些检查,代码会输出消息提示这个插件可以通过在TES4头部添加ESL标记来转换为ESL。如果最大FormID超过$FFF,还需要先压缩FormID,然后再添加ESL标记。
点击OK后,脚本会为我们自动检查所有插件,然后右边的message就会像我一样,给出各种可能可以转的插件名和信息

大致为以下两类:
"Can be turned into ESL by adding ESL flag in TES4 header"
与
"Can be turned into ESL by compacting FormIDs first, then adding ESL flag in TES4 header"
前者是能直接转的,后者需要先压缩FormID再直接转
先讲后者,如图点击我鼠标所示的选项:

然后上面会说明哪些模组受到影响,如我的是REFR。

值得注意的是,当上面出现INFO和NPC时不能点击YES压缩(INFO和NPC记录包含动态数据,这些数据在游戏运行时会改变)
最后点击模组本身,在右边的Record Falgs里勾上esl

不过这种要压缩FormID的esp,不要转是别人master(前置)的那种,会导致后面esp的引用出错。
对“Can be turned into ESL by adding ESL flag in TES4 header”的插件,直接勾选上esl就行。
操作完以上步骤后,你的插件部分就处理完了,你的转esl基本上就完成了一半(对于很多模组来说,也就到此为止了,“Can be turned into ESL by adding ESL flag in TES4 header”的插件不用考虑这一步),但也许你的模组比较复杂,可能做完上面步骤还不够,需要进一步处理其他的非插件文件(我不建议新手搞这个,不过还是简单讲述一下方法),注意以下文件:
重新生成 FaceGen 数据:如果 Mod 包含 FaceGen 数据并且在转换过程中发生了变化(主要是你的FormID变化),您可能需要使用 Creation Kit 重新生成这些数据。打开 Creation Kit,加载您的插件,然后导航到“Actors”部分。对于每个受影响的角色,右键单击它们,然后选择“Export FaceGen Data”。这将重新生成与新 ESL 或 ESLFE 插件对应的 FaceGen 数据。
更新脚本引用:如果 Mod 的脚本涉及到 FormID 引用,那么在转换过程中,这些引用可能会发生变化。这种情况下,您需要手动更新这些脚本中的 FormID 引用,使其与新的 ESL 或 ESLFE 插件匹配。这可能需要一些 Papyrus 脚本语言的知识,并且在某些情况下,可能需要联系 Mod 作者以寻求帮助(这个一般就不是我们能考虑的了,要我说就别动这类模组)。
.dll 插件:如果 Mod 依赖于特定的 .dll 文件,那么这些文件可能需要针对新的 ESL 或 ESLFE 插件进行更新。通常,这需要 Mod 作者进行操作。如果您不确定 .dll 文件是否兼容,最好联系 Mod 作者以获取更多信息。但一般都是可以直接使用的,因为这些文件之所以需要被关注,本质还是FormID的变化,大多数dll文件不会涉及这些。
检查 DAR 和 SPID 配置:对于涉及 DAR 和 SPID 的 Mod,您需要确保配置文件正确指向新的 ESL 或 ESLFE 插件。通常,这些配置文件中的 FormID 需要与新的插件匹配。您可以使用 xEdit 等工具检查新的 FormID,并在配置文件中进行相应的更改。
SEQ 文件的处理:如果您的 Mod 包含 SEQ 文件,那么在转换过程中,您可能需要重新生成这些文件以确保正确处理。使用 Creation Kit 打开您的插件并保存,这将生成一个新的 SEQ 文件。确保将此新文件放在 Data\SEQ 文件夹中。(也可以在SSEedit找到插件,点击右键,选择“Other”选项,然后点击“Create SEQ File”)
代码跳任务:
几个控制台代码就能实现,跳过你出bug的某个任务阶段:
save fuclist 1
然后就会弹出一个文本框(你当前存档的txt格式),ctrl+F输入任务名查找,然后复制这一行最前面那段8位ID
回到游戏输入以下代码:
sqs //questID为任务ID
如:
sqs 00000001
控制台会返回你任务的各个阶段,每个阶段已经完成或触发的为1,未完成触发的为0
然后继续输入代码
SetStage //stage为任务阶段,questID为任务ID
如:
setstage 00000001 10
跳任务有以下几点注意事项:
- 不要跳过任务初始阶段。初始阶段通常会初始化任务变量和标志,如果跳过可能会导致后续任务逻辑出错。
- 不要跳过触发重要事件的阶段。某些阶段的完成会触发与任务相关的重要事件,如果跳过可能会导致事件无法触发。
- 跳过阶段时,理解各阶段的逻辑和变量变化。如果不明白阶段的具体逻辑,随意跳过可能会导致变量状态混乱,影响后续任务。
- 完成任务时,理解任务结束条件。如果条件不满足就强制完成,很可能会导致无法正确关闭与该任务相关的各种数据,形成“死任务”等bug。
- 避免在复杂逻辑或多任务交互的任务中随意跳阶段或完成任务。这类任务的变量和事件管理比较复杂,容易出错。
不能跳任务的几种常见情况:
- 触发关键事件的阶段。如初始化任务NPC,删除其他NPC等关键事件。
- 分支选择阶段。这类阶段根据条件会分支到不同的阶段,如果跳过将无法正确分支。
- 复杂逻辑管理阶段。一些阶段负责协调多个任务变量或事件,这类阶段不宜跳过。
- 变量初始化阶段。某些阶段负责初始化任务变量,如果跳过其他阶段可能会出现变量未定义等bug。
- 任务结束条件未满足。如果强制完成任务,很可能会留下未释放的资源或未关闭的任务数据等bug。
所以,总的来说,在不清楚任务具体逻辑和变量变化的情况下,不建议随意跳阶段或完成任务,以免引起任务bug。需要妥善考虑各个阶段的作用后才决定是否可以跳过某些阶段。(也即是说你最好是碰到了bug再跳,跳前存好存档)
为什么不要在存档中开关mod:
跳任务教程中,你如果打开了你的存档你就会发现,你的存档数据存入存档时每个id也是存入了你的排序号的,而增删模组会改变排序,并且你会发现几乎你的每个模组都会往你存档里塞东西.......机警的玩家一般会就此产生警惕,对模组增删更加谨慎。理论上,因为各种原因导致插件的排序变动都是能被游戏引擎检测并且重定位的(特指最原始的esp,即未esl标记过的esp),但是在模组环境下,不一定如此,比如某些dll文件会在存档中以原来的位置进行检测然后导致游戏出错。
这段内容出自其他帖子(https://www.afkmods.com/index.php?/topic/3676-skyrim-information-baked-into-saves/),我简单翻译一下:
以下内容是会存入你的存档的:
1、Papyrus脚本的属性。从游戏开始的那一刻起,和当一个新的带有脚本的mod被添加进游戏时时,这些就会被永久地储存在存档里面里面。脚本属性只能通过更新脚本强迫它们改变,就像非官方修复补丁用于追溯修复的那样。
2、由Papyrus属性指向的对象。这些对象永远不能被移动,即使是用脚本的命令。这些数据从游戏开始和/或添加新MOD的那一刻起就已经被存储进去了。大多数的尝试都会悄无声息地失败,而其他尝试则只会报错,说这些对象不能被移动。
3、强制指向的对象引用了任务的别名。这些对象按理不应该成为永久的储存对象,但往往会成为永久持续对象。
4、通过脚本对任何虚构的对象进行的修改。包括全局变量和任何的其他信息。这些修改在保存时被写成修改记录,只能用另一个脚本来逆转。
5、地图标记数据。具体来说,如果你改变了一个地图标记,删除了其中的名称,然后继续游戏,那么即使在MOD被删除后,地图标记也会永久地失去这些信息。
6、在你访问过的单元格中,havok 启用的物品的位置(Positions of havok enabled items in cells you've visited)。(前面那一句我个人也没有太看得懂,所以没翻译出来,但是可以结合后文理解)即使你在CK中移动它们,而且你自己也没有在游戏中动过它们。按理说应该会在CELL的下一个循环中刷新,但到目前为止,所有迹象表明它不会刷新。可移动的静态物体的位置在你第一次遇到它们之后就会永久储存。在这之前,它们会被刷新。
7、将一张床的所有权从无名改为一个派别似乎不会更新,而将它从无名氏改为一个特定的NPC似乎能正常工作。
8、众所周知,NPC的一下几个字段会被存储: Crime Faction(犯罪派别), Faction memberships(派系成员), Inventory items(库存物品), Morality (道德), the opposite gender animations flag(性别动画标志)。这些字段似乎只有在NPC在游戏过程中实际加载到内存中至少一次的情况下才会被存档记录。
9、NPC的脸部数据。这几乎是必定的,但通常情况下,如果你在玩游戏时遇到了NPC,那么之后对他们的面部数据所做的任何改变都将被忽略。
10、时间尺度的改变。你可以通过ESP对游戏的时间尺度进行一次性的改变,但在那之后,任何对时间尺度的改变都必须通过Papyrus或控制台进行,因为一旦做出改变,就会在保存中永久存在。
更多的数据将在发现后加入。
也就是说,存档中的很多内容都是一旦储存后就再也无法去除的东西,当你加载完模组后,很多东西就永远存进存档里无法改变了。有些模组作者会教你怎么中途卸载他们的模组,使之成为“clean save”,但是这种东西根本不存在。当你删除了一个模组(哪怕只是一个补丁)后,坏档就是必然的,这只是时间问题(只有些小错可能会长到你封档都未爆发出来)。
我在看一些朋友们的控制台信息时,经常能看到有些东西的最后编辑模组是:“undesigned .....(后面忘了)”,这种基本上都是中途取消模组带来的问题。
B站up遥望东南2018,因做视频存档与游戏存档未做区分,长期增删模组,最终几十小时的存档坏档,道心破碎隐退江湖,各位朋友,警钟长鸣🙏
baseid与prid:
没什么大用的小知识,这两个主要是用于输入代码作弊的,临时想到了就加了进来。
在Skyrim中,baseid和prid是两个常用的ID类型,它们有以下区别:
- baseid:是对象的模版ID,代表一个对象的原型。多个同类型的对象可以共享一个baseid。例如所有的钢剑可能有相同的baseid。
- prid:是对象的实例ID,代表场景中实际存在的一个对象。每个具体对象都有唯一的prid,即使是相同类型的对象也不同。例如场景中每一把钢剑都有自己唯一的prid。
- baseid在游戏资源中定义,prid在实际游戏过程中动态生成。baseid是固定的,而prid会根据对象实例化的顺序递增。
- 可以通过baseid找到对象的原型信息,如模型、纹理、属性等。而prid代表具体实例,关联了实例的动态信息,如位置、数量等。
- 对象被删除后prid会被回收重用,而baseid是永久的。
所以简单来说:
baseid代表对象类型,可以看作模版。prid代表具体对象实例,包含动态实例信息。baseid是固定的,prid是动态生成的。baseid关联对象原型,prid关联对象实例。
因此你在输入作弊代码时要生成一个物体时如"addition f 99999"时,输入的物品时baseid,而你在找游戏中已有物体时用prid,如"00114514.moveto player"
存档脚本清理:
如果是我,看完了前文,我就会得出存档脚本清理(Resaver )这个玩意没用结论。某些程度上来说也的确如此。如果你不中途增删模组(尤其是卸载),你压根用不上这个工具,这个工具只能帮你的存档“止血”,延长它坏档时间,却不能阻止坏档这事本身的发生。它无法真的处理坏档错误。
如果你一定要删除一个模组,记得存档,然后打开脚本清理工具,点击这个

然后把筛选出来的东西删除,可以考虑事先备份。
平时没有删除mod时不要去进行上述操作!不要听信什么没事拿出来维护存档之类的话并非出现了unattached instances就需要清理,很多脚本甚至就是靠这些东西来运行的,清理了容易出事。
最后记住:
永远不要使用快速存档,自动存档在高脚本负载情况下会产生不完整的存档(其实手动存档也会,只是自动存档更为严重)永远不要使用号称修复了快速存档的快速存档模组,因为无法修复。因此即便是手动存档,也尽量避免在大量脚本运行时(比如战斗中)存档。
结语:
非模组制作者,一家之言,如有错误还请各位大佬指出

感谢 @LuckYin
***
欢迎各位mod爱好者进群交流:891651174