WhiteWolf424242 Posted September 19, 2021 Share Posted September 19, 2021 Hello, Unfortunately it seems a project of mine is going downhill into the situation, where it will have to do that: Move lots of unique ObjectReferences out of, then into the player inventory in a quick succession. As far as I know, this is a golden recipe for triggering possible papyrus stack dumps if there are lots of other scripts present in the game without the necessary inventory filters. So the scenario is that the ObjectReferences are sitting in an array on a script, and they have to be moved out of the inventory, (the script the does some stuff to them, namely puts them into aliases), and then they must be moved back into the player inventory, silently. The theoretical limit of the objects is 128 (length limit of the array). I don't expect to have this many ObjectReferences in an actual game, but theoretically it's possible that the script will have to move up to 128 ObjectReferences out of, then into the player inventory. Successively, quickly. How is it possible to do this safely? Are there some sort of precaution techniques that can do this in a safe way, preventing a possible stack dump? (I mean on THIS end of the code, that's doing the moving in and out thing. NOT on the end of the other scripts that failed to use inventory filtering to reduce their load.) Thanks Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 20, 2021 Share Posted September 20, 2021 (edited) My Inventory Management System mod (SSE version) does a lot of mass transfer back and forth. The way I avoided as many stack dumps as possible was two fold. The first thing I did was utilize SKSE's added Mod Events feature. The script triggering the transfer would first send a mod event to the aliases running the OnItemAdded and OnItemRemoved events. Those scripts would receive the mod event and remove all inventory filters and add back a filter for a certain single item. When the transferring was complete, a separate mod event would be sent which would then add back the inventory filters for the lists of items. The second thing was designating a count limit of 31. If a list contained 31 or less items, the list would be transferred in one go. If the list was greater, I'd compare the quantity of items in the container being transferred from against the index size of the current list. Whichever was smaller, I'd cycle through one at a time and transfer if said item matched the criteria. Since you are doing something to each object, if done sequentially rather than all at once it will spread the processing out and help eliminate the stack dumps. Downside is that it may take longer than desired. Edited September 20, 2021 by IsharaMeradin Link to comment Share on other sites More sharing options...
WhiteWolf424242 Posted September 20, 2021 Author Share Posted September 20, 2021 Thanks very much :smile: I'm afraid I do things a bit differently. My mod doesn't contain any OnItemAdded and OnItemRemoved events by the way, so there's nothing I can do about those - I'm just worried what I might trigger by doing by stuff if someone does have such events without filters in their game. Doing the moving with a limit (why 31 though? Just curious. I get it it's a prime, but any other reason?) seems like a reasonable idea. However, the doing something to the objects is done by the script that's also doing the move in/out.Let me clarify: Each ObjectReference has a script attached, that has this property: ObjectReference Property OwningContainer Auto The script uses states and OnContainerChanged events to store what container the reference is currently in (NONE if dropped in the world). The move in/out of owning container happens as a part of saved game reload maintenance. Alias renamings of these objects are lost on a save reload because their underlying Message title that was renamed with SKSE's SetName() is lost. Which means the items all return to the Message's original CK name - and thus the items in inventories get stacked since they get the same name (and are also the same base objects).Unfortunately, doing just the renaming-back maintenance does not unstack the items. (Instead the last item's name is shown as the stack name). They need to be moved out of inventory, and back in so that they are again shown as separate items and not as a stack. So the maintenance script does something like this: ; objects that need maintenance are sitting in an array like this: ObjectReference[] SentRefs int sentRefsLen ; their current number, guaranteed to be less than 128 function RenamingPartOfTheMaintenance() ObjectReference OwningContainers = new ObjectReference[128] int i = 0 while(i < sentRefslen) ) ; iterate over all currently in-game items ItemScriptName itemscript = SentRefs[i] as ItemScriptName OwningContainers[i] = itemscript.OwningContainer ; get owning container from their script ; if this is not NONE, the item is in some inventory, and needs to be moved out then back in to avoid stacking there if(OwningContainers[i]) SentRefs[i].Moveto( someXMarkerInAJunkyardWorldspace) endif ; clear renaming alias here ; update underlying Message name here i += 1 endwhile i = 0 while(i < sentRefsLen) ; force ref back into renamer alias to update name here if(OwningContainers[i]) ; it was moved out previously, now to put it back in (silently) OwningContainers[i].AddItem( SentRefs[i], 1, true) endif endwhile endfunction (A note: I'm not renaming my items with SetDisplayItem() because they are books and that breaks their text replacement. See this thread and this thread. I'm afraid this is the only way to reliably rename successively spawned book references with text replacement.) Most of the ObjectReferences are likely in the player inventory. So would it help if the loops only went until something like 31, and then went to sleep for a few seconds by registering for a single update, to allow other stalled papyrus stacks to get out of there, and then continuing there? Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 20, 2021 Share Posted September 20, 2021 Why 31? In the unmodified game, that is the total number of alchemy ingredients and the smallest list. And whenever there were less than that in a container and take all was used (even without deactivating my mod's event filters) there were no stack dumps appearing. Seemed to be a logical cut off point before having to take a slower one by one approach. Unfortunately, it seems like my approaches will not work with your specific scenario. You may be fine as it seems that your maintenance function already handles one item at a time. There is a difference between cycling an array / list and transferring all at once. It is the latter that contributes to the stack dumps, the former takes up more time. Link to comment Share on other sites More sharing options...
WhiteWolf424242 Posted September 20, 2021 Author Share Posted September 20, 2021 All right, thanks :) I guess only one way to know for sure - next week I'll try a stress test, I'll spawn 128 objects, and try loading a saved game with them in the inventory and check the papyrus logs after.If it causes a stack dump, I'll revive the thread. Link to comment Share on other sites More sharing options...
IsharaMeradin Posted September 20, 2021 Share Posted September 20, 2021 Good luck! Link to comment Share on other sites More sharing options...
ItsAlways710 Posted October 17 Share Posted October 17 IsharaMeradin, is there any way to avoid firing the OnItemAdded event in other mods playeralias scripts, it seems you mention something above but I'm not following you on it... Or maybe you were just referencing your OWN alias scripts OnItemAdded events? I need to totally avoid the OnItemAdded event in EVERY alias script (my alias script uses states to avoid firing it while it's busy) and I'm guessing the only way would be to create an SKSE plugin? I really don't want to have to learn C LOL. -IA710 Link to comment Share on other sites More sharing options...
IsharaMeradin Posted October 18 Share Posted October 18 @ItsAlways710 The only time OnItemAdded does not trigger when an item is added is when that item is not found within the defined items for the inventory filter. I was referring to something that I did within one of my own mods. The process would work with other mods provided the other mods registered for the events I created and adjust their inventory filters as the events were received. Otherwise, it is something specific to my own mod. Given the improbability of getting every mod author to cooperate to add in the necessary stuff, what you want cannot be achieved by Papyrus alone. Sorry, I cannot be of much help in this regard. Link to comment Share on other sites More sharing options...
Recommended Posts