jptrrs / HumanResources

A technology overhaul for RimWorld
MIT License
17 stars 12 forks source link

Missing bookshelf on load #168

Open voschvon opened 2 years ago

voschvon commented 2 years ago

Issue : Bookshelf are not spawned on save load Step to reproduce : drop herbal medicine on bookshelf, save and reload Cause : seems like it's caused by a null pointer exception on spawning bookshelf, when trying to iterate a non book object in the inner list of the bookshelf container.

https://gist.github.com/voschvon/a8a5c096797a5d49138cc105dd8f818a

removing the medicine from the list solves the issue

Relevant log : https://gist.github.com/voschvon/599210a2c4938d47042f81911eaf1b30

hanssun07 commented 2 years ago

Same issue, this time with a fine meal, with same solution through modifying the save file.

I don't know how to set things up to test it myself, but I think this can be fixed by adding a check to the loop in Building_Bookstore.SpawnSetup() to first make sure that book actually has the def TechBook before trying to unlock the tech inside.

jptrrs commented 2 years ago

I cannot reproduce the issue. Are you running any other mods? Please follow these instructions for reporting issues: https://steamcommunity.com/workshop/filedetails/discussion/2119687603/2295094308095765898/

MorpheusAk commented 2 years ago

Same issue. Here are the hugslib file, and a reference to the exception:

https://gist.github.com/HugsLibRecordKeeper/ebdb994b3ad586d721465d119883b142

Exception spawning loaded thing BookShelf71368: System.NullReferenceException: Object reference not set to an instance of an object at HumanResources.Extensions.TryGetTech (Verse.Thing book) [0x00028] in :0 at HumanResources.Building_BookStore.SpawnSetup (Verse.Map map, System.Boolean respawningAfterLoad) [0x00037] in :0 at (wrapper dynamic-method) Verse.GenSpawn.Verse.GenSpawn.Spawn_Patch7(Verse.Thing,Verse.IntVec3,Verse.Map,Verse.Rot4,Verse.WipeMode,bool) at (wrapper dynamic-method) Verse.GenSpawn.Verse.GenSpawn.SpawnBuildingAsPossible_Patch1(Verse.Building,Verse.Map,bool) at (wrapper dynamic-method) Verse.Map.Verse.Map.FinalizeLoading_Patch3(Verse.Map) UnityEngine.StackTraceUtility:ExtractStackTrace () (wrapper dynamic-method) Verse.Log:Verse.Log.Error_Patch3 (string) (wrapper dynamic-method) Verse.Map:Verse.Map.FinalizeLoading_Patch3 (Verse.Map) (wrapper dynamic-method) Verse.Game:Verse.Game.LoadGame_Patch10 (Verse.Game) (wrapper dynamic-method) Verse.SavedGameLoaderNow:Verse.SavedGameLoaderNow.LoadGameFromSaveFileNow_Patch3 (string) Verse.Root_Play/<>c:b1_1 () (wrapper dynamic-method) Verse.LongEventHandler:Verse.LongEventHandler.RunEventFromAnotherThread_Patch0 (System.Action) Verse.LongEventHandler/<>c:b27_0 () System.Threading.ThreadHelper:ThreadStart_Context (object) System.Threading.ExecutionContext:RunInternal (System.Threading.ExecutionContext,System.Threading.ContextCallback,object,bool) System.Threading.ExecutionContext:Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object,bool) System.Threading.ExecutionContext:Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object) System.Threading.ThreadHelper:ThreadStart ()

jptrrs commented 2 years ago

Thanks for the log, MorpheusAk, but you were running over 600 mods. It's impossible to pinpoint the cause for ANY issues under those conditions. Please, follow the instructions on our steam page, link on my last comment.

MorpheusAk commented 2 years ago

Not sure if there was a mod interaction involved or not. Could've potentially been a hauling or inventory mod I guess. Anyways, the problem was feces. I literally had fecal sludge in my bookshelf. I used voschvon's save editing method to fix the problem, and now I'm good to go. Thanks, guys =D

jptrrs commented 2 years ago

Not sure if there was a mod interaction involved or not. Could've potentially been a hauling or inventory mod I guess. Anyways, the problem was feces. I literally had fecal sludge in my bookshelf. I used voschvon's save editing method to fix the problem, and now I'm good to go. Thanks, guys =D

Well, I can't reproduce the issue, so it's gotta be a mod conflict.

voschvon commented 2 years ago

Sorry, it seems like I can't reproduce the issue as well, using only vanilla + the dependencies. Unfortunately my rimworld saves got wiped out, so I can't check the modlist that was used.

I can't reproduce how the non book got into the inner list, but if it somehow does, it will cause the issue. You can try adding the non book item to the innerList manually on the xml to reproduce the issue.

jptrrs commented 2 years ago

Sorry, it seems like I can't reproduce the issue as well, using only vanilla + the dependencies. Unfortunately my rimworld saves got wiped out, so I can't check the modlist that was used.

I can't reproduce how the non book got into the inner list, but if it somehow does, it will cause the issue. You can try adding the non book item to the innerList manually on the xml to reproduce the issue.

I'll only ever spend time on this if the issue is confirmed and its causes are clear. I'm leaving this open for now just in case someone finds it. Hopefully, with enough care to follow the instructions I layed out and actually provide the information we need.

voschvon commented 2 years ago

Alright, I'll let you know if I found the clear cause, thanks.

Vladorio commented 2 years ago

Same issue. By my observations, most likely connected with unload inventory items behavior (Pick Up And Haul mod). Pawn drop any item (probably next item in unload order, usually peace of resource) into bookshell instead of book he wanted to put in (book stays in inventory). So bookshelf disappear on reload.

jptrrs commented 2 years ago

"Most likely" it's not enough. We need accurate information before any issue can even be adressed. And that's the bare minimun. Please follow these instructions on how to gather the necessary information: https://steamcommunity.com/workshop/filedetails/discussion/2119687603/2295094308095765898/

Eumenes99 commented 2 years ago

I have the same problem here. The bookshelf disappears when loading. Could anyone tell me how to find the location of the bookshelf in the save file?

MorpheusAk commented 2 years ago

If you try to load a save where the bookshelf has bad data, then the bookshelf won't load, and then if you save that file, there will be no bookshelf, so you need a save where the bookshelf is still there. Make a copy of the save file. Then open it with a text editor. Search for "bookshelf." You'll find several references. You're looking for one that looks like, "Bookshelf13573", except that the numbers at the end will be random five numbers that identify your particular broken bookshelf. I think it will be nearer to the end of the document. You're looking for an instance that belongs to the code which describes the broken bookshelf and what's within it. It will have several groups of lines of code which make up items in the list of things that the bookshelf contains. Each item starts with a "li" tag, and ends with a "/li" tag (They're in brackets). You want to find the item that is not a book, and then delete everything from the "li" tag to the "/li" tag. Then save the document, and load the altered savefile, and if you did it right, the save should load the bookshelf, and you're good to go.

Eumenes99 commented 2 years ago

If you try to load a save where the bookshelf has bad data, then the bookshelf won't load, and then if you save that file, there will be no bookshelf, so you need a save where the bookshelf is still there. Make a copy of the save file. Then open it with a text editor. Search for "bookshelf." You'll find several references. You're looking for one that looks like, "Bookshelf13573", except that the numbers at the end will be random five numbers that identify your particular broken bookshelf. I think it will be nearer to the end of the document. You're looking for an instance that belongs to the code which describes the broken bookshelf and what's within it. It will have several groups of lines of code which make up items in the list of things that the bookshelf contains. Each item starts with a "li" tag, and ends with a "/li" tag (They're in brackets). You want to find the item that is not a book, and then delete everything from the "li" tag to the "/li" tag. Then save the document, and load the altered savefile, and if you did it right, the save should load the bookshelf, and you're good to go.

That's why I couldn't find it... I guess I need to start over again then. Thank you!

hernantas commented 2 years ago

This also happens to me, I think this is because of another mod or incompatibility with something when storing items.

I tried to dive into the save files since I still have a lot of autosave and found this:

<thing Class="HumanResources.Building_BookStore">
  <def>BookShelf</def>
  <id>BookShelf55681</id>
  <map>0</map>
  <pos>(167, 0, 62)</pos>
  <rot>1</rot>
  <health>65</health>
  <stuff>WoodLog</stuff>
  <faction>Faction_33</faction>
  <questTags IsNull="True" />
  <innerContainer Class="Verse.ThingOwner`1[Verse.Thing]">
    <innerList>
      <li Class="ThingWithComps">
        <def>TechBook</def>
        <id>TechBook169943</id>
        <pos>(164, 0, 56)</pos>
        <health>50</health>
        <stackCount>1</stackCount>
        <stuff>Tech_Smithing</stuff>
        <questTags IsNull="True" />
        <CommonSenseWasInInventory>True</CommonSenseWasInInventory>
      </li>
      <li Class="ThingWithComps">
        <def>Pemmican</def>
        <id>Pemmican195698</id>
        <health>60</health>
        <stackCount>75</stackCount>
        <questTags IsNull="True" />
        <rotProg>142311.5</rotProg>
        <ingredients>
          <li>Meat_Horse</li>
          <li>RawPotatoes</li>
          <li>Meat_Duck</li>
        </ingredients>
      </li>
      <li Class="ThingWithComps">
        <def>Pemmican</def>
        <id>Pemmican195773</id>
        <health>60</health>
        <stackCount>75</stackCount>
        <questTags IsNull="True" />
        <rotProg>57343.34</rotProg>
        <ingredients>
          <li>Meat_Duck</li>
          <li>RawPotatoes</li>
        </ingredients>
      </li>
      <li Class="ThingWithComps">
        <def>Pemmican</def>
        <id>Pemmican195853</id>
        <health>60</health>
        <stackCount>33</stackCount>
        <questTags IsNull="True" />
        <rotProg>56000</rotProg>
        <ingredients>
          <li>Meat_Duck</li>
          <li>RawPotatoes</li>
        </ingredients>
      </li>
      <li Class="ThingWithComps">
        <def>RawPotatoes</def>
        <id>RawPotatoes195889</id>
        <health>60</health>
        <stackCount>28</stackCount>
        <questTags IsNull="True" />
        <rotProg>304271.1</rotProg>
      </li>
      <li Class="ThingWithComps">
        <def>RawHealroot</def>
        <id>RawHealroot195919</id>
        <health>49</health>
        <stackCount>75</stackCount>
        <questTags IsNull="True" />
        <rotProg>107723.3</rotProg>
      </li>
      <li Class="ThingWithComps">
        <def>TechBook</def>
        <id>TechBook199669</id>
        <pos>(166, 0, 60)</pos>
        <health>50</health>
        <stackCount>1</stackCount>
        <stuff>Tech_RS_MedievalStorage</stuff>
        <questTags IsNull="True" />
        <CommonSenseWasInInventory>True</CommonSenseWasInInventory>
      </li>
      <li Class="ThingWithComps">
        <def>TechBook</def>
        <id>TechBook202795</id>
        <pos>(166, 0, 60)</pos>
        <health>50</health>
        <stackCount>1</stackCount>
        <stuff>Tech_Brewing</stuff>
        <questTags IsNull="True" />
        <CommonSenseWasInInventory>True</CommonSenseWasInInventory>
      </li>
    </innerList>
  </innerContainer>
  <storageSettings>
    <priority>Critical</priority>
    <filter>
      <disallowedSpecialFilters>
        <li>AllowCorpsesColonist</li>
        <li>AllowCorpsesStranger</li>
        <li>AllowCorpsesSlave</li>
      </disallowedSpecialFilters>
      <allowedDefs>
        <li>Tech_PsychoidBrewing</li>
        <li>Tech_TreeSowing</li>
        ...omitted
      </allowedDefs>
      <allowedHitPointsPercents>0~1</allowedHitPointsPercents>
      <allowedQualityLevels>Awful~Legendary</allowedQualityLevels>
    </filter>
  </storageSettings>
</thing>

As you can see on <innerList>, the bookshelf contains items that are not tech books which are weird. Somehow pawns or something can store non-tech books on the bookshelf. My assumption is that this cause the bookshelf contains bad data thus making the bookshelf disappear.

My suspicion is that it's not this mod that causes this, it's LWM Deep storage which makes pawn can store multiple items on a shelf but I'm not sure.

Update

After some testing with minimum load order, I think there's a bug in either storing (hauling) jobs or shelf container configuration.

While using mods that can pick up multiple items to inventory such as "Pick Up And Haul", when a pawn trying to store tech books on a bookshelf and has other items in the inventory, unloading cause that pawn to begin storing other items even if those items shouldn't be stored on the bookshelf. In my case, it was "potatoes", "heal roots", etc...

This does not happen with other storage even with "LWM's Deep Storage" which can also contain multiple items on a tile.

To reproduce

Must have a mod that cause pawn to add hauling items to inventory such as "Pick Up And Haul"

  1. Create a stockpile which accepts all items
  2. Order pawn to haul other items first
  3. Once pawn done picking up items to inventory and began walking to stockpile, force them to haul tech book to "bookshelf" while maintaining picked items on pawn inventory.
  4. Immediately delete the stockpile (but not the bookshelf). This will force the pawn hauling the book to the bookshelf instead of the stockpile which is somehow ignored even on critical priority.
  5. When pawn begin hauling tech books to the bookshelf, create a new stockpile which accepts all items to prevent the pawn from dropping its inventory.
  6. Watch pawn unloading all of its inventory (except equipment) to the bookshelf.

Note that this might takes several times to reproduce. But what you want to do is basically:

  1. Force pawn to pick up items to haul. The items will have their drop icon red (marked for hauling?)
  2. Force pawn to haul tech book to bookshelf while still have other items.
  3. Watch pawn unloading all of its inventory to the bookshelf. Step 5 above is required since otherwise, the pawn will unload other items on the ground.

There are no errors when unloading items to the bookshelf but if you try to open the bookshelf with corrupted "innerThings", you will get an error pretty much the same error as this issue post.

jptrrs commented 2 years ago

To reproduce

Must have a mod that cause pawn to add hauling items to inventory such as "Pick Up And Haul"

1. Create a stockpile which accepts all items

2. Order pawn to haul other items first

3. Once pawn done picking up items to inventory and began walking to stockpile, force them to haul tech book to "bookshelf" while maintaining picked items on pawn inventory.

4. Immediately delete the stockpile (but not the bookshelf). This will force the pawn hauling the book to the bookshelf instead of the stockpile which is somehow ignored even on critical priority.

5. When pawn begin hauling tech books to the bookshelf, create a new stockpile which accepts all items to prevent the pawn from dropping its inventory.

6. Watch pawn unloading all of its inventory (except equipment) to the bookshelf.

Note that this might takes several times to reproduce. But what you want to do is basically:

1. Force pawn to pick up items to haul. The items will have their drop icon red (marked for hauling?)

2. Force pawn to haul tech book to bookshelf while still have other items.

3. Watch pawn unloading all of its inventory to the bookshelf. Step 5 above is required since otherwise, the pawn will unload other items on the ground.

There are no errors when unloading items to the bookshelf but if you try to open the bookshelf with corrupted "innerThings", you will get an error pretty much the same error as this issue post.

That's what I'm talking about! I would only need the ctrl+F12 log for when that happens now. Errors or no errors, that's still vital information. Thx!

rimpy-custom commented 2 years ago

Tried to reproduce issue (used mentioned steps) and got this HugsLib log: https://gist.github.com/c757e84332cba6a48dc4b6f9b87679fb No errors appear but book bookshelf got all items book + survival meals. In ma case that was survival meal. Screenshot: https://imgur.com/68nrKxT HugsLib log after loading saved game: https://gist.github.com/2feba6dbdfc9793ce1342479f919c892 Screenshot of error: https://imgur.com/z1EhV23

thailyn commented 1 year ago

@jptrrs , respectfully, I think you're focusing on the wrong thing here. Yes, it is important to understand how non-TechBook items are dropped on or put into the bookshelf. And, yes, there is not much point in you investigating this on your own when it is most likely due to a mod conflict, or a mod making a bad decision and leading to the situation being described here.

However, it is a rare situation, and a difficult one to catch at that. It's really only noticed after the game is saved and subsequently loaded, and even then it might not be noticed right away. But when it does happen, it is incredibly frustrating for the player, as the "best" solution for this situation is to manually edit the save file they had loaded, and then load that file again. And that's only possible if the save wasn't overwritten by reusing the same save file.

So, yes, there is a bug somewhere -- in this mod or in another one -- that is leading to the items being dropped on the bookshelf. And maybe one day we can conclusively identify and fix it. But there is another bug that we know is in this mod: the loading process for this mod is brittle; it makes assumptions that aren't true. That is, you should not assume that only TechBooks are in the contents of the bookshelves. This is something you can easily fix with a little defensive coding and being more careful to avoid NullReferenceExceptions. Do whatever you need to do so data in the save file -- and potentially a lot of player progress, time, and effort -- is not lost in a frustrating way. It doesn't solve everything, but will make the player experience so much better.

Also, I mentioned it is unreasonable for it to be your responsibility to recreate and identify the bug. And that's true. But you can also help players investigate the issue, given how elusive it is. I'm still learning about RimWorld C# modding, but I presume you could add in some checks when an item is added to the bookshelf and, if it is not a TechBook, make a stink to the player so they can have a larger chance of identifying the cause. If you don't want to be obnoxious to every player who uses the mod, put it behind a "debug mode" option or something. And if it's not possible to reactively catch this situation, you could just poll the contents of the bookshelf every... long tick or whatever. And put that behind a debug mode option, too. I know I'd switch on such an option to help investigate the bug, even if it had a performance penalty.