Jump to content

Recommended Posts

Just tested it, and it works now, giving it just "SexLabMissionary." and keyContains = true it exports the tags as expected.

 

It does however insert some null's before and after the list:

{
   "stringlist" : [
      null,
      {
         "key" : [ 77, 1158035935, "SexLab.esp" ],
         "value" : [
            {
               "key" : "SexLabMissionary.Tags",
               "value" : [ "Default", "sex", "Missionary", "Laying", "Vaginal", "MF" ]
            }
         ]
      },
      null
   ]
}

Which doesn't happen when not doing keyContains.

Link to comment

I've used the examples given in the OP to store a variable on an actor and then manipulate it. However the variable stays '0'.

My code:

 

 

	int i = 0
	while i < lengthOfActorList
		
		if StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") == 0 ;if variable doesn't exist yet initialize it
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
		endIf
		
		
		int temp = StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100 ;increase second value of array by 100
		StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, temp)
		
		
		i += 1
	endWhile
	
	
	debug.Notification("WearTearVaginal = " + StorageUtil.IntListGet(game.getPlayer(), "SLMF_WearTearVaginal", 1)) ;print value ;Error: Always returns 0

 

 

 

edit:

'actorList' and 'game.getPlayer()' point towards the same actor.

Link to comment

I've used the examples given in the OP to store a variable on an actor and then manipulate it. However the variable stays '0'.

My code:

 

 

	int i = 0
	while i < lengthOfActorList
		
		if StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") == 0 ;if variable doesn't exist yet initialize it
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
		endIf
		
		
		int temp = StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100 ;increase second value of array by 100
		StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, temp)
		
		
		i += 1
	endWhile
	
	
	debug.Notification("WearTearVaginal = " + StorageUtil.IntListGet(game.getPlayer(), "SLMF_WearTearVaginal", 1)) ;print value ;Error: Always returns 0

 

 

 

edit:

'actorList' and 'game.getPlayer()' point towards the same actor.

 

Can you try a couple of test lines like:

PapyrusUtil.SetIntValue(myActor, "TestVar", 10)
Int result = PapyrusUtil.GetIntValue(myActor, "TestVar")
Bool worked = result == 10
Link to comment

If your 100% positive actorList has the same form as Game.GetPlayer() (which you should almost never use by the way, a PlayerRef property is significantly faster), than the issue is most likely with your initialization, try this:

int i = actorList.Length
while i
	i -= 1

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile
	StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, (StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100))

	Debug.Notification("IsPlayer = "+(actorList[i] == Game.GetPlayer())+" - WearTearVaginal = "+StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1))
	
endWhile
	

That'll more reliably initialize it to your presumably desired length of 2, and adjust the second value of the list by 100, then inform you if actorlist is definitely the same as Game.GetPlayer() or not.
Link to comment

Just tested it, and it works now, giving it just "SexLabMissionary." and keyContains = true it exports the tags as expected.

 

It does however insert some null's before and after the list:

{
   "stringlist" : [
      null,
      {
         "key" : [ 77, 1158035935, "SexLab.esp" ],
         "value" : [
            {
               "key" : "SexLabMissionary.Tags",
               "value" : [ "Default", "sex", "Missionary", "Laying", "Vaginal", "MF" ]
            }
         ]
      },
      null
   ]
}

Which doesn't happen when not doing keyContains.

 

To add more to this, I left the code alone for awhile while I worked on some other stuff, so it ran repeatedly a couple times without me checking the results, but I just looked my test json file again and now after it's run a couple more times it looks like this:

 

 

 

{
   "stringlist" : [
      null,
      null,
      null,
      null,
      null,
      null,
      null,
      null,
      {
         "key" : [ 77, 1158035935, "SexLab.esp" ],
         "value" : [
            {
               "key" : "SexLabMissionary.Tags",
               "value" : [ "Default", "sex", "Missionary", "Laying", "Vaginal", "MF" ]
            }
         ]
      },
      null,
      null,
      null,
      null,
      null,
      null,
      null,
      null
   ]
}
Link to comment

I'm confused, an author confirmed that this is causing skse save bloat, then I see that you can clean everything backwards (the forms modified by yourself) - so how do you do it guys? Will something that gets removed leave empty entry in array?

Link to comment

If your 100% positive actorList has the same form as Game.GetPlayer() (which you should almost never use by the way, a PlayerRef property is significantly faster), than the issue is most likely with your initialization, try this:

int i = actorList.Length
while i
	i -= 1

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile
	StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, (StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100))

	Debug.Notification("IsPlayer = "+(actorList[i] == Game.GetPlayer())+" - WearTearVaginal = "+StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1))
	
endWhile
	

That'll more reliably initialize it to your presumably desired length of 2, and adjust the second value of the list by 100, then inform you if actorlist is definitely the same as Game.GetPlayer() or not.

 

 

Ashal, I'm having a hard time seeing the advantage of:

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile

Over

		if StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") == 0 
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
		endIf

Can you kindly please explain? They look equivalent to me, and actually the second is easier to read (I don't have to 'think' about looping, etc)

Link to comment

 

If your 100% positive actorList has the same form as Game.GetPlayer() (which you should almost never use by the way, a PlayerRef property is significantly faster), than the issue is most likely with your initialization, try this:

int i = actorList.Length
while i
	i -= 1

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile
	StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, (StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100))

	Debug.Notification("IsPlayer = "+(actorList[i] == Game.GetPlayer())+" - WearTearVaginal = "+StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1))
	
endWhile
	

That'll more reliably initialize it to your presumably desired length of 2, and adjust the second value of the list by 100, then inform you if actorlist is definitely the same as Game.GetPlayer() or not.

 

 

Ashal, I'm having a hard time seeing the advantage of:

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile

Over

		if StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") == 0 
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
		endIf

Can you kindly please explain? They look equivalent to me, and actually the second is easier to read (I don't have to 'think' about looping, etc)

 

 

Say they were initialized somewhere before with 1 or more elements on that same IntList, whether through a bug or from the authors previous debugging or experimentations.

  1. If Count == 0 doesn't account for that, resulting in them skipping the block with their length of 1 and trying to set the second element afterward in the function fails.

     

  2. If Count != 2 has the problem that if they were to go into it with 1, they would end up with a length of 3. The next time they entered the function, they would leave it with a count of 5. And time after that they'd leave with 7. And so on so on.

     

  3. While Count < 2  solves the first problem, and prevents the second from happeneing.

Secondly, I'd disagree the second is easier to read. You can just look at the condition's 2 and know that it is going to make the count come out to 2 and be done, it provides an easy way to adjust the size of the list should the author ever wish to, simply by changing the 2 in the loop condition to a different number, and lastly a common mantra of maintainable and good code is "Don't Repeat Yourself" (DRY) and while repeating two simple lines  may be so minor that it shouldn't fall under DRY, I'd consider it a bad habit at the least.

Link to comment

 

 

If your 100% positive actorList has the same form as Game.GetPlayer() (which you should almost never use by the way, a PlayerRef property is significantly faster), than the issue is most likely with your initialization, try this:

int i = actorList.Length
while i
	i -= 1

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile
	StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, (StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100))

	Debug.Notification("IsPlayer = "+(actorList[i] == Game.GetPlayer())+" - WearTearVaginal = "+StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1))
	
endWhile
	

That'll more reliably initialize it to your presumably desired length of 2, and adjust the second value of the list by 100, then inform you if actorlist is definitely the same as Game.GetPlayer() or not.

 

 

Ashal, I'm having a hard time seeing the advantage of:

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile

Over

		if StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") == 0 
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
		endIf

Can you kindly please explain? They look equivalent to me, and actually the second is easier to read (I don't have to 'think' about looping, etc)

 

 

Say they were initialized somewhere before with 1 or more elements on that same IntList, whether through a bug or from the authors previous debugging or experimentations.

  1. If Count == 0 doesn't account for that, resulting in them skipping the block with their length of 1 and trying to set the second element afterward in the function fails.

     

If Count != 2 has the problem that if they were to go into it with 1, they would end up with a length of 3. The next time they entered the function, they would leave it with a count of 5. And time after that they'd leave with 7. And so on so on.

 

While Count < 2  solves the first problem, and prevents the second from happeneing.

Secondly, I'd disagree the second is easier to read. You can just look at the condition's 2 and know that it is going to make the count come out to 2 and be done, it provides an easy way to adjust the size of the list should the author ever wish to, simply by changing the 2 in the loop condition to a different number, and lastly a common mantra of maintainable and good code is "Don't Repeat Yourself" (DRY) and while repeating two simple lines  may be so minor that it shouldn't fall under DRY, I'd consider it a bad habit at the least.

 

 

Thanks for articulating your defensive programming practices. I don't know if I agree with you completely on point 1, but agree that style 2 (Count != 2) would be an laughable code choice. It is possibly that coding with "count<2" might cover up a bug that was introduced before (as you mentioned through author's changes) - that is, the IntList might have an existing member that would silently work with "count<2" whereas "count==0" would possibly rise to the attention earlier (what originally caused the query to be surfaced here). I agree with DRY completely and been following it for decades.

Link to comment

If your 100% positive actorList has the same form as Game.GetPlayer() (which you should almost never use by the way, a PlayerRef property is significantly faster), than the issue is most likely with your initialization, try this:

actorList is the actor list you get from SexLab. Aparently for PapyrusUtil GetPlayer() and the player from actorList are not identical.

GetPlayer() is faster if you're just debugging, though.

 

PapyrusUtil doesn't seem to work at all for me; this failed as well:

 

 

	StorageUtil.SetIntValue(actorList[0], "TestVar", 10)
	Int result = StorageUtil.GetIntValue(actorList[0], "TestVar")
	if result == 10
		debug.Notification("It works!")
	endIf

 

 

Do I need to include PapyrusUtil to my script or something?

 

Full script:

 

 

scriptname SexLabMF_WearTear extends Quest
{...}



SexLabFramework property SexLab auto

sslThreadController Controller





function OnLoadGame()
	
	RegisterForModEvent("AnimationStart", "SexLabAnimStart")
	RegisterForModEvent("OrgasmStart", "SexLabOrgasmStart")
	
endFunction



event SexLabAnimStart(string eventName, string argString, float argNum, form sender)
	
	Controller = SexLab.HookController(argString)
	
	
	
endEvent

event SexLabOrgasmStart(string eventName, string argString, float argNum, form sender)
	
	actor[] actorList = Controller.positions ;SexLab.HookActors(argString)
	int lengthOfActorList = Controller.ActorCount
	bool isAggressive = Controller.IsAggressive 
	actor victim = Controller.GetVictim()
	;hook = Controller.GetHook()
	
	
	
	int i = 0
	while i < lengthOfActorList
		
		while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
			StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
		endwhile
		
		
		
		StorageUtil.IntListSet(actorList[i], "SLMF_WearTearVaginal", 1, (StorageUtil.IntListGet(actorList[i], "SLMF_WearTearVaginal", 1) + 100))
		
		
		i += 1
	endWhile
	
	
	debug.Notification("IsPlayer = "+(actorList[0] == Game.GetPlayer())+" - WearTearVaginal = "+StorageUtil.IntListGet(actorList[0], "SLMF_WearTearVaginal", 1))
	
	
	StorageUtil.SetIntValue(actorList[0], "TestVar", 10)
	Int result = StorageUtil.GetIntValue(actorList[0], "TestVar")
	if result == 10
		debug.Notification("It works!")
	endIf
	
	
endEvent

 

 

Link to comment
  • 2 weeks later...

I have a quick question about this. Is PapyrusUtilv just a rename of StorageUtilv? I only ask to be sure the StorageUtilv13 is just a old version of the current PapyrusUtilv19 and not a second required program, which I think it is just a old version but wanted to be sure.

Link to comment
  • 2 weeks later...

I'm using version 1.9 with SKSE 1.7.0.

 

The ImportFile and ExportFile functions appear to be broken when using "restictForm" after starting a new game.

 

ExportFile writes a file with the correct value and keys, but missing the plugin name from the FormID key. Here is the code used to create the file:

;_kDummyActors[] is an array of ActorBases defined elsewhere

SetStringValue(_kDummyActors[idx],sKey + "Name","foo") 
ExportFile(_kDummyActors[idx].GetName(),restrictForm = _kDummyActors[idx])

Here is the resulting file when the function is run after loading a save game (this is the expected output):

 

{
   "string" : [
      {
         "key" : [ 43, 855642837, "vMYC_MeetYourCharacters.esp" ],
         "value" : [
            {
               "key" : "vMYC.Name",
               "value" : "foo"
            }
         ]
      }
   ]
}

 

Again, this is the correct and expected output.

 

Now, here is the resulting file when the same function is run after starting a new game. It is not in OnInit, but is run several seconds later during an OnUpdate event:

 

{
   "string" : [
      {
         "key" : [ 43, 855642837, "" ],
         "value" : [
            {
               "key" : "vMYC.Name",
               "value" : "foo"
            }
         ]
      }
   ]
}

 

 

Note the key has the correct FormID, but is missing the plugin name. I am guessing a similar bug in ImportForm is why I can't read form-restricted data after starting a new game, either.

 

If I start a new game, quicksave, quickload, and try it, it works fine.

 

Is there a workaround for this, or is it something you'll have to fix?

Link to comment

Would it be possible to extend the Condition Function List, so that we can work directly with Variables stored in Papyrus Util? Something like a new Condition Function GetPapyrusUtilVariable.

I thought about how to do this but didn't come up with a solution that works for all situations.

I wouldn't recommend doing this, this uses the old script API and the functions use fixed function opcodes. There is no interface here for plugins to add their own functions currently. I would steer clear of this until we work something out if this is really in high demand, realistically nobody is going to be using these condition functions until the Creation Kit Extender is up, as the only other way to get your custom functions into a plugin would be low-level record editing the function opcode.

 

 

Also unrelated to this, but SKSE 1.7.0 beta is currently out and has this in changelog, "enabled previously-temporary Papyrus plugin API" I assume that means they added more official support Papyrus functions to be added with SKSE plugins, and no idea of it makes any difference from the current method you're using to add Papyrus functions, but just a heads up, just in case.

Shouldn't make a difference, as it was previously hooking another function call to register. While we recommend switching to the new method it wouldn't be backwards compatible and you would have to force people to update, which is usually not preferable.

 

To register functions you only needed a pointer to the VMClassRegistry, which is only initialized at a certain point, so you could pretty much hook anywhere after the initialization occurs to register your function (Preferably after the vanilla functions have all registered).

 

It was added very early on by me, but it was disabled because we never intended for the API to be that way. We were supposed to decode enough of Papyrus to actually register AND bind the functions (thus eliminating the pex files except for modding). The one who knows the most about Papyrus internally got really busy and hasn't had time to do this so we agreed to just enable the basic API and hope that nobody registers functions for any of the vanilla classes (There's no need to do this anyway, Papyrus member functions are no faster than global functions).

 

 

Ashal, I'm having a hard time seeing the advantage of:

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile

While normally I would agree loops are better, but what we have here is all kinds of bad. There is no exit strategy for a function that could potentially return zero when SKSE isn't running, thus creating an infinite loop as 0 will always be less than 2 until hopefully you re-install the library this function relies on.
 
Never write a Papyrus loop relying on an SKSE function's return value that would evaluate as true if the function were to not exist. If you need to do something like this, wrap it with an exiting counter like 'tries'.

Link to comment

 

 

Ashal, I'm having a hard time seeing the advantage of:

	while StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal") < 2
		StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	endwhile

While normally I would agree loops are better, but what we have here is all kinds of bad. There is no exit strategy for a function that could potentially return zero when SKSE isn't running, thus creating an infinite loop as 0 will always be less than 2 until hopefully you re-install the library this function relies on.

 

 

If a mod relies on SKSE, it should have an exit strategy from performing anything at all in the first place, beyond a check for SKSE being enabled at startup. That alleviates the infinite loop concern, at least in my opinion, only real fringe case in that event would be somebody who saved their game mid function/loop call and later reloaded their game without SKSE, which while not impossible, is rather unlikely.

 

Though there is also wisdom in being paranoid about it regardless, and in hindsight it's also kind of ridiculous of me to recommend such a loop for something as simple as a 2 length integer list, though I would defend it in the case of larger initializations when proper SKSE checks are in place beforehand.

int n = StorageUtil.IntListCount(actorList[i], "SLMF_WearTearVaginal")
while n < 2
	StorageUtil.IntListAdd(actorList[i], "SLMF_WearTearVaginal", 0)
	n += 1
endWhile

Would obviously be a safer way to do it in any case.

Link to comment

 

To register functions you only needed a pointer to the VMClassRegistry, which is only initialized at a certain point, so you could pretty much hook anywhere after the initialization occurs to register your function (Preferably after the vanilla functions have all registered).

 

Tried that trick without any luck (due to uninitialized registry pointer propably).  While looking at other  plugins i noticed that they hook into SKSE registation method..

It's  the only way to achieven that on pre 1.7.0 SKSE?

Link to comment

 

 

To register functions you only needed a pointer to the VMClassRegistry, which is only initialized at a certain point, so you could pretty much hook anywhere after the initialization occurs to register your function (Preferably after the vanilla functions have all registered).

 

Tried that trick without any luck (due to uninitialized registry pointer propably).  While looking at other  plugins i noticed that they hook into SKSE registation method..

It's  the only way to achieven that on pre 1.7.0 SKSE?

 

Pre 1.7.0 yes.

Link to comment

Is there a way to account for how much storage StorageUtil is taking up in its various calls against global or forms? As a mod developer I have a pretty good idea how many things I am adding to the game save space, but it would be nice if I could run a diagnostic method that would report information to Papyrus log, etc.

 

Thanks

Link to comment

In calls themselves, like on stack? Should be few bytes in addition to papyrus function overhead, debug to see. If you mean data saved in memory then it's saved like this:

map<int64, map<string, int32>> ; integers

map<int64, map<string, vector<int32>> ; integer lists

to save on forms and globally. Each data type has own map. You can calculate the actual bytes but if you try to save memory somehow you may actually make the performance worse. You would need to have hundreds of thousands of entries saved before you think about optimization and the only optimization will be about how many function calls you make and not the memory amount that it occupies.

 

If you mean to save in file (not to confuse with export) then I believe about a thousand integers saved on all different forms (worse case scenario) should be less than 50 KB.

Link to comment

In calls themselves, like on stack? Should be few bytes in addition to papyrus function overhead, debug to see. If you mean data saved in memory then it's saved like this:

map<int64, map<string, int32>> ; integers

map<int64, map<string, vector<int32>> ; integer lists

to save on forms and globally. Each data type has own map. You can calculate the actual bytes but if you try to save memory somehow you may actually make the performance worse. You would need to have hundreds of thousands of entries saved before you think about optimization and the only optimization will be about how many function calls you make and not the memory amount that it occupies.

 

If you mean to save in file (not to confuse with export) then I believe about a thousand integers saved on all different forms (worse case scenario) should be less than 50 KB.

 

No, not for memory savings. I just want to disprove that my use of PU/StorageUtil is causing save bloat. It may be hard to winnow out what all other mods and SL itself is storing against global or forms though. For property names I always prepend my Mod's name before the property name itself so if I could simply have an MCM function in my mod that runs a method against StorageUtil that simply prints to the log or console based on my mods name as a "namespace" ? Just thinking out loud here.

Link to comment

You can iterate all data in storage util from all mods, check out the debug functions. With this data you can do what you want: write to file, log, MCM or console or whereever you wish.

 

Example to iterate all global int values:

 

int count = debug_GetIntKeysCount(none)

while(count > 0)

count -= 1

string key = debug_GetIntKey(none, count)

int val = GetIntValue(none, key)

Debug.Trace("Key: " + key + " = " + val)

endwhile

 

If you want to iterate forms too not just global then debug_GetIntObjectCount() for count and debug_GetIntObject(index) to get the object, then instead of none use that Form.

 

Just printing out the count of saved values should be enough to see if there is bloat though. I'm almost certain this doesn't cause any noticable save file size change unless there's a mistake in someone's script and added like millions of values but you would also notice that the saving of game would take a long time.

 

Edit: I could compile a debug version for you that writes to console the size of data section this mod uses when saving game.

Link to comment

You can iterate all data in storage util from all mods, check out the debug functions. With this data you can do what you want: write to file, log, MCM or console or whereever you wish.

 

Example to iterate all global int values:

 

int count = debug_GetIntKeysCount(none)

while(count > 0)

count -= 1

string key = debug_GetIntKey(none, count)

int val = GetIntValue(none, key)

Debug.Trace("Key: " + key + " = " + val)

endwhile

 

If you want to iterate forms too not just global then debug_GetIntObjectCount() for count and debug_GetIntObject(index) to get the object, then instead of none use that Form.

 

Just printing out the count of saved values should be enough to see if there is bloat though. I'm almost certain this doesn't cause any noticable save file size change unless there's a mistake in someone's script and added like millions of values but you would also notice that the saving of game would take a long time.

 

Edit: I could compile a debug version for you that writes to console the size of data section this mod uses when saving game.

 

Thanks, I guess I wasn't aware of the debug_ functions. I'm not presupposing PU/StorageUtil is at fault - i'm actually just trying to prove that my code isn't using PU/SU inappropriately or naively. 

 

Regarding your proposal - that would be helpful to me at least. Console and Papyrus log?

Link to comment

I think having the specially instrumented .dll would be helpful as part of the development of a mod, as a great debug tool or even sanity check/smoke test. Also using the methods above would help me to insert some diagnostics inside my mod to be executed "in the field" so to speak.

 

thanks!

Link to comment

Ok done, made a new version out of it while I was doing things. Didn't test anything, I don't have time. If something is not working right let me know and I'll try to fix.

 

This new version includes:

Fix for JSON export (maybe) - Ashal

List insert and sort for .. I forget but someone asked

Debug mode for reporting StorageUtil section size in save games - gooser and perhaps helpful to many others as well

 

Edit:

 

StorageUtil.debug_SetDebugMode(true) ; enable debug mode until you exit game or set false

 

Currently only thing it does is when you load or save a game it displays the size of StorageUtil section in save game in bytes on console. You may need to open console at least once first, someone said.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use