Open drok opened 3 years ago
Mods should do this (good example):
void ILoadingExtension.OnCreate()
{
Singleton<PluginManager>.instance.GetImplementations<IMyAPI>()
.Do((x) => x.DoStuff());
}
And should NOT do this (bad example):
void OnEnable()
{
Singleton<PluginManager>.instance.GetPluginsInfo()
.DoIf(
(x) => (x.userModInstance as IUserMod).Name == "MyDependent",
(x) => (x.userModInstance as IMyAPI).DoStuff());
}
Given an internal interface IMyAPI
:
public interface IMyAPI
{
void DoStuff();
};
The good example scans only the enabled mods, and instantiates only those classes that implement the IMyAPI
interface.
The bad example scans a partial list of all mods, including disabled mods, and instantiates all IUserMods that have been enumerated up to the time OnEnable()
was called. It's likely not what you want; you're not even scanning the full mod list, so you have a load-ordering problem, in addition to instantiating all mods, unjustifiably.
Many mods use
PluginInfo.GetInstance()
from theirOnEnable()
, causing all subscribed mods to be instantiated prematurely, even if they are not enabled, as seen in the stack trace below.This causes some problems with mods that want to self enable, as this mod (auto-enables once after initial subscription).
Normally, disabled mods are instantiated from
ContentManagerPanel.Initialize()
after all the enabled mods have been instantiated andOnEnabled()
Being instantiated prematurely means a self-enabling, but disabled mod cannot simply "myPluginInfo.isEnabled = true" in their constructor. This could cause a second instance to be constructed via a second call to
get_userModInstance()
andOnEnabled()
from within the prematureget_userModInstance()
. The final value ofuserModInstance
would be the premature instance (which is notOnEnabled()
), and not the second instance (because the premature call returns after the call triggered byisEnabled=true
This would leave the self-enabling mod in an confused state (two instances, one enabled but not `List'-ed, and one listed but not enabled).