QUOTE(Wrye @ Jan 21 2007, 04:46 AM)

Dan: Ahh, okay. Formids and script variables are totally different problems. We've got formids pretty well figured out, and know how they get into scripts (not as variables by as constant references). The duplicate formids problem with Gecko is a technical issue with the way gecko handles merging in objects that seem to be modifying existing formids, but in fact are supposed to be new objects -- i.e., it's not an inherent problem with the engine, but a problem with gecko (inherited from tes4 plugin utility) and the merging process.
It's the variables for scripts that are the problem -- they don't have the protection against change that formids do. Or maybe they do -- maybe Ian can shed some light.
I'm still working on decoding how script variable changes are handled in the save file, so I can't be sure yet, but it would be consistent with everything I've seen so far if they didn't handle changes correctly. I've run some tests to see exactly what the runtime behavior is for overriding scripts:
First off, I added a quick command to OBSE to dump out the two variable lists for the current script when called, then made a simple esp that modified the AltarofAkatosh script so it would call the new command when activated. Activating the objects logs this:
CODE
script vars 1600B550
0: 00000000 00000000 00000000 (00000000) 00000002
1: 00000000 00000000 18A59028 (00000014 <no name>) 00000000
2: 00000000 00000000 0A001848 (0017720E <no name>) 00000000
3: 00000000 00000000 0E03094C (00064C9E Blessings of Akatosh) 00000000
event list 050979EC
0: 00000003 061AAA50 1.000000 3FF0000000000000
1: 00000001 061AAA38 10.000000 4024000000000000
2: 00000002 061AAA20 0.000000 0000000000000000
Script variables are defined in two tables: one stored on the script object that is shared between all instances of the script, and one stored on what I've called the "event list" above, but is really just per-instance data.
The first two columns in the "script vars" list are unk0 and unk1 in Script::RefVariable. My guess is that they would be used for storage of constant floating point values if the script compiler didn't support inline floats in the script format. Next is a pointer to a TESForm, and in parenthesis the form ID and full name of the form (if valid). Finally is the "varIdx" variable, which is a reference in to the event list table.
The first column in the "event list" table is 'id' in ScriptEventList::Var, the second is 'unk1', and the third and fourth are 'data', represented as first a double and then a UInt64.
To understand what's going on in the tables, it's important to note that the Oblivion script system refers to all variables and form IDs indirectly. The first table ("script vars") is a list of all of the 'ref' variables and form IDs in the script, and the second table ("event list") is a list of all the floating point variables, along with the storage for 'ref' variables. Entries in the first table that represent variables are redirected to the second table by setting the 'varIdx' variable to a non-zero value.
So, with this knowledge and a bit of guessing, we can determine what each entry in the lists is for:
script vars 0: redirects to event list ID 2, representing the "ref target" variable
script vars 1: constant form ID 00000014 (the player), representing the references to "player" in the script
script vars 2: constant form ID 0017720E, I didn't look this up but I'd assume it's the global FameAkatosh
script vars 3: constant form ID 00064C9E (Blessings of Akatosh), brought in by the "cast AltarAkatosh target" line
event list 0: data storage for "short doonce"
event list 1: data storage for "short DayofLastUse"
event list 2: data storage for "ref target"
Next I created another esp that replaced the entire script with:
CODE
ScriptName AltarofAkatosh
ref var0
ref var1
ref var2
short var3
short var4
short var5
Begin OnActivate
set var0 to player
set var1 to AbAncestorGuardian
set var2 to AbApplePoison
set var3 to 1
set var4 to 100
set var5 to 12345
dumpvarinfo
end
I added this to the plugin list after my original esp, and got this:
CODE
script vars
0: 00000000 00000000 00000000 (00000000) 00000004
1: 00000000 00000000 00000000 (00000000) 00000005
2: 00000000 00000000 00000000 (00000000) 00000006
3: 00000000 00000000 18A5BDB0 (00000014 <no name>) 00000000
4: 00000000 00000000 0E02E7F8 (000C6572 Ancestor Guardian Resistances) 00000000
5: 00000000 00000000 0E02C154 (00009617 Poisoned Apple Effect) 00000000
event list
0: 00000004 061AA8E8 0.000000 0000000000000014
1: 00000005 061AA8D0 0.000000 00000000000C6572
2: 00000006 061AA8B8 0.000000 0000000000009617
3: 00000007 061AA8A0 1.000000 3FF0000000000000
4: 00000008 061AA888 100.000000 4059000000000000
5: 00000009 061AA870 12345.000000 40C81C8000000000
The generated IDs for the script variables started after the IDs generated for the original script. This is good, and means that overriding a script from a master file works correctly. I then saved this game in to a new file. My guess is that the save game now contains data saying "variable 4 contains the data 0x0000000000000014" and etc. Next, I made another plugin swapping the type of the variables, but not the order:
CODE
ScriptName AltarofAkatosh
short var0
short var1
short var2
ref var3
ref var4
ref var5
Begin OnActivate
dumpvarinfo
end
Loading the game showed this list:
CODE
script vars
0: 00000000 00000000 00000000 (00000000) 00000007
1: 00000000 00000000 00000000 (00000000) 00000008
2: 00000000 00000000 00000000 (00000000) 00000009
event list
0: 00000004 061AA8D0 0.000000 0000000000000014
1: 00000005 061AA8B8 0.000000 00000000000C6572
2: 00000006 061AA8A0 0.000000 0000000000009617
3: 00000007 061AA888 1.000000 3FF0000000000000
4: 00000008 061AA870 100.000000 4059000000000000
5: 00000009 061AA858 12345.000000 40C81C8000000000
This list looks approximately the same as it did from the previous mod, but the variable types are now swapped, so the data is incorrect. Modifying the script so it changes the variable data proves this.
I believe that this is the root of the problem: modifying a script only allocates your new variables after the space allocated for the variables in the master file, and the save file only contains enough information to restore variable data by index, ignoring the type, name of the variable, and which mod it came from. It seems like the variables are allocated IDs in the order they're found in the file, so it may be possible to work around this via only appending variables and never changing existing the order of existing variables.
The crashes to desktop are probably caused when a float is replaced by a ref. Because Oblivion packs the form ID of a ref in to the lower bytes of the double, you'll get a completely random form ID, which probably won't resolve to a form, which results in a NULL TESForm * being passed back through the script command handler, which then probably crashes.
I'm going to try removing variables and a few other things to see what happens, but this post is already very long, so I'll end it here for now.