Example #1
0
        private void GenerateHookDict()
        {
            List <String> modsToUnload = new List <String> ();

            modHooks = new Dictionary <string, MethodDefinition[]> ();
            hooks    = new Dictionary <string, Dictionary <string, List <BaseModWithId> > > ();
            foreach (String modId in loader.modOrder)
            {
                BaseMod mod = null;
                try {
                    mod = loader.modInstances [modId];
                } catch {
                    continue;
                }
                if (mod != null)
                {
                    Dictionary <string, List <BaseModWithId> > methodHooks;
                    List <BaseModWithId> hookedMods;
                    MethodDefinition[]   requestedHooks;
                    try {
                        requestedHooks = (MethodDefinition[])mod.GetType().GetMethod("GetHooks").Invoke(null, new object[] { types,
                                                                                                                             SharedConstants.getExeVersionInt() });
                    } catch (Exception ex) {
                        Console.WriteLine(ex);
                        modsToUnload.Add(modId);
                        continue;
                    }
                    modHooks.Add(modId, requestedHooks);
                    foreach (MethodDefinition hookedMethod in requestedHooks)
                    {
                        //TODO: FIx for overloaded methods!
                        if (!hooks.TryGetValue(hookedMethod.DeclaringType.Name, out methodHooks))
                        {
                            methodHooks = new Dictionary <string, List <BaseModWithId> > ();
                            hooks.Add(hookedMethod.DeclaringType.Name, methodHooks);
                        }
                        if (!methodHooks.TryGetValue(hookedMethod.Name, out hookedMods))
                        {
                            hookedMods = new List <BaseModWithId> ();
                            methodHooks.Add(hookedMethod.Name, hookedMods);
                        }
                        hookedMods.Add(new BaseModWithId(mod, modId));
                    }
                }
            }
            Unload(modsToUnload);
            Console.WriteLine("Hooks:");
            foreach (string hookedTypeName in hooks.Keys)
            {
                Console.WriteLine(hookedTypeName);
                foreach (string hookedMethodName in hooks[hookedTypeName].Keys)
                {
                    Console.WriteLine("\t" + hookedMethodName);
                    foreach (BaseModWithId modWithId in hooks[hookedTypeName][hookedMethodName])
                    {
                        Console.WriteLine("\t\t" + modWithId.id);
                    }
                }
            }
        }
Example #2
0
        protected bool LoadModAssembly(ModAssemblyInfo assemblyInfo)
        {
            if (Mod != null)
            {
                throw new InvalidOperationException("Cannot load a mod if one has been loaded already");
            }

            if (assemblyInfo == null)
            {
                throw new ArgumentNullException(nameof(assemblyInfo));
            }

            if (string.IsNullOrWhiteSpace(assemblyInfo.AssemblyName))
            {
                throw new ArgumentException("Assembly name must be valid", nameof(assemblyInfo));
            }

            var path = $"{EngineShared.GameDirectory}/{assemblyInfo.AssemblyName}";

            Logger.Instance.Information($"Loading mod from path \"{path}\"");

            Mod = Assembly.LoadFrom(path);

            if (Mod == null)
            {
                Logger.Instance.Error($"Couldn't load mod {assemblyInfo.AssemblyName}");
                return(false);
            }

            //Exclude abstract classes; developers may place common code in abstract base classes
            var modInterfaces = Mod.GetTypes().Where(type => type.IsSubclassOf(typeof(BaseMod)) && !type.IsAbstract).ToList();

            if (modInterfaces.Count == 0)
            {
                Logger.Instance.Error("Couldn't find the mod interface class");
                return(false);
            }

            var modInterfaceClass = modInterfaces[0];

            if (modInterfaces.Count > 1)
            {
                Logger.Instance.Warning("Found more than one candidate for the mod interface class");

                Logger.Instance.Warning("The types found are:");

                modInterfaces.ForEach(t => Logger.Instance.Warning(t.FullName));

                Logger.Instance.Warning($"Using the first found class \"{modInterfaceClass.FullName}\"");
            }

            var instance = Activator.CreateInstance(modInterfaceClass);

            ModInterface = (BaseMod)instance;

            Logger.Instance.Information($"Mod \"{assemblyInfo.AssemblyName}\" loaded");

            return(true);
        }
Example #3
0
 protected virtual void Dispose(bool disposing)
 {
     if (disposing)
     {
         CoreMod.Dispose();
         BaseMod.Dispose();
     }
 }
Example #4
0
 public override void OnLoad(SimAirport.Modding.Data.GameState state)
 {
     Debug.Log("ModRunner OnLoad");
     mod = findMod();
     if (mod != null)
     {
         mod.SettingManager = settings;
         OnSettingsLoaded();
         mod.OnLoad(state);
     }
 }
Example #5
0
        public void Shutdown()
        {
            if (ModInterface != null)
            {
                ModInterface.Shutdown();
                ModInterface = null;
            }

            if (Mod != null)
            {
                Mod = null;
            }
        }
Example #6
0
 public void loadMods()
 {
     BaseMod.Initialize(publicAPI);
     foreach (String id in modOrder)
     {
         LocalMod lmod = (LocalMod)modManager.installedMods.Find(delegate(Item mod) {
             return((mod as LocalMod).localId.Equals(id));
         });
         if (lmod.enabled)
         {
             this.loadMod(lmod);
         }
     }
 }
Example #7
0
        public string OwnFolder(BaseMod mod)
        {
            String installpath = null;

            foreach (String id in loader.modInstances.Keys)
            {
                if (loader.modInstances [id].Equals(mod))
                {
                    installpath = (loader.modManager.installedMods.Find(delegate(Item lmod) {
                        return((lmod as LocalMod).localId.Equals(id));
                    }) as LocalMod).installPath;
                }
            }

            if (installpath == null && currentlyLoading != null)
            {
                return(Path.GetDirectoryName(currentlyLoading.installPath));
            }
            if (installpath == null)
            {
                return(Platform.getModLoaderPath() + Path.DirectorySeparatorChar + "mods" + Path.DirectorySeparatorChar + "Unknown" + Path.DirectorySeparatorChar);
            }
            return(Path.GetDirectoryName(installpath));
        }
Example #8
0
        public static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
        {
            if ((e.ExceptionObject as Exception).TargetSite.Module.Assembly.GetName().Name.Equals("UnityEngine") ||
                (e.ExceptionObject as Exception).TargetSite.Module.Assembly.GetName().Name.Equals("Assembly-CSharp") ||
                (e.ExceptionObject as Exception).TargetSite.Module.Assembly.GetName().Name.Equals("ScrollsModLoader") ||
                (e.ExceptionObject as Exception).TargetSite.Module.Assembly.Location.ToLower().Equals(Platform.getGlobalScrollsInstallPath().ToLower()) ||
                (e.ExceptionObject as Exception).TargetSite.Module.Assembly.Location.Equals(""))                  //no location or Managed => mod loader crash

            //log
            {
                Console.WriteLine(e.ExceptionObject);
                new ExceptionLogger().logException((Exception)e.ExceptionObject);

                //unload ScrollsModLoader
                MethodBodyReplacementProviderRegistry.SetProvider(new NoMethodReplacementProvider());

                //check for frequent crashes
                if (!System.IO.File.Exists(Platform.getGlobalScrollsInstallPath() + System.IO.Path.DirectorySeparatorChar + "check.txt"))
                {
                    System.IO.File.CreateText(Platform.getGlobalScrollsInstallPath() + System.IO.Path.DirectorySeparatorChar + "check.txt");
                    Platform.RestartGame();
                }
                else
                {
                    try {
                        foreach (String id in instance.modOrder)
                        {
                            BaseMod mod = instance.modInstances [id];
                            if (mod != null)
                            {
                                try {
                                    instance.unloadMod((LocalMod)instance.modManager.installedMods.Find(delegate(Item lmod) {
                                        return((lmod as LocalMod).id.Equals(id));
                                    }));
                                } catch (Exception exp) {
                                    Console.WriteLine(exp);
                                }
                            }
                        }
                    } catch (Exception exp) {
                        Console.WriteLine(exp);
                    }
                    instance.repatch();
                }
            }
            else if (instance != null && logger != null && logger.Count > 0)
            {
                Console.WriteLine(e.ExceptionObject);

                Assembly asm      = (e.ExceptionObject as Exception).TargetSite.Module.Assembly;
                Type     modClass = (from _modClass in asm.GetTypes()
                                     where _modClass.InheritsFrom(typeof(BaseMod))
                                     select _modClass).First();

                //no mod classes??
                if (modClass == null)
                {
                    return;
                }

                foreach (String id in instance.modOrder)
                {
                    BaseMod mod = null;
                    try {
                        mod = instance.modInstances [id];
                    } catch (Exception exp) {
                        Console.WriteLine(exp);
                    }
                    if (mod != null)
                    {
                        if (modClass.Equals(mod.GetType()))
                        {
                            String folder = Path.GetDirectoryName(asm.Location);
                            if (File.Exists(folder + Path.DirectorySeparatorChar + "config.json"))
                            {
                                JsonReader reader = new JsonReader();
                                LocalMod   lmod   = (LocalMod)reader.Read(File.ReadAllText(folder + Path.DirectorySeparatorChar + "config.json"), typeof(LocalMod));
                                if (!lmod.localInstall)
                                {
                                    logger [lmod.localId].logException((Exception)e.ExceptionObject);
                                }
                            }
                        }
                    }
                }
            }
        }
Example #9
0
 public BaseModWithId(BaseMod mod, string id)
 {
     this.mod = mod;
     this.id  = id;
 }
Example #10
0
        public object Intercept(IInvocationInfo info)
        {
            if (lastModInstancesCount != loader.modInstances.Count)
            {
                lastModInstancesCount = loader.modInstances.Count;
                hooks = null;
            }
            if (hooks == null)
            {
                GenerateHookDict();
            }
            //list for unloading
            List <String> modsToUnload = new List <String> ();
            String        replacement  = "";

            //Find Mods that hooked into Method
            Dictionary <string, List <BaseModWithId> > methodHooks;
            List <BaseModWithId> hookedMods;

            string declaringTypeName = info.TargetMethod.DeclaringType.Name;
            string targetMethodName  = info.TargetMethod.Name;

            if (hooks.TryGetValue(declaringTypeName, out methodHooks))
            {
                if (methodHooks.TryGetValue(targetMethodName, out hookedMods))
                {
                    //determine replacement
                    foreach (BaseModWithId modWithId in hookedMods)
                    {
                        BaseMod mod = modWithId.mod;
                        string  id  = modWithId.id;
                        try {
                            if (mod.WantsToReplace(new InvocationInfo(info)))
                            {
                                replacement = id;
                            }
                        } catch (Exception ex) {
                            Console.WriteLine(ex);
                            modsToUnload.Add(id);
                        }
                    }

                    //unload
                    Unload(modsToUnload);

                    //load beforeinvoke
                    foreach (BaseModWithId modWithId in hookedMods)
                    {
                        BaseMod mod = modWithId.mod;
                        string  id  = modWithId.id;
                        if (id.Equals(replacement))
                        {
                            continue;
                        }
                        try {
                            mod.BeforeInvoke(new InvocationInfo(info));
                        } catch (Exception ex) {
                            Console.WriteLine(ex);
                            modsToUnload.Add(id);
                        }
                    }
                }
            }

            //unload
            Unload(modsToUnload);


            //TODO: Simplify the Patch-Finding Process - Implement as Mod?
            //check for patch call
            object ret        = null;
            bool   patchFound = false;

            foreach (Patch patch in loader.patches)
            {
                if (patch.patchedMethods().Any(item => ((item.Name.Equals(info.TargetMethod.Name)) && (item.DeclaringType.Name.Equals(info.TargetMethod.DeclaringType.Name)))))
                {
                    try {
                        ret        = patch.Intercept(info);
                        patchFound = true;
                    } catch (Exception ex) {
                        Console.WriteLine(ex);
                    }
                }
            }
            if (!patchFound)
            {
                if (replacement.Equals(""))
                {
                    ret = info.TargetMethod.Invoke(info.Target, info.Arguments);
                }
                else
                {
                    try {
                        BaseMod mod = loader.modInstances [replacement];
                        mod.ReplaceMethod(new InvocationInfo(info), out ret);
                    } catch (Exception exp) {
                        Console.WriteLine(exp);
                        modsToUnload.Add(replacement);
                    }
                }
            }

            //Additional unload?
            Unload(modsToUnload);

            //load afterinvoke
            if (hooks.TryGetValue(declaringTypeName, out methodHooks))
            {
                if (methodHooks.TryGetValue(targetMethodName, out hookedMods))
                {
                    foreach (BaseModWithId modWithId in hookedMods)
                    {
                        BaseMod mod = modWithId.mod;
                        string  id  = modWithId.id;
                        try {
                            mod.AfterInvoke(new InvocationInfo(info), ref ret);
                        } catch (Exception exp) {
                            Console.WriteLine(exp);
                            modsToUnload.Add(id);
                        }
                    }
                }
            }

            //unload
            Unload(modsToUnload);

            return(ret);
        }
Example #11
0
 public Patcher(BaseMod <Mod> mod) : base(mod)
 {
 }
Example #12
0
 public Patcher(BaseMod mod) : base(mod)
 {
 }
Example #13
0
        private BaseMod findMod()
        {
            //find location of Mod.cs file
            //the scripting dir is completely loaded as assembly, so can't use it,
            //use modrunner dir instead
            string cslocation = Path.GetDirectoryName(Assembly.GetAssembly(this.GetType()).Location) + Path.DirectorySeparatorChar + ".." + Path.DirectorySeparatorChar + "modrunner" + Path.DirectorySeparatorChar + "Mod.cs";

            Debug.Log(1);
            //find SimAirport.Modding.Base assembly
            string locModding = Assembly.GetAssembly(this.GetType().BaseType).Location;

            Debug.Log(2);
            //find the ref Type we can use to find the Assembly-CSharp assembly
            //depending on whether we are in the game or menu
            //this could probably be done way better
            Type refType;

            if (MainMenu_UI.instance != null)
            {
                refType = MainMenu_UI.instance.GetType();
            }
            else
            {
                refType = Game.current.GetType();
            }

            //find Assembly-CSharp assembly
            String locAssembly = Assembly.GetAssembly(refType).Location;

            //find UnityEngine.CoreModule assembly
            String locUnity = Assembly.GetAssembly(refType.BaseType).Location;

            Debug.Log(3);

            //add all of the assemblies to a Set for the compiler
            HashSet <string> assemblies = new HashSet <string>();

            assemblies.Add(locModding);
            assemblies.Add(locAssembly);
            //find all dependencies/references of main assembly
            AssemblyName[] assemblyNames = Assembly.GetAssembly(refType).GetReferencedAssemblies();
            foreach (AssemblyName assname in assemblyNames)
            {
                //system seems to reference the mscorlib already, so do not add it again
                if (assname.Name != "mscorlib")
                {
                    string loc = Assembly.Load(assname.Name).Location;
                    assemblies.Add(loc);
                }
            }
            Debug.Log(4);

            //prepare in-memory assembly compiler...
            CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary <string, string>()
            {
                { "CompilerVersion", "v4.7.1" }
            });
            //...add the references...
            CompilerParameters parameters = new CompilerParameters(assemblies.ToArray());

            parameters.GenerateInMemory      = true;
            parameters.GenerateExecutable    = false;
            parameters.TreatWarningsAsErrors = false;
            //...and compile --- here you could also provide multiple source files, it's an array ---
            CompilerResults compilerResults = provider.CompileAssemblyFromFile(parameters, new[] { cslocation });

            compilerResults.Errors.Cast <CompilerError>().ToList().ForEach(error => Debug.Log("Error from compilation: " + error.ErrorText));
            //CompiledAssembly is either null (then the errors above are interesting), or a real assembly (then you can just treat the errors as warnings)
            var asm = compilerResults.CompiledAssembly;

            if (asm == null)
            {
                Debug.Log("Generated assembly is null");
            }
            else
            {
                //TODO probably should search for all types which extend BaseMod
                Type t = asm.GetType("qcs2017.modrunner.ScriptMod");
                mod = (BaseMod)Activator.CreateInstance(t);
                return(mod);
            }

            return(null);
        }