PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [Papyrus] Mod deinstallieren oder updaten



Boïndil
28.02.2012, 09:38
Hallo, Leute,
ich habe ja letzthin mitgekriegt, dass die Engine ein haarsträubendes Verhalten zeigt, wenn es darum geht, geänderten Code neu einzulesen oder Code zu entladen, den es nicht mehr gibt, weil der Mod deinstalliert wurde.
Wenn man in einem Mod den Event OnUpdate() verwendet, dann läuft der selbst dann weiter, wenn sämtliche Mod-Dateien gelöscht wurden. Man muss also nicht meinen, dass deinstallierte Mods keine Einflüsse mehr haben.
Mit einem sauberen Save kann man zumindest gewährleisten, dass Auto-Propertys neu eingelesen werden.
Wenn nämlich zwei Scripts aufeinander zugreifen und beim einen als Beispiel eine neue Property MessageX dazugekommen ist, dann kann es sein, dass MessageX.Show() nicht ausgeführt wird, d.h. keine Box angezeigt wird. Auto-Propertys werden im Spiel nur richtig eingelesen, wenn die Quest initialisiert wird und das wird sie nicht, wenn man einfach eine neue Property setzt. Kann sein, dass man das mit einem StopQuest(), StartQuest() oder so lösen könnte, aber damit man das tun kann, muss man wissen, wann es notwendig ist.

Da kommt jetzt mein Script ins Spiel:


int Property FxVersion auto
GlobalVariable Property DRWFxVersion Auto
bool updateLocked = false

; Dieser Block wird nur ein Mal beim Start der Quest ausgefuehrt.
; Variable FxVersion bei jedem Update erhoehen, begonnen ab 1
Event OnInit ()
FxVersion = 14
DRWFxVersion.SetValueInt(FxVersion)
; Andere Tasks
EndEvent

; Dieser Block wird bis ans Ende des Spiels ausgefuehrt, selbst wenn der Mod deinstalliert wurde, wenn man ihn nicht stoppt
Event OnUpdate()
If(!updateLocked)
If (DRWFxVersion.GetValueInt() == 0) ; Global-Variable existiert nicht = Mod wurde deinstalliert
updateLocked = true
UnregisterForUpdate()
Debug.Notification("Mod uninstalled.")
ElseIf (DRWFxVersion.GetValueInt() != 14) ; Nicht die selbe Version, updaten
DRWFxVersion.SetValueInt(14)
Debug.Notification("Mod updatet.")
ElseIf (DRWFxVersion.GetValueInt() == 13) ; Nicht die selbe Version, keine Reaktion gefordert
DRWFxVersion.SetValueInt(14)
Debug.Notification("Mod updatet.")
ElseIf (DRWFxVersion.GetValueInt() < 13) ; Nicht die selbe Version, Reaktion gefordert
updateLocked = true
UnregisterForUpdate()
Debug.Notification("Bitte einen sauberen Save machen.")
Else
DoSomethingBiiiiig()
EndIf
EndIf
EndEvent


Damit kann man gewährleisten, dass der Event gestopt wird, wenn der Mod nicht mehr existiert oder eine Reaktion auszulösen, wenn die Versionsnummer des letzten installierten Mods ein Update erfordert.
Habe es natürlich nicht gerne, wenn Leute meinen Mod deinstallieren, aber ich kann nicht damit leben, deren Speicher unnötig zu belasten oder ihr Spiel zu gefährden.

Grüsse
Boïndil

walli
28.02.2012, 11:04
Sehr mysteriös, wenn wirklich irgendwelche Scriptüberreste eigenständig im Save weiterlaufen kann das den Spielstand irgendwann mal schrotten. Ich glaube kaum daß es bis jetzt überhaupt jemand bemerkt hat wie irgendwelcher Code im Hintergrund weiterläuft aber wenn genug Mods ins Save gewandert sind ist irgendwann Ende.
Hoffentlich beschränkt sich das ganze auf das OnUpdate Event sonst wirds dreckig.
Könnte man nicht zumindest die Questproperties mit der reset Funtion beim Initialisieren der Quest cleanen? Auf jedenfall eine gute Lösung die du hier hast, sollte eigentlich idiotensicher sein für die Nutzer deines Mods, aber für Modder ist das ein dickes Fettnäpfchen.

Boïndil
28.02.2012, 13:45
Ich glaube, dass Referenzen auf Objekte das Spiel nicht gross belasten, aber Funktionen in Events, die alle paar Sekunden ablaufen eben schon.
Ich weiss nicht, ob dir das schon aufgefallen ist, aber es kann sein, dass mehrere Events des gleichen Scripts zeitgleich in verschiedenen Threads ablaufen. Wenn man das Intervall besonders klein hat und im OnUpdate Funktionen ablaufen, die Werte verändern, kann das problematisch werden.

Hier mein Event, das ich mit einer Variable isBusy versuche zu schützen, wobei UpdatePreset eine recht heftige Funktion ist, daüpr, dass sie alle paar Sekunden abläuft:

Event OnUpdate()
If(!isBusy && !updateLocked)
isBusy = true
If (DRWFxVersion.GetValueInt() == 0)
updateLocked = true
UnregisterForUpdate()
Debug.Notification("Mod uninstalled")
ElseIf (DRWFxVersion.GetValueInt() != 14) ; Not the same value as in OnInit() = not the same version
DRWFxVersion.SetValueInt(14)
Debug.Notification("Mod updatet")
Else
UpdatePreset(false)
isBusy = false
EndIf
EndIf
EndEvent