The problem#
Continuing from the past two weeks, in my work on the Pacifist Factorio mod, I noticed there were rich text icons for military-related entities that I thought the mod had removed from the game. By "rich text icons", I'm referring to the dialog that some text boxes in the game (e.g. for naming a train stop) have a button to bring up which shows icons that can be inserted into the text box which include all of the items in the game along with a few other things. In that dialog, there were icons for things like biter corpses despite biters having been removed from the game.
The solution#
This PR, which is included in the latest version of Pacifist, hides all of the icons related only to items that have been removed or hidden by Pacifist.
The details#
Extra rich text icons#
Browsing around one thing I noticed was that with Pacifist enabled there were some rich text icons related to things that the mod had removed from the game like combat robots and remnants of buildings. Strangely, some of these icons didn't appear when Pacifist wasn't enabled, apparently getting added to that dialog due to the entities that referenced them being removed (e.g. gun turret remnants showing up when gun turrets were removed). Since icons seemed to appear once they no longer had anything referencing them, I figured I could fix that by implementing a kind of garbage collection algorithm, looking at what things Pacifist removed and what they were referencing and removing them if they were the last reference.
Identifying references#
There were a few problems with this plan. The first is that while
Factorio does have a well-defined concept of a reference with
EntityID
and similar types, from the point of view of
the mod code, they're all just string
s. So either I had to somehow
explicitly specify which string
s are which kind of reference—which
I didn't want to do—or treat any string
as possibly being a
reference, which could be an over-approximation (and therefore result
in not deleting objects that should be deleted). I chose the latter on
the assumption that such mistakes would be rare, and, after all, the
worst case is extra icons in the rich text dialog that maybe need to be
manually added to the list of objects to remove.
Tracing garbage collector#
So I implemented an algorithm that was essentially a simple tracing garbage collector. It scanned all of the objects and noted down which ones had no possible references. Then after the rest of the Pacifist logic had run and removed things, it checked again and removed anything that was newly lacking references. Then it repeated that scan removing anything that was no longer referenced due to its previous pass until it found nothing left to delete.
It seemed to more or less do the right thing. It did reveal a couple entities that I needed to explicitly hide as they really were still used, but other than that it worked fine without other mods.
Improving performance#
On the other hand, the developer of Pacifist expressed concern that the multiple passes could be a performance problem for mods that add a lot to the game, so I rewrote the algorithm to be more like a reference counting garbage collector. By adding some bookkeeping of which objects referenced which other objects in both directions as well as which objects were deleted, the full pass over all of the data only had to happen once, which resulted in a measureable improvement in performance.
Mod compatibility problems#
Unfortunately, that algorithm ran into problems with some mods. The
first issue was that DamageTypeID
is sometimes stored
in properties named type
which I had been ignoring for considering
references because most properties named type
are names of types or
prototypes and the latter share names with entities, so I didn't think
type
properties should count as references. This is difficult to
resolve in general without more precise type information, so I just
added an exception to my algorithm for damage types to work around the
issue.
But that wasn't the main mod incompatibility problem. Unsurprisingly, scripts in mods tend to assume the entities defined by the same mod actually exist. And by deleting them, Pacifist was causing the mod code to fail. That discovery led to the final version of the algorithm, which was actually a small change: instead of deleting everything, just mark things as "hidden". Then mod scripts can reference the objects since they stil exist in the game code, but they won't show up in the interface to the player, satisfying the goal of getting the icons out of the rich text dialog.
Comments
Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.
There are no comments yet.