[Any version] Multi-explosion performance can be boosted significantly

Started by Alistaire, March 27, 2020, 05:45:27 PM

Previous topic - Next topic


Setting off several stacks of large-radius explosives is extremely detrimental to performance. Without this fix, the creation of motes provides an incredible RAM throttle. The fix improves performance around hundred-fold during large, consecutive and nearby explosions.


The major cause of this is the following:

EACH Explosion spawns damType.explosionCellMote onto EACH tile, since Explosion.AffectCell(IntVec3 c) calls damType.Worker.ExplosionAffectCell(., ., ., ., bool canThrowMotes) with canThrowMotes = true, whenever ShouldCellBeAffectedOnlyByDamage(IntVec3 c) is true.

The ShouldCellBeAffectedOnlyByDamage check is true for nearly every tile.

This means that in a stockpile full of antigrain mortar shells (don't ask), one mortar shell detonates setting off all other mortar shells. Each explosion spawns EXACTLY THE SAME damType.explosionCellMote on every affected cell, meaning EACH CELL contains upwards of the total amount of mortar shell stacks that have exploded.

Creating a mote on each cell is extremely costly, such that setting off a stack of mortar shells can easily lead to <1 FPS framerates.


The solution to improving performance significantly:

In AffectCell, add the following boolean, here called spawnMote:

var spawnMote = c.GetFirstThing(Map, damType.explosionCellMote) == null;

Then, call the worker with spawnMote && !flag instead of just !flag.

this.damType.Worker.ExplosionAffectCell(this, c, this.damagedThings, this.ignoredThings, spawnMote && !flag);

What results is a nearly- N-fold reduction in motes being created per tick, with N the amount of explosions. As a result, framerates throughout massive antigrain explosions become >>1 FPS, for my old computer even up to 15-30 FPS from ~60 seconds per frame for especially large explosions.