RimWorld

RimWorld

Stack Merger
Tizferatu 4 Jun, 2018 @ 10:59am
Bug with picking up/dropping onto same stack (infinite loop until interrupted)
Fromt he comments for context:
Fluffy"
@tizuby; interesting, that sounds like a new situation. I wouldn't mind some fresh eyes looking at the code, and you don't even have to crack open the assembly, as it's all on GitHub!

The relevant bits are found here;
https://github.com/FluffierThanThou/StackMerger/blob/master/Source/StackMerger/WorkGiver_StackMerge.cs
https://github.com/FluffierThanThou/StackMerger/blob/master/Source/StackMerger/ListerStackables.cs "

I see two potential issues, but do also need some clarification.

1) I don't see anything explicitly preventing a stack being chosen to "merge" with itself. It looks as though it's possible. Please do point me towards any lines that would prevent this case from happening. But from my brief check there, it looks like essentially a stack can be both a source and destination at the same time. Assuming both target and thing in that method are stacks.

Also the comments don't jive with the code for the following

// only move stuff to larger stacks
// should stop situation with stacksize mods
// where pawns keep going back and forth between stacks
&& target.stackCount >= thing.stackCount
Shouldn't be using greater than or equal if you want it to only go to greater than.

That method should also maybe chuck in an "&& target != thing" (assuming both target and thing are stacks. If they are this method would accept target and thing as being the same stack and return true).

2) How does the process work in full - is it "scan for mergers, select stack A and send to stack B" or is it "go pick up from stack A and then figure out where to stack it"? As in is the full job an actual pick up and delivery, or is it a pick up and then figure out where to deliver?

Basically what I'm getting at is that if it first picks up the item and then decides where to move it (which I'm hoping/don't think is the case) then it could be choosing the stack it just picked up from to drop off.

I'm hoping the process isn't interrupted like that and the whole job is "pick up from A and deliver to B" but don't know enough about it.
< >
Showing 1-8 of 8 comments
Fluffy  [developer] 4 Jun, 2018 @ 12:54pm 
Heya, thanks for taking the time to look into this!

First off, SlotGroups are not MonoBehaviours, so the null weirdness does not apply. In fact, pretty much the only part of Unity that RimWorld uses is the event loop and UI, pretty much everything else is custom-made. That said, thanks for pointing me towards this issue, it might be useful in the future.

As for your specific points;
1) You are correct, the comments don't reflect the actual code. The code is intended though, as two equal size partial stacks should still be merged, and whether A -> B or B -> A is not relevant. I'll update the comment.

There is actually a `thing != target` check, it's the first check on line 119 (https://github.com/FluffierThanThou/StackMerger/blob/master/Source/StackMerger/ListerStackables.cs#L119).

I do suspect the problem is here, but I can't figure out the specific scenario where it would occur. With two stacks, I can see no scenario in which the loop can arise. If stack A < B, it will be merged into B, if they are equal, either direction can work. Three or more stacks get more complicated, but I still can't think of a scenario in which a problem arises.

2) Here's a rough outline of the process. In essence, it's the first scenario you outlined (whole job is given at once).
- The game keeps track of items in stockpiles (listerThings), I've hooked the update operations for listerThings to also update my own cache of stackables (listerStackables). In addition, I periodically scan stockpiles to catch changes I've missed for some reason.
- When a pawn is looking for a stacking job, he'll iterate over the items in listerStackables ('PotentialWorkThingsGlobal'), and check if they're still viable ('HasJobOnThing'). A viable thing is 'TheoreticallyStackable' (the thing itself is not forbidden, on fire, partial stack, etc.) and has a valid target (any other stack in the SlotGroup (storage zone/building) 'CanBeStackTarget'). If not viable, it's removed from listerStackables. If viable, a job is handed out to stack 'thing' with 'target'.
Tizferatu 4 Jun, 2018 @ 4:14pm 
Oh yep, totally missed that (I do &&'s on the end of the line instead of the begining).

Maybe chuck some logging code into that method to see what stacks are trying to be merged. If we can sort out what the pawn is trying to do when it gets into one of those loops we can probably sort out a fix for it if that's where it's happening.

Worst case scenario for that is the issue is happening somewhere else in the code, but at least something will be ruled out.

I can really only think, if target and thing inequality check is performing as expected (e.g. there aren't two different Thing objects somehow representing the same stack...though maybe that should be double checked. IIRC != just compares the reference address on reference types) is that something is interrupting the process immediately after pickup that causes the pawn to drop the item...and then select the same job again.

I would think, reading the code, that it should work for any arbitrary amount of stacks as eventually there'll only be one valid stack with the same or more items in it than the pick up stack (though in between it may move stuff around really inefficiently among multiple stacks...but they should always be merging).
Tizferatu 7 Jun, 2018 @ 7:51pm 
Hm, I'm not sure it is what we were thinking. Something else weird is going on.

On a pile of 92 rice it was happening on a "shuttle to stack in fridge (using the fridge mod - this happens with or without that though".

I moved the person and they dropped the 16 they had, then went back to first pile and got stuck again. so I moved her to the second pile, and she got stuck on that one. Out of curiosity I moved her to yet another pile and she got stuck there.

It looks more like maybe the job is starting and being immediately cancelled rapidly?

It's also affecting the same colonist repeatedly.
Last edited by Tizferatu; 7 Jun, 2018 @ 7:52pm
Coomby 14 Jun, 2018 @ 10:30am 
I experienced something extremely similar to what you are explaining. My construction pawn would get stuck in a loop when replacing walls(jt's replace wall mod.)

The wall would be deconstructed but then he would get stuck in a loop . He would go grab the brick blocking the construction and walk to it to the proper location in the stockpile but instead of adding to stack he turn around and go drop it at the source location. I assumed he would repeat process because the source location is blocking his construction, I changed my replacewall mod and it corrected his behavior in that scenario.

I have noticed this occuring in several other situations where one of the stacks was next to an unpassable object. I resolved every incident by deleting an object right next to the location of either the source or destination stack, I did not try this method for the situation above. All of the deleted objects could of been pathed around but the pawn would get stuck in a loop while trying to interact with the stack. Most of them would loop but I had a few who would just stand still with "standing" as their displayed task until a neighboring object that was not obstructing the job was deleted.
Tizferatu 14 Jun, 2018 @ 11:29am 
The issue I'm experiencing isn't tied to passable objects. Happens in the middle of a room or next to a wall, doesn't really seem to discriminate.
Coomby 14 Jun, 2018 @ 12:40pm 
The reason I saw merrit in bringing up the impassable object idea was that I had a steel stack in a field that was causing a loop when attempting to haul it to a stockpile. It had a piece of a fence on one tile next to it. All other 7 tiles around the stack were clear of any obstructions. As soon as I removed the fence the pawns could do everything as intended. The loop created noticeable lag and also looked like the pawns would start the job and cancel the job.

My construction pawn scenario was the most odd as it was delivering to the center of a room in a stockpile and would get stuck in a loop of taking that item back to the location of the wall it deconstructed, which had plenty of space around it.

Take everything I say with a grain of salt as I have little to no code knowledge
Last edited by Coomby; 14 Jun, 2018 @ 2:51pm
Tizferatu 15 Jun, 2018 @ 7:59pm 
Looks like this might possibly be an issue with CE and any mod that does hauling/pickuping stuffs. I've seen reports on others (particularly WM-SFS) that SE can cause pick up/drop loops, particularly with some type of 10 jobs/10 ticks error or something.
MickTheLick 24 Aug, 2018 @ 5:01pm 
I think tizuby could be right and this is an issue with Combat Extended (CE). I was using this mod without issue for a couple of play throughs. In my current play through using CE I'm getting the same behaviours described above
< >
Showing 1-8 of 8 comments
Per page: 1530 50