RimWorld

RimWorld

LightsOut
Performance issues
On a fairly large mod list of 300 mods, but mostly of pawn behavior adjustments ("QoL") and very few content mods, this causes my game to freeze on a quick dev test start for a good 1s-3s depending on how large a structure I build.

Large strings of walls across the map causes a 3s-5s freeze.

Disabling all but this mod, harmony, dubs perf analyzer, and all dlcs, this mod sadly still causes noticeable micro-hitching when placing anything on the map. It's far less than 1s, but it's still very noticeable.

However, it only seems to apply to anything spawned outside of a room anywhere on the map.

Using Dub's perf analyzer the culprit seems to be DisableThingsInRoomOnSpawn and FixLightsonRoomSetup, with a root culprit of Common.Glowers:GetGlower.

If I create a fairly large room but much smaller than the whole map, placing similar long strings of walls just inside the room causes no lag or performance issues, the patches are much faster and totally negligible.

It's as if the patches are catching the entire map, and one of them or even both of them are looping through the entire map?

I think it'd be best if both patches outright ignore anything spawned outside of a room
Last edited by Twinki; 3 Aug @ 4:39pm
< >
Showing 1-5 of 5 comments
juanlopez2008  [developer] 9 Aug @ 9:32pm 
Well, there's at least one oversight exposed here: DisableThingsInRoomOnSpawn and FixLightsOnRoomSetup are identical patches. We only need one of those two, and removing one of them will help a little.

I can also be better about the caching I do: right now each individual light/bench/anything you build checks to see if it's a bench or light individually right when it spawns, and we cache the result of that check to use next time since that's better for performance than running all the checks again. Instead, I can run the checks the first time and cache it based on the building's def instead of the building itself. Since all buildings of the same type (e.x., Standing Lamp, Wooden Wall) all share the same def, we would never need to run the checks again for that def. This will help reduce some work being done every time something is built.

If you'd have some time soon, I'd be happy to work with you to see what other things we can do to help performance. I don't see any hitching in my testing, but I suspect that it's just my PC specs masking issues like this.
Twinki 9 Aug @ 10:22pm 
Sure!

I'll mention that there was a IEnumerable loop being the root culprit of the long execution time on the patches.

To me, without digging much into the source or really knowing much about RimWorld mods, it seems like the patches are trying to disable/enable lights whenever something is built (really, spawned in), but briefly looking over the source it doesn't look like those patches check to see if the "room" something spawned in is the "outside map".

So they're spending a lot of time looping through the entire map looking for lights.

Personally, I don't think the mod should care about the lights on the entire map.. only lights in a proper "enclosed" room.

EDIT: Make sure you're testing this on the latest Harmony version, two weeks ago this wasn't an issue.. at all, but it suddenly became one after updating Harmony.
Last edited by Twinki; 9 Aug @ 10:24pm
juanlopez2008  [developer] 10 Aug @ 12:02am 
Rooms shouldn't be spawned outside of the current map from my understanding; if you load another map (e.x., for a raid) then rooms will be spawned in at that time, but not before then since the map hasn't been generated yet.

Ultimately, any time something is built in the game, the region they occupy is marked as dirty; regions are smaller than rooms, and you can enable the "Draw Region Dirties" debug display to see this in action. This happens in RegionDirtyer.DirtyRegionForThing. At some point in the near future, something requests the room that something is in and forces the game to evaluate the dirty regions to ensure that all rooms are up to date (RegionAndRoomUpdater.TryRebuildDirtyRegionsAndRooms and eventually RegionAndRoomUpdater.CombineNewAndReusedDistrictsIntoContiguousRooms).

After combining the regions into "region groups" (which appear to be temporary data structures analogous to rooms, RegionTraverser.FloodAndSetNewRegionIndex), the game then attempts to recalculate all rooms on the map using the new "region groups" that were affected by the dirty regions (RegionAndRoomUpdater.CreateOrAttachToExistingRooms). At this point the game inspects the rooms associated with the regions and considers a room change to have happened if: at least one region group contains regions that were previously part of two different rooms (e.g., a wall was removed); or, a region group has no current associated room (e.g., the last wall was placed, creating a new room whose regions are new and completely isolated from existing rooms). If a room change has happened, RegionAndRoomUpdater.FloodAndSetRooms is called on the room that changed (not all rooms).

The patches called out above postfix FloodAndSetRooms, which will only be called on the rooms that actually changed; notably, the "outdoors" of the map is a room and the code will run there. Running the code on the outdoor rooms is a requirement, since we want those lights to be on at all times -- and this behavior is why removing a wall will cause previously "on standby" lights to suddenly turn on. This does mean that the room changes force a full refresh of the lights in both affected rooms, which unfortunately requires looking through all contained and adjacent things in both rooms to see if any are lights. Fortunately, that information is cached from when the thing was first constructed, so the lookup isn't expensive and the O(n) search for lights shouldn't be that big of an issue.

One area to improve would be to check whether a light is already enabled/disabled before trying to enable/disable it. That would save some work in that we could prevent enabling/disabling glowers (which can be expensive). I saw a measurable performance gain in this case, but I'm uncertain that it's the normal case.

Probably unrelated, but I am noticing that removing a wall in a room (thus making it "outside") no longer re-enables the light, which isn't how it's supposed to work.
Twinki 19 Aug @ 5:27pm 
Popping in, got distracted with BF6

I've tested your most recent changes, and I definitely feel an improvement but there's still some pretty significant freezing & hitches when building long strings of walls not constrained in a room on a quick dev test world.

The longer the wall, the bigger the hitch. Hitching / freezing has been greatly reduced though and is very much playable again when playing normally.

https://i.imgur.com/LevXrk0.png
https://i.imgur.com/uDwK73b.png
https://i.imgur.com/qp5LsRW.png

It's possible you've hit a point where not much can be done, but I wanted to post anyway if you have any epiphanies on things to optimize further.
juanlopez2008  [developer] 19 Aug @ 7:04pm 
Yeah, those are some ugly numbers and I can see how those would become hitching. I have a couple more modifications I was able to make that I was hoping to send your way before pushing it to the workshop for everyone (I just need to find time to upload the DLL for you to test).

If you don't mind me asking what are tour specs? Are you using Windows?

Unfortunately it is pretty close to the end of the rope as far as tuning goes, I think. A lot of it comes down to the way I chose to structure the mod, which cant be helped without rewriting it. I've been slowly chipping away at trying to get a V2 of LightsOut running but progress has been a little stalled since I'm short on free time. It does look promising though from what I've been experimenting with.
< >
Showing 1-5 of 5 comments
Per page: 1530 50