the Sim Settlements forums!

Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

ResourceManager code bugs and potential fixes

cbrgamer2

Well-Known Member
Messages
723
I'm posting this here on advice from RayBo. I believe I have located the reason why the numbers in the HUD resources panel are way off what they should be for the totals.
I'm going to reference my decompiled code here. I assume the function names line up with the actual code, although of course the line numbers won't. So when I refer to line numbers, I am referring to the code snippets pasted here.

Firstly, in the DailyUpdate function, the plot costs do not seem to be taken into account at all.
EDIT : I have discovered that this is intentional, as the plot costs are handled the by the plots themselves (although a little inconsistently it seems). This explains why people see their resource totals go down even when there is a surplus of that resource. I have discussed the problems with this in post 10.

The second issue is in the AdjustSettlementVirtualResource function.
In the following, I'll refer to Scrap as Level 1, Building Materials, Organic Materials, Machine Parts and Rare Materials as Level 2 and the rest as Level 3.
The DailyUpdate code runs through all resources, including the Level 2 and 3 resources. For each one it works out the production amount by getting the amount produced and subtracting the costs (though not the plot costs currently). It does that for each settlement. Then it deals with deficits by taking from the production value of other resources. So we end up with a ProductionRates array with how much of the current resource is produced in each settlement (after costs have been paid). This production is then added to the virtual resource storage, by calling ProduceSettlementVirtualResource, which checks for capacity and in turn calls AdjustSettlementVirtualResource to make the necessary change.
Here is the relevant code from AdjustSettlementVirtualResource
1623552546500.png
abBypassGroupHandling is always passed as false from ProduceResource.

First Scrap (Level 1) is passed through. It does use use Base Value as Capacity, so 1526 and 1527 are not run. In 1532 it's iCategoryIndex is -1, which is the iVRCategory flag. AdjustValue is true, and AjustMax is not, so 1535 is run and this is key - it tells it not to change that virtual resource. Line 1541 is not run because my scrap category is set to complex, so bMakeChange stays false. ICategoryIndex is still -1, so 1546 does not run. Since bMakeChange is false, the rest does not run and the resource is not added. This is all CORRECT for Scrap (Level 1).

Next, Building Materials (Level 2) is passed through. When passed, abAdjustValue is true and abAdjustMax is false, but for BuildingMaterials DoesUseBaseValueAsCapacity is true, so 1526 runs, setting abAdjustMax to true. This means bMakeChange stays true for Building Materials. Building Materials also has iCategoryIndex of 0, so it runs the HandleAdjustSettlementVirtualResourceForGroupedStorage.
This function is designed to add the resource to the parent groupings as well. So when it is run on the Building Materials pass, it adds the value to scrap as well. This is INCORRECT. Building Materials then has bMakeChange as true, so the amount is added to the Building Materials virtual storage. This is also INCORRECT.

The other Level 2 materials are passed through with the same problem. By now, Scrap Level 3 has had the full amount added to it, as have all Level 2 materials. Actually, it's not quite the full amount because the function GetSpecificDailyCosts returns 0 for level 2 materials and scrap, so the full production amount without any costs has been added.

Now the Level 1 materials get passed through (one at a time). Their abAdjustValue and abAdjustMax are both true, so bMakeChange is set to true. Their iCategoryIndex is also greater than 0, so HandleAdjustSettlementVirtualResourceForGroupedStorage is run as well. This function adds the amount to the levels above the Level 3 resource, so for Wood it adds it to Building Materials and Scrap as well. This is actually CORRECT, but because Scrap and Building Materials were also incorrectly added to on the Building Materials pass, both scrap and Building Materials have had it added twice (actually, a little more the first time because costs are not taken into account).

So, my conclusion is when level 2 materials are passed through, they should not have bMakeChange set as true and should not run HandleAdjustSettlementVirtualResourceForGroupedStorage. This will mean when a Level 3 resource goes through, it will correctly add it to that resource, the level above it, and the scrap resource, only once, taking costs into account. I believe this was the intended function. This could be achieved by firstly having iCategoryIndex test for > 0, not >= 0 in line 1545, as Level 2 resources will return a iCategoryIndex of 0 at that stage. That means the Handle function will not run for them. We also need the Level 2 categories to be set to false. If it were changed to have the DoesUseBaseValueAsCapacity return true for them, that would fix the problem. But I don't know if that causes problems, because I don't know how that value is used elsewhere.

I have tested these fixes by copying the relevant functions so I can modify them and call my modified ones. The fixes make the DailyUpdate add resources work as intended (including not going over the virtual limit). The resource numbers are then correct on the HUD.
I think correcting this could fix quite a few problems people have been having with resources, because currently the numbers for Level 2 and Level 1 resources aren't accurate, which probably messes up other calculations the code is doing.

This is all with scrap category set to complex. I'm not totally sure yet how the other categories are supposed to work. My guess is when it is set to moderate, none of the Level 3 resources are recorded and when it is set as Simple, nothing below level 3 is recorded and when you switch between them it changes all the values. However, this isn't what actually happens, so I don't know if it's a bug or I don't understand the intention.

EDIT : I should mention here that for simplicity I have only been testing this using one settlement. I know each settlement stores its own values, but I'm not sure if the HUD gets the caravan network values by adding them all up, or if that number is stored somewhere as well. FURTHER EDIT : the caravan network values are obtained by adding the individual settlement values.

ALSO, see post 7 for another potential fix for a different HUD problem.
 

Attachments

  • 1623551567850.png
    1623551567850.png
    45.5 KB · Views: 24
  • 1623551917581.png
    1623551917581.png
    64.3 KB · Views: 5
Last edited:
Wow :)
I really do hope these bugs gain some traction as they're completely messing up my whole settlement experience. I love that you took the time to get into this.
 
Very nice analysis! It seems that I was way off in my own. :) I completely misread what fPowerCost and similar variables are.

Anyhow, if I will still have mental capacity after work, I would very much like to double check your changes on my test settlement.
Can you share your modified code for both functions? Your instruction is very clear, but this way I could save myself from potentially missing a comma.

In return, attached you can find language definition for Papyrus that you can use in Notepad++ for syntax coloring and code folding. It is mostly based on language definition from https://github.com/tschilkroete/PapyrusPlusPlus, but with my tweaks and additional keywords. You can import it by selecting: Language -> Define your language -> Import, and restarting Notepad++. Should make code somewhat more readable. You can tweak the colors to your liking in Define your language menu.
1623591785259.png
 

Attachments

  • papyrus_otik_white.zip
    5.2 KB · Views: 2
The way I've been testing it is by copying the relevant functions in ResourceManager then modifying the copies so all function calls and variables point back to the ResourceManager.pex. Then I can make whatever changes I need to for testing.

I have it set up with an esp. I've attached the esp, the .pex files and the original source files.
I've tried to comment my scripts to make it a bit clearer.

Originally, I was trying to make an item that you can craft at a cooking station so when you ate it, it called a setup function in my TestResources quest script, where I could show a menu or something. I couldn't get it to call the function in the quest script reliably, so in the end I gave up and just called the functions from the console. If you know how to get it to work, let me know.
 

Attachments

  • TestResources.zip
    13.5 KB · Views: 0
I've put on your language definition lticskypi. It's great, but I periodically have this problem where the editor decides everything below a certain line is a comment for no reason. If I save the file, close it and reopen it, everything is fine. It's also contagious - if I backspace at the start of the word "return" in line 29 until it joins line 28, line 28 is then all commented as well.
1623656982126.png
EDIT : don't worry, it seems to fix itself if I collapse that block and open it again. Still a little annoying though.
 
Last edited:
I have another possible correction. In the HUD, the daily change for Scrap and Building Materials etc does not include any costs, so may not be what the change in resources below it add up to. This is because when GetSpecificDailyCost is called on Scrap or Building Materials, it returns no costs (costs only seem to be stored on individual materials, not categories). The following code, or something like it at the top of the GetSpecificDailyCosts function would cause it to return the total costs in these categories correctly.
1623667135800.png
RMQuest should actually be ResourceManager in the original function. I just use RMQuest in my test code.
I have only tested this on the complex resources option (or whatever it is called), but I think it would be the same on any setting, as I think costs are always stored by raw materials, even when the easier settings are applied.
My next project is why the info box tells me a house makes 12 caps, when the asam says it only makes 6 ...
 
I think its an issue with Notepad++ I get that a lot when cutting/pasting. If you click (menu) language -> your custom def, the syntax coloring will correct itself. Its a PITA, but I have not found a better solution. Overall I think VS Code is better (also has a language def), but NP++ is more intuitive and easier to use. (subjective lol)

Here, have DailyUpdate with comments:
 

Attachments

  • ResourceManager_DailyUpdate.psc
    11.1 KB · Views: 2
If you know how to get it to work, let me know.
Create a settings holotape:
To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.
Make a global variable (to toggle with the holotape) and a new script. We'll call it TestResourceManager and should look something like this:
Code:
Scriptname NameSpace:TestResourceManager extends SimSettlementsV2:Quests:ResourceManager

GlobalVariable Property TestTogggle Auto Const

Function DailyUpdate()
    if ( TestTogggle.GetValue() > 0.0 )
        ; your test version of DailyUpdate here
    else
        Parent.DailyUpdate()
    Endif
EndFunction
NameSpace can be whatever. Attach this script to SS2_ResourceManager quest. Save this as a new esp. (actually save first and often if you are using the CK) You should be able to turn your test code on and off in game.

You can also use the created holotape to call functions directly. You will have to setup the script as a property in the terminal fragment. NameSpace:TestResourceManager Property TestResourceManager Auto Const Then in the fragment for the terminal menu you can call your function. TestResourceManager.MyTestFunction() with MyTestFunction defined in the NameSpace:TestResourceManager script.

By making your test script a child of ResourceManager your test script will inherit all the functions, events and properties of the parent.
 
Thanks msalaba. I think I understand about plot costs now and why they are not included in DailyUpdate. I've edited my original post.
This explains the problem people are having with storage filling up and them getting cascade failures. Since the plot costs are not done during the DailyUpdate (presumably to work out if each plot should continue functioning), they must subtract their cost directly from the store. I assume this runs after the DailyUpdate, so it has had a chance to add items to the store first (otherwise a plot could crash right before the resources it needs are added). However, when the virtual storage is full, the materials this plot needs to function could be thrown out as excess before the plot attempts to cover costs, so the plot crashes even though enough of that resource is being produced.
A solution to this is have a record of everything that has been thrown out (because virtual storage is full) in each settlement in the DailyUpdate. Then plots should attempt to take their costs from this before trying to take it from the actual virtual storage. That way, as long as you produce enough of that item, your stored amount will not go down and your plots won't crash.
I think the ability to throw away items in the virtual storage and either have the option to replace it with others from the "thrown out" record or have a priority system for what order resources are added that can be set by the user is an absolute must going forward.
 
The settings holotape stuff is useful, but not quite what I was going for unfortunately (although the toggling idea is nice). I was trying to make it so with the press of a button (which eats a favourited item), code in my quest script runs. As it is, I just have the function hot keyed using FO4HotKeys.

Call me a noob, but I didn't realise I could just overwrite the original function. If I do that, does that mean my function gets called by SS2 instead of the original? If so, I like it! Could you use it to overwrite event calls as well? That would be useful for testing the problem of workshop objects still leaving their costs behind after they are removed.
 
When extending a script, the child script will have priority over the parent.
Also, IIRC, you can attach a script to an ALCH object. (ingestible)
 
Yep, you can attach the script straight to it. I didn't really need to have it in a quest, except that I already did and couldn't be bothered changing it .. :grin
I've tried overriding the OnWorkshopObjectDestroyed event (copying and pasting the entire function name line from ResourceManager), but it didn't work - it wasn't called when an object is removed. This may be because I am copying from a decompiled script so something isn't matching up? If I register the event in my script it calls it fine.
 
Thanks for looking into this! It's on my list to be addressed for next patch, it's a pretty deep change that might have consequences elsewhere, so I'll definitely want to post it in public beta to get some feedback before then.
 
I've tried overriding the OnWorkshopObjectDestroyed event
Custom and Remote events are only received by the scripts that register for them. They are not inherited by children.
 
That's what I thought. But this line in the documentation on creationkit.com got me thinking :
If a function or event is implemented in the parent, and you implement it in the child as well, then the child one overrides the parent, and any calls to that function or event will use the child's version instead.
Either I'm reading that wrong or it's poorly written.
EDIT : It could be written clearer, but I think it means the event is called, if it is registered in the new script.
 
Last edited:
Ah msalaba ...
Attach this script to SS2_ResourceManager quest. Save this as a new esp. (actually save first and often if you are using the CK) You should be able to turn your test code on and off in game.
You didn't say anything about having to fill all the properties again. When I tried this after attaching the script the properties window came up asking me to fill the dozens of properties in the original script ... did I do it wrong?
 
If a function or event is implemented in the parent
The key detail missing is NATIVE. Only native Events are inherited by the child script.
Code:
Scriptname myScriptParent extends ObjectReference

Event OnRead()
    ; I am a native event so I do not need to be registered
EndEvent

Quest.OnStageSet(int auiStageID, int auiItemID)
    ; I am not native so I need to be registered to get events
    HandleOnStageSet(auiStageID, auiItemID)
EndEvent

Event OnInit()
    ; register so I can receive this event   
    RegisterForRemoteEvent(Quest, "OnStageSet")
EndEvent

Function HandleOnStageSet(int auiStageID, int auiItemID)
    ; I moved the event to a function so the child can override me
EndFunction
So, if a child is created:
Code:
Scriptname myScriptChild extends myScriptParent

Quest.OnStageSet(int auiStageID, int auiItemID)
    ; I will need to be registered even though my parent is
    ; I will not be able to override my parent.
    HandleOnStageSet(auiStageID, auiItemID)
    ; since HandleOnStageSet is called by this event on the parent, I do not need this event and can modify HandleOnStageSet instead.
EndEvent

Function HandleOnStageSet(int auiStageID, int auiItemID)
    ; I can now override the parent!
    ; do stuff
    ; I still want the parent version to run
    Parent.HandleOnStageSet(auiStageID, auiItemID)
EndFunction
Hopefully, that gives you the basic idea of how things work.
As for the properties, use the easy button. Open your mod in xEdit and copy the properties from SS2.
If you have the CK ini setup to allow multiple editors, load SS2 in one and your mod in another. You can copy/paste the properties.
 
You didn't say anything about having to fill all the properties again.
Wait, did you define them in the child script? You do not need to do that. Only define properties you need for the child script, all the parent properties are inherited.
 
Top