So... how do I publish an update for this thing and not brea

Post » Fri Nov 16, 2012 6:57 pm

So, I'm working on Frostfall again, and the problem that's cropping up in my head is how to properly update my mod (which is very script-centric) without breaking everyone's games or causing undesirable behavior. I have read several topics on the subject of how scripts "stick" in people's save games with no good method of user removal, but every time I've stepped away from these threads I've left more confused than informed as to how to apply what I've read. I think I need more specific guidance. Help me keep things clean for all (or most) users!

Here is the general structure of my mod. Quests are in Green, Aliases are in Yellow, scripts are in Blue.

Quest _DE_Main_1_6: Never runs. Is set to stage 10 to begin the mod's functionality.
Script _DE_EPMonitor_1_6 extends Quest: Attached to _DE_Main_1_6. Runs the whole show. Has continuously running RegisterForSingleUpdate(). Accesses other script's properties to gather information.

Alias DE_Player: Filled by the Player reference. Attached to _DE_Main_1_6. Has several scripts attached:
Script _DE_ClothingMonitor_1_6 extends ReferenceAlias: Monitors all armor / clothing equip / unequip events. Runs "on demand" only when an OnObjectEquip() event is sent by DE_Player.
Script _DE_CookingPot_MISC_Script extends ReferenceAlias: Watches for OnItemRemoved() event from DE_Player to swap a MiscItem cooking pot item for the furniture variant. Runs "on demand".
Script _DE_FoodDetect extends ReferenceAlias: Watches for OnObjectEquipped() events sent by DE_Player to detect when foods have been eaten. Runs "on demand".
Script _DE_WoodHarvestScript extends ReferenceAlias: Watches for an OnObjectEquipped() event from DE_Player when a Woodcutter's Axe has been equipped. Runs "on demand".

Quest _DE_PackageQuest: Never runs. Holds aliases filled by the player with certain AI packages attached, for driving the player with AI packages. In the current form, there is only a single alias attached:
Alias _DE_WoodHarvestingAlias: filled by the Player; has a single AI package attached, used for a Wood Harvesting cutscene when chopping wood. (Player paths from point A to B ).

Quest _DE_TrackingQuest: Starts game enabled. Contains quest objectives directing player to go to an Inn to find a book in an Inn, which sets _DE_Main_1_6's stage to 10, which causes _DE_Main_1_6's logic to start firing. Has two papyrus fragments attached that SetObjectiveDisplayed() and SetObjectiveCompleted().

I hope this is enough of an overview for someone to be able to tell me what the best way to update this mod for my users would be. I publish on Skyrim Nexus in a BSA-archived version as well as a "No BSA" version with all loose files. I also publish on Steam Workshop (which is BSA-archived regardless).

In the past, when I made a change to _DE_EPMonitor_1_6, it resulted in several duplicate versions of the script firing when someone upgraded the mod when loading an existing save game. The solution was to duplicate the quest that it was attached to (_DE_Main_1_6) and delete the old one. I don't know if this trick still works or if this is even the desirable thing to do.

Thank you very much for any insight and reading the multi-colored mess I just posted up above.
User avatar
He got the
 
Posts: 3399
Joined: Sat Nov 17, 2007 12:19 pm

Post » Fri Nov 16, 2012 5:16 pm

If it wasn't for the Steam Workshop bit, the quick-and-dirty answer would be to make an uninstaller ESP that calls all the same variables and scripts, but just ends the scripts one after another.
User avatar
Stephy Beck
 
Posts: 3492
Joined: Mon Apr 16, 2007 12:33 pm

Post » Fri Nov 16, 2012 9:02 am

For the sake of argument let's assume that I completely don't care about Steam Workshop and am thinking about not continuing to support it going forward.

By "ends the scripts one after another", do you mean unregisters for subscribed events? Would these be scripts with the exact same name as existing scripts, or...?

The only script that runs on an OnUpdate basis is _DE_EPMonitor_1_6. I currently have a built-in way to shut the mod down in-game, but it doesn't force the RegisterForSingleUpdate() to stop being called; it just sets a bShutdown bool variable to True, which causes all of the main logic to be skipped (the main function is never called). The OnUpdate() event, however, keeps firing, waiting until such time that bShutdown is no longer True.
User avatar
SUck MYdIck
 
Posts: 3378
Joined: Fri Nov 30, 2007 6:43 am

Post » Fri Nov 16, 2012 9:25 am

Ah. Well, all I know is vague theory; if you want specifics about that method, I haven't had to do it myself yet. http://www.gamesas.com/user/581287-thomas-kaira/ seemed to have a good grasp of the whole system and its issues, should memory serve, and http://www.gamesas.com/user/766649-amethyst-deceiver/ also regularly has weighed in on the matter.
User avatar
cheryl wright
 
Posts: 3382
Joined: Sat Nov 25, 2006 4:43 am

Post » Fri Nov 16, 2012 9:20 pm

Thanks. I'll direct them to this thread.
User avatar
El Khatiri
 
Posts: 3568
Joined: Sat Sep 01, 2007 2:43 am

Post » Fri Nov 16, 2012 11:09 am

Don't know how much of this is fact... It's what I've gleaned from reading...

It depends on how much of the old scripts are used in the updates I think.
If your update uses the same varables and properties, you could simply include a new quest in the update the stops and restarts all the quests so the newer scripts run instead of the older.
If your update doesn't use the same variables and properties, your unistall esp needs to stop all of your quests, unregister all calls for an update, and clear any properties not used in your updated esp. A clean save may be required.
User avatar
Dominic Vaughan
 
Posts: 3531
Joined: Mon May 14, 2007 1:47 pm

Post » Fri Nov 16, 2012 11:16 pm

Don't know how much of this is fact... It's what I've gleaned from reading...

As noted, most of these quests never actually run. Scripts attached to quests that aren't running still fire. Most notably, _DE_EPMonitor_1_6 attached to _DE_Main_1_6. So there's nothing to shut down.
User avatar
Racheal Robertson
 
Posts: 3370
Joined: Thu Aug 16, 2007 6:03 pm

Post » Fri Nov 16, 2012 10:59 pm

I've heard conflicting reports on the utility of clean saves, and I have to say, any mods I installed that suggested I use a Clean Save seemed to give me more trouble when I did than when I just plunked it in. Note that those didn't use uninstallers though.
User avatar
Ricky Rayner
 
Posts: 3339
Joined: Fri Jul 13, 2007 2:13 am

Post » Fri Nov 16, 2012 9:17 pm

As noted, most of these quests never actually run. Scripts attached to quests that aren't running still fire. Most notably, _DE_EPMonitor_1_6 attached to _DE_Main_1_6. So there's nothing to shut down.
If the scripts are attached to the quests that "don't run", how do the scripts fire? Are they flagged as Start Game Enabled? If so, they are running even though you think they aren't.
If the scripts are simply function holders, I don't think you would need to do anything but use the method below:
Build your unistall scripts with the same script names completely empty except for simply unregistering and clearing properties.
User avatar
Alberto Aguilera
 
Posts: 3472
Joined: Wed Aug 29, 2007 12:42 am

Post » Fri Nov 16, 2012 11:48 pm

Chesko, I've put quite a bit of effort in to this issue and did have problems after my first update to ScenicCarriages.

The problem I found is that scripts don't update if they are currently running... but no errors are thrown until AFTER the fact (and in the log file.) So basically you need to have a way to stop your scripts from updating. I thought it was Frostfall that had a "Shutdown" option in the config? My current version has steps to stop the quests, but my next version has a "Shutdown" in the config to make it easier. On another mod I am making, I am including a check condition to stop calling RegisterForSingleUpdate in the OnUpdate event to effectively shut down the script when needed.

The other issue is property changes, but I have yet to have any real problems with these, they just show up in the log file but will go away after another save. But, just in case, I am trying to be careful here and minimize any changes. I've read other people keep the old property just to be sure. (I haven't actually had any property changes since my last update so not sure the best route here.)

And, btw, I don't think you need to have a seperate esp and empty script files. I think those are for situations where a mod is uninstalled, but still left running. From what I see, a clean upgrade and a uninstall are basically the same. You need to stop all the scripts for both a Clean Uninstall and/or to Upgrade the scripts.
User avatar
Chris Jones
 
Posts: 3435
Joined: Wed May 09, 2007 3:11 am

Post » Fri Nov 16, 2012 6:54 pm

Clean saves are useless for getting rid of scripts now. They work for resetting game objects, but scripts remain in your save exactly as they were left when the mod was uninstalled indefinitely, and nothing you do can change that. This is why I feel it is very important that scripted mods be able to handle file updates on their own.

Here are a few things I do to keep updates clean and error-free:
  • Never, ever delete Properties if you plan on keeping the script. If I plan on deprecating a property, I move it into a special section down at the very bottom of my script that very clearly notifies me that the property is no longer being used. I can bring it back if I want, but the point is I do not remove it altogether. The only time this is okay is when the script itself is being removed.
  • If I am deprecating an entire script, first thing I do is make sure it gets unregistered for updates if need be (I'd advise changing that bShutdown section of the script to actually call an UnregisterForUpdate() if you plan on replacing it with a new script, just to be safe). Afterwards, don't remove the script from the resources altogether. Papyrus will complain about this every time you load a game if you do. What you can do, though, is detach the script from whatever you were using it on and delete every line of code except for the scriptname segment. Keeps Papyrus from complaining, and keeps the old, unwanted script from running anymore. Just make sure you properly shut the script down before you do this. Don't do this unless absolutely necessary, though, because you will end up packaging junk files. This is why I try very hard to preserve what I have by the following:
  • One of my preferred methods of updating is to use a version controller which operates on this simple fact: AutoReadOnly properties do not get saved. So, I create an AutoReadOnly property containing my mod's version number, and every time I need to make some changes to the internal operation of the mod, I change this number, which triggers the script to run the function that does what I need done. It could be shutting down and cleaning up old scripts, or redoing previous setup operations because I've changed something, to starting new scripts.
  • I don't use OnInit() because the only way to get OnInit() to fire again post-installation is to call Stop() on the quest, which terminates everything tied to it. I prefer to use Papyrus fragments. Also, unless you flag your quest to Run Once, OnInit() blocks on quest scripts fire twice. Using fragments to perform your needed operations is cleaner, and doesn't require you to nuke your quest to run them again. Just check the Allow Repeat Stages flag, and every time you want to redo that initialization call, just reset the quest stage and the Fragment will re-fire.
  • Finally, I never isolate my Quest scripts, they are all in communication with each other in some form. Scripts being able to interact with other scripts is one of those things I really like about Papyrus, especially for updating, because it allows me to contain all of my initialization stuff in an initialization block (or script), which then tells the other scripts what I want them to do when I want them to do it. This "Hive Mind" style is very, very useful, because it makes the entire update process so much easier than if your scripts are lone wolves.
Let me know if you have any questions about the above.
User avatar
Kelly Osbourne Kelly
 
Posts: 3426
Joined: Sun Nov 05, 2006 6:56 pm

Post » Fri Nov 16, 2012 7:57 pm

If the scripts are attached to the quests that "don't run", how do the scripts fire? Are they flagged as Start Game Enabled? If so, they are running even though you think they aren't.
They are not Start Game Enabled. Scripts attached to quests that aren't running still fire their OnInit() block. Try it. I never start the quest (via Start Game Enabled or otherwise) because when I did so, I would get duplicate OnUpdate() events for attached scripts. Never starting the quest in the first place solved this problem.

Here are a few things I do to keep updates clean and error-free:

Thank you for all of this. I do have a couple of questions:
  • Never, ever delete Properties if you plan on keeping the script. If I plan on deprecating a property, I move it into a special section down at the very bottom of my script that very clearly notifies me that the property is no longer being used. I can bring it back if I want, but the point is I do not remove it altogether. The only time this is okay is when the script itself is being removed. What if the object that the property was resolved to no longer exists?
  • If I am deprecating an entire script, first thing I do is make sure it gets unregistered for updates if need be (I'd advise changing that bShutdown section of the script to actually call an UnregisterForUpdate() if you plan on replacing it with a new script, just to be safe). I am using RegisterForSingleUpdate(), so I will need to put some logic in place that avoids calling the RegisterForSingleUpdate() at the end of the OnUpdate() block.
  • One of my preferred methods of updating is to use a version controller which operates on this simple fact: AutoReadOnly properties do not get saved. So, I create an AutoReadOnly property containing my mod's version number, and every time I need to make some changes to the internal operation of the mod, I change this number, which triggers the script to run the function that does what I need done. Could you explain this? How does changing this number "trigger" a script to run a function? What function?
  • This "Hive Mind" style is very, very useful, because it makes the entire update process so much easier than if your scripts are lone wolves. Do you have a preferred method of "pushing" data to another script? Or do you usually set properties on your initialization script that your other scripts read at the appropriate time and take action?
Thanks!

Edit: Is there an exact condition that causes a duplicate version of a script to be fired? And assuming that updating my script doesn't cause a duplicate script issue, if I update a script that is in the middle of execution (via OnUpdate or otherwise), what is the order of operation? Does the old version of the script completely execute one update, and then on the next update the new one fires? What exactly happens here?
User avatar
sw1ss
 
Posts: 3461
Joined: Wed Nov 28, 2007 8:02 pm

Post » Fri Nov 16, 2012 6:46 pm

im actually currently in the same boat. i am overhauling my first mod (which was made while i was learning papyrus and the whole thing written and structured very poorly and in desperate need of an overhaul). my mod will likely end up with a lot of junk that i will be forced to continue packaging with the mod due to the permanence of script embedding in save games. thomas has covered pretty much everything above, but there are a few things i have noticed in addition.

if your deprecated quest had dialogue and you are using TIF topic info fragments, you can safely delete the topics as well as all of the TIF fragments without embedded errors. the save game will update and no longer associate those fragments with the quest (and can be deleted entirely without problems).

regarding deprecated properties. it is possible to remove these from the save game. the only way i know of to do it safely is to clear its value in the properties window and save those changes into the esp file (will be located in the VMAD subrecord of the form). forever error-ing properties are the result of uncleared property values still in the VMAD record. once this is cleared, the next time you load your save, you will get errors due to missing properties, but a subsequent save will ignore those property errors going forward (successfully erased the properties from the save game)

one sure-fire way to kill property errors would be to detatch the script entirely from the form, save and close out the edit windows (all of them), then re-open the edit window and re-attach forms and re-fill properties. this will create a brand new VMAD record from scratch. your save game will sync with this record on the subsequent save and no errors will be puked into the logs.

lastly, when you include a permanent uninstaller for your mod for users who no longer wish to use it anymore, you will need to pack your scripts loose (not a bsa) that the user must leave in their scripts folder permanently for as long as they use that save game (again, you can skip all the TIF fragments if you have them, so long as you delete the topics from your quest dialogue if any)
User avatar
WTW
 
Posts: 3313
Joined: Wed May 30, 2007 7:48 pm

Post » Fri Nov 16, 2012 8:12 am

... if I update a script that is in the middle of execution (via OnUpdate or otherwise), what is the order of operation? Does the old version of the script completely execute one update, and then on the next update the new one fires? What exactly happens here?

Maybe you missed my post, but that was my point. If the script is executing, the script itself will not update. There will be no indication the update failed. If you look in the log file, you'll see the save game will still be referencing the old script files and unable to find them since the mod has new scripts. The outward affect is that users will complain because these (failed to upgrade) scripts will not be working.
User avatar
REVLUTIN
 
Posts: 3498
Joined: Tue Dec 26, 2006 8:44 pm

Post » Fri Nov 16, 2012 9:53 pm

This is such a bag of hurt. Thanks Amethyst. It looks like I'm going to have to think very critically about my next steps, because it seems like ensuring upgrade smoothness is going to require a very specific set of actions on my part, as well as restructuring how I do certain things. I'm still trying to parse through all of this.

Minor side note: all of this information needs to be spread far and wide. This is stuff people need to know. The Creation Kit wiki page on http://www.creationkit.com/Save_File_Notes_%28Papyrus%29 covers hardly any of this.

Edit: Thanks Sollar, I think I understand now.
User avatar
Music Show
 
Posts: 3512
Joined: Sun Sep 09, 2007 10:53 am

Post » Fri Nov 16, 2012 3:42 pm

What if the object that the property was resolved to no longer exists?

- Clear out what the Property was pointing to in the Creation Kit. Then it won't return anything and Papyrus won't complain.

I am using RegisterForSingleUpdate(), so I will need to put some logic in place that avoids calling the RegisterForSingleUpdate() at the end of the OnUpdate() block.

- You can use Return for this. If you return before you re-register the script to update, then the registration will never be called and the script will become idle.

Could you explain this? How does changing this number "trigger" a script to run a function? What function?

Here's my version control script from Economics of Skyrim:

scriptname aaTKVersionControl extends Questquest property aaTKEconomicsControl autoMessage property aaTKUpdateMSG autoFloat VersionNumberEvent OnUpdate()	If(VersionNumber == 0)		VersionNumber = FetchVersion.VersionNumber	ElseIf(VersionNumber != fetchVersion.VersionNumber)			UpdateVersion()			EndIf		RegisterForSingleUpdate(1)	EndEventaaTKEconDefaults property fetchVersion	aaTKEconDefaults function get()		if !fetchSet			fetchSet = true			fetchVal = (Self as Quest) as aaTKEconDefaults		endif		return fetchVal	endFunctionendPropertyaaTKEconDefaults fetchValbool fetchSet = falseFunction UpdateVersion()	VersionNumber = fetchVersion.VersionNumber		aaTKEconomicsControl.setStage(0)		aaTKUpdateMSG.Show(VersionNumber)	EndFunctionFunction VersionCheckStart()	RegisterForSingleUpdate(1)	EndFunction

- The initialization/update functions for the mod are embedded into a separate Initialization script that gets called to run whenever the containing quest is at Stage 0.

Do you have a preferred method of "pushing" data to another script? Or do you usually set properties on your initialization script that your other scripts read at the appropriate time and take action?

- There is an example of this in the above script, where I have a read-only property set up to obtain the value of a property from another script. If you want a full property, you can just declare " property Auto" and point it to the quest containing that script in the Creation Kit.

Is there an exact condition that causes a duplicate version of a script to being firing? And assuming that updating my script doesn't cause a duplicate script issue, if I update a script that is running (via OnUpdate or otherwise), what is the order of operation? Does the old version of the script completely execute one update, and then on the next update the new one fires? What exactly happens here?

I'm not sure what the trigger is, but I had one guy report to me he was having problems with one of my mods that I was eventually able to trace to duplicate copies of the mod's scripts existing in his save (but for some reason they had no data tied to them and so were throwing an insane amount of errors, eventually causing Stack Suspension in about two minutes). I've since added contingencies to hopefully prevent that from happening, but I still don't know what the trigger is, as he was the only guy who reported that problem and that isn't enough to go on, since I can't trace any common actions and can't recreate the behavior myself.

It could also be that he was a user of the mod during the time I made it while a newbie to Papyrus and I hadn't yet decided on my conventions. Now I have, and those conventions allow me to keep updates and possibly overhauls to my mods very clean.

But unless you set your mod up with such scenarios in mind, you will still need to consider how you are going to get there. It's very hard to change conventions in Papyrus, and I do not think it will be possible to do so without some residual debris. Best you can do is minimize the garbage that will get left behind.
User avatar
pinar
 
Posts: 3453
Joined: Thu Apr 19, 2007 1:35 pm

Post » Fri Nov 16, 2012 3:17 pm

What a humbling, eye-opening experience this has been. Most of this code was written before I had a real understanding of Papyrus, and before the mod's overall structure had solidified. I've identified 20 properties that are no longer being used, and 10 that are properties but really should be globally-scoped variables. And the graveyard at the bottom continues to grow.

Anyway, thank you to everyone that contributed knowledge in this thread. I feel like I have a much better grasp on what the heck I'm doing and what to do next.

:thanks:
User avatar
Batricia Alele
 
Posts: 3360
Joined: Mon Jan 22, 2007 8:12 am

Post » Fri Nov 16, 2012 10:56 am

One last question. We mentioned earlier that it's OK if properties no longer are resolved to their original objects, as long as the property is Cleared in the CK (for instance, GlobalVariables). To clarify, that means that it is OK to delete unused objects (of various types), yes?
User avatar
Andrew Tarango
 
Posts: 3454
Joined: Wed Oct 17, 2007 10:07 am

Post » Fri Nov 16, 2012 7:52 am

its ok to delete unused objects from the esp. but you need to keep the unused scripts in the scripts folder even if nothing is using them anymore, because the save games will look for them forever if they are missing.
User avatar
Kristina Campbell
 
Posts: 3512
Joined: Sun Oct 15, 2006 7:08 am

Post » Fri Nov 16, 2012 6:12 pm

This is probably safe to do, but I figured I would ask anyway: is it OK to change the DocStrings on properties I intend to deprecate? I see this as a good way of keeping track of which properties have been phased out in the CK.
User avatar
Tom
 
Posts: 3463
Joined: Sun Aug 05, 2007 7:39 pm

Post » Fri Nov 16, 2012 11:45 pm

Yes, it's perfectly fine to do that. That info is never used by the game.
User avatar
Phillip Brunyee
 
Posts: 3510
Joined: Tue Jul 31, 2007 7:43 pm


Return to V - Skyrim