Jump to content

[MCM scripting] how to properly do versioning?


3aq

Recommended Posts

I am using this github page as a reference, it seems to compile fine; however as I am unsure whether or not it'll work (don't have a working station to experiment with), I'll assume that I am not doing it properly (ie it's not working).

 

 

So here's the meat of the topic, my test script:

sections and questions are commented, thank you.

Scriptname _MySelfUpdatingScript extends SKI_ConfigBase

;---VERSION CONTROL
;---v1.1.0


;---QUESTION
;is returning 3 on all 3 portion correct..?

int function GetVersion_MSUS()
    return 3
endFunction

int function GetVersionMinor_MSUS()
    return 3
endFunction

int function GetVersionBeta_MSUS()
    return 3
endFunction

string function vc()
    return GetVersion_MSUS() as string + "." + GetVersionMinor_MSUS() as string + "." + GetVersionBeta_MSUS() as string
endFunction

; PRIVATE VARIABLES
; -- Version 1.1.0 --
int      myVar = 0

; INITIALIZATION
event OnConfigInit()
    Pages = new string[2]
    Pages[0] = "Page 1"
    Pages[1] = "Page 2"

    myVar = Utility.RandomInt(0,100)
endEvent

event OnPageReset(string page)
    if (page == "Page 1")
        addHeaderOption("3aq@nexusmods - v" + vc())    
    elseIf (page == "Page 2")
        addHeaderOption(myVar)
    endIf
endEvent


; -- Version 1.0.0 --
; event OnConfigInit()
;     Pages = new string[1]
;     Pages[0] = "Page 1"
; endEvent
;
; event OnPageReset(string page)
;     if (page== "Page 1")
;        addHeaderOption("3aq@nexusmods - v" + vc())
;    endIf
; endEvent

;---QUESTION
; where is a_version referenced to make script autoupdate save from 1.0.0 to 1.1.0?

event OnVersionUpdate(int a_version)
    if (a_version > 1)
        Debug.Trace(self + ": Updating script to version " + a_version)
        OnConfigInit()
    endIf
endEvent
Link to comment
Share on other sites

What you have will work. How exactly, I'm not 100% positive on. I have never really dug into the MCM API scripts themselves.

 

The only way to test this out would be to run an old version of the MCM on a new game, save and exit that game. Then change to the new version and load the previous save. If the versioning works, your changes will go through.

Link to comment
Share on other sites

well there is no instances of xxx_MSUS() it's something that I added, so I am pretty sure it probably wouldn't work (ie the function just returns a number and that's it)

the SKSE psc has GetVersion() but that only checks SKSE's version.

I am rather more curious as to where the a_version is getting referenced to instance the script to autoupdate itself.

Edited by 3aq
Link to comment
Share on other sites

It is all handled within the SkyUI script files. You assign a version value to be returned within the GetVersion() function. Note that it is not SKSE.GetVersion() used but a plain GetVersion(). This is because there is a variation of GetVersion() on SKI_ConfigBase. Thus when you use GetVersion() with your MCM script, SkyUI's code (human readable format not shared in downloads) catches your value and stores it in such a way that it remains associated with your MCM script. Thus when you update your version an internal comparison is done and the OnVersionUpdate event is triggered as necessary.

 

If you really want to know what is going on, you need to extract the SkyUI script files from the SkyUI BSA and decompile them with Champolion. And if you do that, do not, I repeat, do not extract to the game directory.

Link to comment
Share on other sites

The form would just be:

Scriptname _MySelfUpdatingScript extends SKI_ConfigBase

;---VERSION CONTROL
;---v1.1.0

;---QUESTION
;is returning 3 on all 3 portion correct..?

;; ANSWER
;; No, you need to have exactly one GetVersion function that returns an int.
;; A hidden variable is automatically compared to what is returned by your 
;; GetVersion function each time the script runs. If the value of your GetVersion 
;; is higher than the old value in the hidden variable then the OnVersionUpdate 
;; function gets called (and that hidden variable is updated).  The only magic is 
;; that you have to have a function called GetVersion that returns an int which 
;; gets bigger each time you want OnVersionUpdate to get called.

int function GetVersion
    return 3
endFunction

string function vc()  ; you don't actually need this and could just use the basic version number
    if GetVersion() = 3
        return "1.1.0" ; you can do something like this if you want a "pretty" version for printing
    endif
endFunction

; PRIVATE VARIABLES
; -- Version 1.1.0 --
int      myVar = 0

; INITIALIZATION
event OnConfigInit()
    Pages = new string[2]
    Pages[0] = "Page 1"
    Pages[1] = "Page 2"

    myVar = Utility.RandomInt(0,100)
endEvent

event OnPageReset(string page)
    if (page == "Page 1")
        addHeaderOption("3aq@nexusmods - v" + vc())    
    elseIf (page == "Page 2")
        addHeaderOption(myVar)
    endIf
endEvent


;---QUESTION
; where is a_version referenced to make script autoupdate save from 1.0.0 to 1.1.0?

;;Answer:
;;As stated above, this gets called if you change GetVersion to return a larger value.
;;The argument a_version is provide to you so you can choose to do different things
;;for each update you might make.

event OnVersionUpdate(int a_version)
    if (a_version > 1)
        Debug.Trace(self + ": Updating script to version " + a_version)
        OnConfigInit()
    endIf
endEvent

OK, now for the extra info. Many changes to an MCM script won't require a new version number for the script. You generally only really need a new version if you try to change the value of an existing property. One example where that might matter is if you wanted to add a third page to your MCM. Since the code for setting up pages in OnConfigInit had already set up for just two (and OnConfigInit only runs once), if you want to add another page you'll need to change that code in OnConfigInit and then get OnVersionUpdate to force OnConfigInit to run again. If you're simply adding new Properties and changing the code in the OnPageReset and similar functions then you don't technically need to update the script version.

Link to comment
Share on other sites

thank you for the info Ishara and cd.

 

@cdcooley your note on

string function vc()
	if (GetVersion() == 3)
		return "1.1.0"
	endIf
endFunction

so for every additional version update, I will simply change the return "x.x.x" ? this brings up an issue that I've been meaning to ask. Whenever I reuse a string, it would never display the updated string, only displaying the original string. As I do not know the proper way to update strings, I've thus been creating new strings (ie. if original was a_01, updated string will be a_11, I would replace all a_01 with a_11.) atm it's "alright" but I am afraid if I keep this up it'll cause potential problems in the future.

 

I am unsure it'll be the same for string function vc(), but my past observation with string a_01

tells me that it might require me to do the same, ie rename vc() to vc1(), replace all instances of vc() with vc1().

Link to comment
Share on other sites

If your string a_01 is a variable or property then it's value only changes if you explicitly change it in some function. Those are exactly the sorts of things you need an version update to do. That string being returned by the vc() function (and the number being returned by the GetVersion() function) are literals inside the body of a function so they will change dynamically unlike anything held in a variable or property.

 

The point of GetVersion() is so that you can write the code in the OnVersionUpdate event to change any property and variable values that need to be modified after the previous version values get "baked in" to the saved game files.

 

Basically when you modify the script you're free to change the contents of any of the functions and events, but you can really only add properties and global variables (to expect them to appear in game). If you want to change a property or variable default value you have to do it in the OnVersionUpdate event not in the declaration or by filling it in the CK.

Link to comment
Share on other sites

so for the record in order to update instances of string a_01 from version 1 to version 2.. let's say example

first version string a_01 = "hello world"

second version string a_01 = "goodbye world"

I would have to put the following

string a_01 = "goodbye world" into OnConfigInit

 

 

; string a_01 = "hello world" ;; version 1 string a_01, what needs to be changed.
string a_01 = "goodbye world" ;; version 2 string a_01, however since it was not placed within the onconfiginit it'll still display version 1 a_01 "hello world".

event OnConfigInit()
Pages = new string[2]
Pages[0] = "Page 1"
Pages[1] = "Page 2"

myVar = Utility.RandomInt(0,100)
string a_01= "goodbye world" ;; this would now replace all a_01 with version 2.
endEvent


 

this being the case the proper method would be to omit the lines?

 

 

 

; omit this line ; string a_01 = "hello world" ;; version 1 string a_01, what needs to be changed.
; omit this line ; string a_01 = "goodbye world" ;; version 2 string a_01, however since it was not placed within the onconfiginit it'll still display version 1 a_01 "hello world"

event OnConfigInit()
Pages = new string[2]
Pages[0] = "Page 1"
Pages[1] = "Page 2"

myVar = Utility.RandomInt(0,100)
string a_01= "goodbye world" ;; this would now replace all a_01 with version 2.
endEvent


 

if that's the case, then it makes sense to me.

sincere thanks cdcooley for the indepth explanation on this.. this really does help me digest and understand the nature of this.

(asking these questions helps to clarify and digest info I am uncertain of; apologies for asking/restating what seems to be dumb question/statements)

Link to comment
Share on other sites

Except that you can only use a variable at a level the same or lower than where it is declared and defined. So if you declare string a_01 within the OnConfigInit() event, you can only use that variable within that event. If you need to use it elsewhere in the script, declare it outside but define it inside. i.e.

String a_01
Event OnConfigInit()
;other stuff
a_01 = "goodbye world"
EndEvent
Link to comment
Share on other sites

so if I get what you said correct,

version 1

string a_01 = "hello world"

event OnConfigInit()
Pages = new string[1]
Pages[0] = a_01
EndEvent

event OnPageReset(string page)
if(page == a_01)
draw_a()
endIf
endEvent

function draw_a
addHeaderOption (a_01)
endFunction


version 2 a_01 not declared outside

 

event OnConfigInit()
Pages = new string[2]
Pages[0] = a_01
Pages[1] = "Page 2"

string a_01 = "goodbye world"
EndEvent

event OnPageReset(string page)
if(page == a_01)
draw_a()
elseIf(page == "Page 2")
addHeaderOption(a_01)
endIf
endEvent

function draw_a
addHeaderOption (a_01)
endFunction

 

Results: MCM "Pages" titles will still show version 1 "hello world" due to OnPageReset not getting its a_01 updated which is caused by the lack of declaration (?)

The string added by "draw_a" will show version 1 "hello world" (?),

The string added directly will show version 2 "goodbye world" (?)

 

version 2 a_01 declared outside

 

string a_01
 
event OnConfigInit()
Pages = new string[2]
Pages[0] = a_01
Pages[1] = "Page 2"

string a_01 = "goodbye world"
EndEvent

event OnPageReset(string page)
if(page == a_01)
draw_a()
elseIf(page == "Page 2")
addHeaderOption(a_01)
endIf
endEvent

function draw_a
addHeaderOption (a_01)
endFunction

 

Results: MCM "Pages" titles will show version 2 "goodbye world" due to a_01 being both declared outside and assigned in OnConfigInit (?)

The string added by "draw_a" will show version 2 "goodbye world" (?)

The string added directly will show version 2 "goodbye world" (?)

Edited by 3aq
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...