Closed drok closed 3 years ago
(partial list, there may be others I'm unaware of)
Issue is detected and reported on the Harmony Report as of 6d05eff
Population Demographics and Building Usage have been updated to gracefully handle missing Harmony mod.
Population Demographics and Building Usage have been updated to gracefully handle missing Harmony mod.
Thank you for your quick fix, cheers!
Classes that use HarmonyLib features should not be public, because this causes
ReflectionTypeLoadException
errors andTypeLoadException
errors.Failure mechanism
The game loads mods in 3 phases:
OnEnable()
themThe Harmony Mod assemblies may be loaded at phase 2, but some time after the mod that uses them. This should not matter, because no mods are instantiated until all the assemblies are loaded. If a dependent assembly is a perfect match (ie, matching public key token and culture), it is "borrowed" from the mod that supplies it, to load it into the mod that requires it. The borrowing only happens once, because once loaded into memory, it is used for all mods that need it. If two mods need the same dependency, that dependency will appear on the assembly list of the mod that happened the need it first, and no longer on the assembly list of the supplying mod.
If the match is not perfect (ie, either public key token or culture don't match), then the game cannot load the needed assembly as a leaf in the dependency tree of the mod that needs it. Instead, it would be loaded as a leaf in the dependency tree of the mod that supplies it. The effect is that by the time phase 3 starts, all needed assemblies are loaded.
However, if a mod with the dependency exposes this dependency through a public class (type), then the public class must be resolved when the game AddAssembly due to
GetExportedTypes()
- where it searches for anIUserMod
type. Since the signed dependency is not yet loaded,GetExportedTypes()
throws aTypeLoadException
, and theIUserMod
class is not found, and will not be instantiated later at phase 3.In short, to avoid dependency order problems like this, the depended types must be inside internal or private types, so they do not need to be Resolved/loaded at
AddAssembly()
time.Practical effects
This bug would cause affected mods to crash with
TypeLoadException
and be unloadable if a Harmony mod is not subscribed.The expected behaviour is that mods should not crash, should load, and should either:
How to test if your mod is affected
%LOCALAPPDATA%
. Do not copy the Harmony folder locally.--noWorkshop
.Workarounds
Since this bug is effectively a load-ordering bug, it can be worked around by ensuring Harmony is subscribed and loaded before the affected mod.
Solutions
See the drok/PopulationDemographics@63d2bd9 and drok/PopulationDemographics@708c894 commits for potential ways to fix this issue.