ryobg / JContainers

JSON-based data structures for Papyrus - the TESV Skyrim SE scripting language
MIT License
107 stars 23 forks source link

JDB initialization #76

Closed andrelo1 closed 2 years ago

andrelo1 commented 3 years ago

Is there way to initialize JDB with default values ?

I have to wrap each JDB value into property:

int MyInt_Default = 0

int property MyInt ---int function get() ------return JDB.solveInt(".MyMod.MyInt", MyInt_Default) ---endfunction ---function set(int value) ------JDB.SolveIntSetter(".MyMod.MyInt", value, true) ---endfunction endproperty

I'm not happy with such cumbersome code. I can use OnInit or OnPlayerLoadGame event to initialize JDB, but it doesn't guaranty that another script won't try to read uninitialized values from JDB. Can I access JDB from init.lua to do my initialization before any script can access it ?

ryobg commented 3 years ago

JDB is public, shared object for all, you usually should not touch the other's data. Hence, don't rely on init order too. Just go, set up your values upfront and read them later.

andrelo1 commented 3 years ago

Sometimes I need to read values from JDB in OnInit event, that kicks off right after start of the game, so there is no way to init values earlier. How can I be sure that values have been set up ? I don't want to use global variable and infinite loop to wait for initialization completion:

while !isJDBInitialized ---Utility.Wait(0.01) endwhile

;Read values from JDB.

andrelo1 commented 3 years ago

To be more specific, I wanted to store some settings of my mod in JDB instead of script object. When I used a script I was able to read its properties at any time, even in OnInit event, because I can assign default values to properties. In JDB there are no values at all by default, and that is a problem.

ryobg commented 3 years ago

I'm getting lost. Select your most "first" function, set all JDB values which has not been set and then use them later.

andrelo1 commented 3 years ago

But there is no most "first" function, because Papyrus language is multithreading, all OnInit events on all game objects start simultaneously, and you can't select one object, that is initialized first, to set up JDB values.

andrelo1 commented 3 years ago

I can make a "proxy" functions to access JDB values:

bool initialized = false

int function GetJDBValueInt(string path) ---if !initialized ------Initialize() ---endif

---return JDB.solveInt(path) endfunction

; Same thing for Float, String, Obj and Form types

But this is not good solution too, in my opinion.

MrOctopus commented 3 years ago

Have 1 main script perform the initalization in the OnInit event:

event OnInit()
---; Init db here
---; Utility.wait(1.0) ; Allow other scripts to finish registering for custom mod event
---; self.SendModEvent("JDBInit")
endevent

In the other scripts register for the mod event in their OnInit. You now have a way to ensure that all other scripts will only access the JDB object after it has been initialized:


event OnInit()
---self.RegisterForModEvent("JDBInit", "OnJDBInit")
endevent

event OnJDBInit(string eventName, string strArg, float numArg, Form sender)
--- ; Do whatever you need to do after JDB has been initialized
endEvent
andrelo1 commented 3 years ago

Well, this is a better solution. I thought that init.lua was intended for such initialization, including initialization of JDB.

Edit: I have looked at source code and found that init.lua is used for context setup when evalLua* function is called, and thus it would be wrong place for JDB initialization.