forked from boformer/CitiesHarmony
-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HarmonyLib dependent must not be an exported type #9
Labels
Comments
drok
added a commit
that referenced
this issue
Mar 15, 2021
Mods that are missing dependencies throw the type load exception (TLE) when instantiated or probed by fetching PluginInfo.userModInstance, but the resulting stack trace does not attribute the fault to the mod that caused it. In order to track proper attribution, this commit installs an alternate getter for userModInstance, which reports the offending mod directly when the TLEs are thrown on construction. A mod can still throw TLE during operation, eg, if it attempts to use a class from another assembly that is missing, but that TLE's stack trace will contain the loading mod, and thus will be attributed to it. The Harmony Mod did not handle mods broken this way. This commit fixes the handling of other mods being unable to load due to this bug, catches those TLE exceptions, and adds them to the Harmony Report Fixes issue #9
drok
added a commit
to drok/PopulationDemographics
that referenced
this issue
Mar 17, 2021
… member Fixes issue drok/Harmony-CitiesSkylines#9 which causes the Exception below when the mod is loaded before Harmony, or with Harmony absent. ReflectionTypeLoadException: The classes in the module cannot be loaded. at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (bool) at System.Reflection.Assembly.GetExportedTypes () [0x00000] in <filename unknown>:0 at ColossalFramework.Plugins.PluginManager+PluginInfo.AddAssembly (System.Reflection.Assembly asm) [0x00000] in <filename unknown>:0 UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object) UnityEngine.DebugLogHandler:LogException(Exception, Object) UnityEngine.Logger:LogException(Exception, Object) UnityEngine.Debug:LogException(Exception) ColossalFramework.Plugins.PluginInfo:AddAssembly(Assembly) ColossalFramework.Plugins.PluginManager:LoadDependenciesRecursive(Assembly, Dictionary`2, Dictionary`2, List`1) ColossalFramework.Plugins.PluginManager:LoadDependencies(Dictionary`2, Dictionary`2) ColossalFramework.Plugins.PluginManager:LoadAssemblies(Dictionary`2) ColossalFramework.Plugins.PluginManager:LoadPlugins() Starter:Awake()
drok
added a commit
to drok/PopulationDemographics
that referenced
this issue
Mar 17, 2021
Fixes issue drok/Harmony-CitiesSkylines#9 which causes the Exception below when the mod is loaded before Harmony, or with Harmony absent. ReflectionTypeLoadException: The classes in the module cannot be loaded. at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (bool) at System.Reflection.Assembly.GetExportedTypes () [0x00000] in <filename unknown>:0 at ColossalFramework.Plugins.PluginManager+PluginInfo.AddAssembly (System.Reflection.Assembly asm) [0x00000] in <filename unknown>:0 UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object) UnityEngine.DebugLogHandler:LogException(Exception, Object) UnityEngine.Logger:LogException(Exception, Object) UnityEngine.Debug:LogException(Exception) ColossalFramework.Plugins.PluginInfo:AddAssembly(Assembly) ColossalFramework.Plugins.PluginManager:LoadDependenciesRecursive(Assembly, Dictionary`2, Dictionary`2, List`1) ColossalFramework.Plugins.PluginManager:LoadDependencies(Dictionary`2, Dictionary`2) ColossalFramework.Plugins.PluginManager:LoadAssemblies(Dictionary`2) ColossalFramework.Plugins.PluginManager:LoadPlugins() Starter:Awake()
This was referenced Mar 17, 2021
Mods that currently contain this bug:(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. |
Thank you for your quick fix, cheers! |
This was referenced Jan 28, 2022
drok
added a commit
that referenced
this issue
Feb 12, 2022
The tests demonstrate buggy behaviour These tests verify that the bugs are caught and reported
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
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.
The text was updated successfully, but these errors were encountered: