Jump to content
模组网
icedream

【Creation Kit 学习指南 36】存档说明

Recommended Posts

本章将详细讲解Papyrus脚本的游戏保存系统。此页上的信息将会随目标改变!已知问题和目标的修复和改变将会被标记。

何时可以存档?

游戏可以在任意时刻存档。这既适用于脚本中的多线任务,也适用于单线任务。在大多数情况下,你不必担心它,在你未改变任何东西的情况下,加载完毕的游戏将可以成功返回脚本并运行。但是如果你改变某些东西,那么本章将会予以具体讲解。

脚本

添加目标

如果你在存档建立后对一个目标添加脚本并保存游戏,那么当存档加载后此脚本将存在于目标之上,但是会原封不动(所有这些属性将设定它们的主文件值,只要存档完成加载,它们的初始化模块将会被运行)。

删除目标

如果在存档建立后从目标删除一个脚本,那么当存档加载后此脚本将持续存在于目标上。如果脚本被完全删除,那么可能会产生异常。

属性和脚本变量

添加

  • 有默认值的变量:当存档加载时,变量有默认值。(例如句法"int myVar = 5")
  • 无默认值的变量:当存档加载时,变量无默认值。(0,空字符串,空,假)
  • 自动属性:属性将收到由主文件给的值。(结尾为关键字"auto"的属性,例如:"ObjectReference Property MyObject Auto")
  • 非自动属性:属性将不会收到由主文件给的值,它将为空。
注意:由于显而易见的原因,如果当存档建立后目标初始化事件已运行,那么它不会再次运行。因此,如果对初始化事件设定一个新的变量,你不能肯定变量将会有一个适当值,除非你能确定目标从未在之前保存的游戏中存在过。

删除

如果你在存档建立后删除一个属性或变量,那么游戏存档中的属性或变量值将被丢弃,然后一个包含详细信息的警告将写入脚本日志。

改变

如果你改变游戏中的属性或变量,那么它将会先删除旧的再添加新的。如果你改变类别(并非名称),然后游戏存档中的任意值将被丢弃,然后包含详细信息的警告将被写入脚本日志。

改变主文件值

如果在主文件中有一个存在的属性并改变它的值,那么脚本将会收到一个存档中不存在的值。换句话说,改变值将不会写入游戏存档中已有的值。

属性范例

; Version 1
Scriptname MyScript Extends ObjectReference
 
int Property MyAutoValue Auto
 
int internalValue
int Property MyNonAutoValue
	Function Set(int value)
		internalValue = value
	EndFunction
	int Function Get()
		return internalValue
	EndFunction
EndProperty
 
int MyVariableWithInit = 1
int MyVariableWithoutInit
 
Event OnInit()
	MyVariableWithoutInit = 1
EndEvent
 
Event OnActivate(ObjectReference akActivator)
	Debug.Trace("MyAutoValue = " + MyAutoValue)
	Debug.Trace("MyNonAutoValue = " + MyNonAutoValue)
	Debug.Trace("MyVariableWithInit = " + MyVariableWithInit)
	Debug.Trace("MyVariableWithoutInit = " + MyVariableWithoutInit)
EndEvent
在主文件中:
  • MyAutoValue = 1
  • MyNonAutoValue = 1
在日志中,activation之后:

MyAutoValue = 1
MyNonAutoValue = 1
MyVariableWithInit = 1
MyVariableWithoutInit = 1
<save is made here>

; Version 2
Scriptname MyScript Extends ObjectReference
 
int Property MyAutoValue Auto
int Property MyAutoValue2 Auto
 
int internalValue
int Property MyNonAutoValue
	Function Set(int value)
		internalValue = value
	EndFunction
	int Function Get()
		return internalValue
	EndFunction
EndProperty
 
int internalValue2
int Property MyNonAutoValue2
	Function Set(int value)
		internalValue2 = value
	EndFunction
	int Function Get()
		return internalValue2
	EndFunction
EndProperty
 
int MyVariableWithInit = 2
int MyVariableWithoutInit
 
int MyVariableWithInit2 = 2
int MyVariableWithoutInit2
 
Event OnInit()
	MyVariableWithoutInit = 2
	MyVariableWithoutInit2 = 2
EndEvent
 
Event OnActivate(ObjectReference akActivator)
	Debug.Trace("MyAutoValue = " + MyAutoValue)
	Debug.Trace("MyNonAutoValue = " + MyNonAutoValue)
	Debug.Trace("MyVariableWithInit = " + MyVariableWithInit)
	Debug.Trace("MyVariableWithoutInit = " + MyVariableWithoutInit)
	Debug.Trace("MyAutoValue2 = " + MyAutoValue2)
	Debug.Trace("MyNonAutoValue2 = " + MyNonAutoValue2)
	Debug.Trace("MyVariableWithInit2 = " + MyVariableWithInit2)
	Debug.Trace("MyVariableWithoutInit2 = " + MyVariableWithoutInit2)
EndEvent
在主文件中:
  • MyAutoValue = 2
  • MyNonAutoValue = 2
  • MyAutoValue2 = 2
  • MyNonAutoValue2 = 2
在日志中,activation之后且加载先前存档:

<save is loaded here>
MyAutoValue = 1
MyNonAutoValue = 1
MyVariableWithInit = 1
MyVariableWithoutInit = 1
MyAutoValue2 = 2
MyNonAutoValue2 = 0
MyVariableWithInit2 = 2
MyVariableWithoutInit2 = 0
函数

注意

函数改变只会影响函数运行中建立的存档。然而,由于存档可以在任意时刻建立,因此这些接下来的点将会被写入。同样,假设在2010年11月29日之后建立并保存一个信息,那么一旦线程中的任意函数改变,早期建立和保存的存档(即使已加载和稍晚建立)将拒绝任何运行的堆栈。

添加

添加的新函数中没有任何问题。

删除

当存档建立后,如果在运行中删除一个函数,那么旧函数将从存档中加载并允许结束。警告将被写入脚本日志,大量对已删除函数的调用(经常由于一些其它改变或删除的函数调用它)将会失败。

改变

改变参数或返回类型

函数的差异将被注意,旧版本的函数将会从游戏存档中被加载并允许结束运行。大量对函数的调用将使用档案和零散文件中的版本,最有可能的问题错误是参数或返回类别的不匹配(经常由于一些其它改变或删除的函数调用它)。

添加/删除/改变函数变量

函数的差异将会被注意,旧版本的函数将从游戏存档中加载并允许结束运行。大量对函数的调用将使用存档/零散文件中的版本。

改变代码

函数的差异将会被注意,旧版本的函数将从游戏存档中加载并允许结束运行。大量对函数的调用将使用存档/零散文件中的版本。例外:如果一个本地函数被脚本化,堆栈将会被拒绝而非恢复。

函数范例

; Version 1
Scriptname MyScript extends ObjectReference
 
Event OnActivate(ObjectReference akActivator)
	MyFunction(1)
	MyFunction(2)
EndEvent
 
Function MyFunction(int aiMyValue)
	Debug.Trace("Entered my function version 1: aiMyValue = " + aiMyValue)
	; 存档*在此*建立
	Debug.Trace("Left my function version 1: aiMyValue = " + aiMyValue)
EndFunction


; Version 2 - 和version 1相同, 除非状态追踪
Scriptname MyScript extends ObjectReference
 
Event OnActivate(ObjectReference akActivator)
	MyFunction(1)
	MyFunction(2)
EndEvent
 
Function MyFunction(int aiMyValue)
	Debug.Trace("Entered my function version 2: aiMyValue = " + aiMyValue)
	; 存档*在此*建立
	Debug.Trace("Left my function version 2: aiMyValue = " + aiMyValue)
EndFunction


; Version 3
Scriptname MyScript extends ObjectReference
 
Event OnActivate(ObjectReference akActivator)
	Debug.Trace("OnActivate received!")
EndEvent
存档在调用version 1的OnActivate的MyFunction(1)运行期间建立。

保存之前的脚本日志:

Entered my function version 1: aiMyValue = 1
加载version 2后的脚本日志:

warning: Function MyScript..MyFunction in stack frame 2 in stack 457 differs from the in-game resource files - using version from save
...
Left my function version 1: aiMyValue = 1
Entered my function version 2: aiMyValue = 2
Left my function version 2: aiMyValue = 2
加载version 3后的脚本日志:

warning: Function Myscript..MyFunction in stack frame 2 in stack 457 doesn't exist in the in-game resource files - using version from save
warning: Function MyScript..OnActivate in stack frame 1 in stack 457 differs from the in-game resource files - using version from save
...
Left my function version 1: aiMyValue = 1
error: Method MyFunction not found on MyScript. Aborting call and returning None
... <later, after another activation>
OnActivate received!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...