private bool InitializeGameSupport(Assembly assembly) { var types = assembly.GetTypes(); var decoratedType = types.FirstOrDefault( t => t.GetCustomAttributes( typeof(GameSupportLibraryEntryPointAttribute), false ).Length == 1 ); if (decoratedType == null) { Log.Error("The game support library is present, but doesn't contain a marked entry point."); return(false); } if (decoratedType.IsAssignableFrom(MonoBehaviourBridge.MonoBehaviourType)) { Log.Error("The game support library has a decorated entry point but it doesn't inherit from MonoBehaviour."); return(false); } if (!decoratedType.Attributes.HasFlag(TypeAttributes.Sealed)) { Log.Error("The game support library has an entry point but its class is not sealed."); return(false); } var attribute = decoratedType.GetCustomAttributes( typeof(GameSupportLibraryEntryPointAttribute), false ).First() as GameSupportLibraryEntryPointAttribute; if (IsGameSupportLibraryPresent(attribute.LibraryID)) { Log.Error("The game support library has a duplicate ID. Contact the GSL developer for assistance."); return(false); } var gameObject = GameObjectBridge.CreateGameObject(attribute.LibraryID); if (attribute.AwakeAfterInitialize) { GameObjectBridge.SetActive(gameObject, false); } var component = GameObjectBridge.AttachComponentTo(gameObject, decoratedType); if (component != null) { var initializerMethod = decoratedType.GetMethod( attribute.InitializerName, new Type[] { typeof(IManager) } ); if (initializerMethod != null) { Log.Debug($"Found initializer method '{attribute.InitializerName}' for {attribute.LibraryID}, calling."); initializerMethod.Invoke(component, new object[] { Manager }); } GameObjectBridge.DontDestroyOnLoad(gameObject); GameObjectBridge.SetActive(gameObject, true); var host = new GameSupportHost { ID = attribute.LibraryID, Assembly = assembly, ComponentInstance = component, UnityGameObject = gameObject }; GSLs.Add(host); return(true); } Log.Error("Game support library failed to initialize, for some reason your component was rejected by Unity Engine.\nLook in the output log of the game for more details."); return(false); }
private void LoadMod(LoadData data) { var rootPath = data.RootDirectory; var manifest = data.Manifest; var targetModulePath = Path.Combine(rootPath, manifest.ModuleFileName); Log.Info($"Now trying to load '{targetModulePath}'"); if (!File.Exists(targetModulePath)) { Log.Error($"That was quick... Target DLL file does not exist."); return; } if (manifest.RequiredGSLs != null && manifest.RequiredGSLs.Length > 0) { foreach (var id in manifest.RequiredGSLs) { if (!GameSupportLoader.IsGameSupportLibraryPresent(id)) { Log.Error($"The mod requires a GSL with ID that is not present: {id}"); Log.Error("This mod will not be loaded. You need to install that GSL before loading that mod."); return; } } } if (manifest.Dependencies != null && manifest.Dependencies.Length > 0) { if (!LoadDependenciesForMod(rootPath, manifest.Dependencies)) { Log.Error("Failed to load dependencies."); return; } } Assembly modAssembly; try { modAssembly = Assembly.LoadFrom(targetModulePath); } catch (ReflectionTypeLoadException rtle) { Log.ReflectionTypeLoadException(rtle); return; } catch (Exception e) { Log.Exception(e); return; } EnsureSingleEntryPoint(modAssembly); Type[] types; try { types = modAssembly.GetTypes(); } catch (ReflectionTypeLoadException rtle) { Log.ReflectionTypeLoadException(rtle); return; } var entryPointType = FindEntryPointType(types); var entryPointInfo = GetEntryPointAttribute(entryPointType); EnsureModIdValid(entryPointInfo.ModID); var initMethodInfo = entryPointType.GetMethod(entryPointInfo.InitializerName, new Type[] { typeof(IManager) }); if (initMethodInfo == null) { Log.Error($"Initializer method '{entryPointInfo.InitializerName}' accepting parameter of type 'IManager' not found."); return; } var messageHandlers = FindMessageHandlers(types); foreach (var messageHandler in messageHandlers) { Messenger.RegisterHandlerFor(messageHandler.ModID, messageHandler.MessageName, messageHandler.Method); Log.Info($"Registered message handler <{messageHandler.Method.Name}> for '{messageHandler.ModID}:{messageHandler.MessageName}'"); } var modHost = new ModHost { Assembly = modAssembly, ModID = entryPointInfo.ModID, LoadData = data, Instance = null, GameObject = null }; var dealingWithGameObject = MonoBehaviourBridge.MonoBehaviourType.IsAssignableFrom(entryPointType); if (dealingWithGameObject) { modHost.GameObject = GameObjectBridge.CreateGameObject(entryPointInfo.ModID); GameObjectBridge.DontDestroyOnLoad(modHost.GameObject); if (entryPointInfo.AwakeAfterInitialize) { GameObjectBridge.SetActive(modHost.GameObject, false); } modHost.Instance = GameObjectBridge.AttachComponentTo(modHost.GameObject, entryPointType); } else { var instance = Activator.CreateInstance(entryPointType); modHost.Instance = instance; } var initializer = entryPointType.GetMethod( entryPointInfo.InitializerName, new Type[] { typeof(IManager) } ); modHost.AssetLoaderMethod = entryPointType.GetMethod( entryPointInfo.LoaderMethodName, new Type[] { } ); if (initializer != null) { Log.Info($"Now calling initializer method '{initializer.Name}' in '{modHost.Assembly.GetName().Name}'"); try { var args = new object[] { Manager }; if (initializer.IsStatic) { initializer.Invoke(null, args); } else { initializer.Invoke(modHost.Instance, args); } } catch (Exception e) { Log.Error("The initializer method has exploded spectacularly. Centrifuge and other mods will still work, though."); Log.Exception(e); if (dealingWithGameObject) { GameObjectBridge.Destroy(modHost.GameObject); } return; } } else { Log.Warning($"Did not find the initializer method '{entryPointInfo.InitializerName}' for Mod ID '{modHost.ModID}'. Seems like it doesn't exist. Loaded the mod anyway."); } if (dealingWithGameObject && entryPointInfo.AwakeAfterInitialize) { GameObjectBridge.SetActive(modHost.GameObject, true); } Registry.RegisterMod(modHost); Log.Info("Mod has been initialized and registered sucessfully."); Manager.OnModInitialized(modHost.ToExchangeableApiObject()); }
public static void Initialize() { foreach (var arg in Environment.GetCommandLineArgs()) { if (arg == StartupArguments.DisableFancyColors) { ConsoleAllocator.FancyColorsEnabled = false; } if (arg == StartupArguments.AllocateConsole) { ConsoleAllocator.Redirect(); ConsoleEnabled = true; } } var version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion; EarlyLog.Info($"Centrifuge bootstrap for Reactor Mod Loader and API. Version {version}. Unity {ApplicationBridge.UnityVersion}"); if (ConsoleEnabled) { EarlyLog.Info($"Diagnostics mode enabled. Remove '{StartupArguments.AllocateConsole}' command line argument to disable."); } if (ApplicationBridge.GetRunningUnityGeneration() == UnityGeneration.Unity4OrOlder) { EarlyLog.Error("Centrifuge requires Unity 5 or newer. Terminating."); return; } EarlyLog.Info("Trying to find Centrifuge Reactor DLL..."); var reactorPath = GetCrossPlatformCompatibleReactorPath(); if (!File.Exists(reactorPath)) { EarlyLog.Error($"Centrifuge Reactor DLL could not be found at '{reactorPath}'. Mods will not be loaded."); return; } Type proxyType; try { EarlyLog.Info("Validating and loading Centrifuge Reactor DLL..."); Assembly.LoadFrom(reactorPath); EarlyLog.Info("Building manager proxy component for Unity Engine..."); proxyType = new ManagerProxyBuilder().WriteDynamicAssemblyAndLoadProxyType(); if (proxyType == null) { EarlyLog.Info("Failed."); return; } } catch (ReflectionTypeLoadException rtle) { EarlyLog.Exception(rtle); EarlyLog.Info(" --- LOADER EXCEPTIONS FOLLOW --- "); foreach (var lex in rtle.LoaderExceptions) { EarlyLog.Exception(lex); } return; } catch (Exception ex) { EarlyLog.Exception(ex); return; } try { EarlyLog.Info("Creating Reactor Manager GameObject..."); ReactorManagerObject = GameObjectBridge.CreateGameObject("com.github.ciastex/ReactorModLoaderProxy"); } catch (Exception e) { EarlyLog.Exception(e); return; } EarlyLog.Info("About to add component to Reactor Manager GameObject."); object proxyComponent; try { proxyComponent = GameObjectBridge.AttachComponentTo(ReactorManagerObject, proxyType); } catch (Exception e) { EarlyLog.Exception(e); return; } if (proxyComponent == null) { EarlyLog.Error("Manager proxy component has failed to attach when it wasn't really supposed to fail on Unity 5+."); EarlyLog.Info("Report this stuff to https://github.com/Ciastex/Centrifuge/issues."); EarlyLog.Info("Make sure to check for and - if existing - include your game's output_log.txt (and/or Player.log) in the report."); EarlyLog.Info("Definitely include this entire log as well."); EarlyLog.Info("Otherwise I'll be very angry and ask you for this stuff in a very rude manner."); if (Platform.IsUnix()) { EarlyLog.Info("Look in ~/.config/unity3d/<CompanyName>/<GameName>/ for any .log and/or .txt files."); } else { var path = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "\\AppData\\LocalLow"); EarlyLog.Info($"Look in {path}\\<CompanyName>\\<GameName> for any .log and/or .txt files."); } } EarlyLog.Info(" --- BOOTSTRAPPER FINISHED --- "); }