Example #1
0
        public void Awake()
        {
            Instance = this;

            Logger = base.Logger;

            ModManager = new DetourModManager();
            AddHookLogging();

            CheckForIncompatibleAssemblies();

            if (Environment.GetEnvironmentVariable("R2API_DEBUG") == "true")
            {
                EnableDebug();
            }

            var pluginScanner    = new PluginScanner();
            var submoduleHandler = new APISubmoduleHandler(Logger);

            LoadedSubmodules = submoduleHandler.LoadRequested(pluginScanner);
            pluginScanner.ScanPlugins();

            var networkCompatibilityHandler = new NetworkCompatibilityHandler();

            networkCompatibilityHandler.BuildModList();

            On.RoR2.RoR2Application.Awake += CheckIfUsedOnRightGameVersion;

            R2APIContentPackProvider.Init();
        }
Example #2
0
        public R2API()
        {
            Logger     = base.Logger;
            ModManager = new DetourModManager();
            AddHookLogging();
            CheckForIncompatibleAssemblies();
            CheckR2APIMonomodPatch();

            Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "Cecil");

            On.RoR2.UnitySystemConsoleRedirector.Redirect += orig => { };

            var pluginScanner    = new PluginScanner();
            var submoduleHandler = new APISubmoduleHandler(GameBuild, Logger);

            LoadedSubmodules = submoduleHandler.LoadRequested(pluginScanner);
            pluginScanner.ScanPlugins();

            var networkCompatibilityHandler = new NetworkCompatibilityHandler();

            networkCompatibilityHandler.BuildModList();

            RoR2Application.isModded = true;

            SteamworksClientManager.onLoaded += CheckIfUsedOnRightGameVersion;

            VanillaFixes();
        }
Example #3
0
File: R2API.cs Project: zkitX/R2API
        public R2API()
        {
            Logger     = base.Logger;
            ModManager = new DetourModManager();
            AddHookLogging();
            CheckForIncompatibleAssemblies();
            CheckR2APIMonomodPatch();

            Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "Cecil");

            On.RoR2.RoR2Application.UnitySystemConsoleRedirector.Redirect += orig => { };

            var submoduleHandler = new APISubmoduleHandler(GameBuild, Logger);

            loadedSubmodules = submoduleHandler.LoadRequested();

            //Currently disabled until manifest v2
            //ModListAPI.Init();

            RoR2Application.isModded = true;

            // Temporary fix as the new quickplay button currently don't have the DisableIfGameModded Script attached to it
            On.RoR2.UI.QuickPlayButtonController.Start += (orig, self) => {
                orig(self);
                self.gameObject.SetActive(false);
            };

            On.RoR2.DisableIfGameModded.OnEnable += (orig, self) => {
                // TODO: If we can enable quick play without regrets, uncomment.
                //if (self.name == "Button, QP")
                //    return;

                self.gameObject.SetActive(false);
            };

            On.RoR2.Networking.SteamLobbyFinder.CCSteamQuickplayStart += (orig, args) => {
                Debug.Log("QuickPlay is disabled in mods due to social contracts and lack of general support");
            };

            SteamworksClientManager.onLoaded += () => {
                var buildId =
                    SteamworksClientManager.instance.GetFieldValue <Client>("steamworksClient").BuildId;

                if (GameBuild == buildId)
                {
                    return;
                }

                Logger.LogWarning($"This version of R2API was built for build id \"{GameBuild}\", you are running \"{buildId}\".");
                Logger.LogWarning("Should any problems arise, please check for a new version before reporting issues.");
            };

            // Make sure that modded dedicated servers are recognizable from the server browser
            On.RoR2.SteamworksServerManager.UpdateHostName += (orig, self, hostname) => {
                var server = ((SteamworksServerManager)self).GetFieldValue <Server>("steamworksServer");
                server.GameTags = "mod," + server.GameTags;
            };
        }
Example #4
0
        internal static void Dispose(object sender, EventArgs args)
        {
            Audio.Unload(); // This exists but never gets called by the vanilla game.

            if (_DetourModManager != null)
            {
                foreach (Assembly asm in _DetourOwners)
                {
                    _DetourModManager.Unload(asm);
                }

                _DetourModManager.Dispose();
                _DetourModManager = null;
                _DetourOwners.Clear();
            }
        }
Example #5
0
        public R2API()
        {
            Logger     = base.Logger;
            ModManager = new DetourModManager();
            AddHookLogging();
            CheckForIncompatibleAssemblies();
            CheckR2APIMonomodPatch();

            Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "Cecil");

            On.RoR2.RoR2Application.UnitySystemConsoleRedirector.Redirect += orig => { };
            var submoduleHandler = new APISubmoduleHandler(GameBuild, Logger);

            submoduleHandler.LoadRequested();

            RoR2Application.isModded = true;

            //This needs to always be enabled, regardless of module dependency, or it is useless
            ModListAPI.Init();

            On.RoR2.DisableIfGameModded.OnEnable += (orig, self) => {
                // TODO: If we can enable quick play without regrets, uncomment.
                //if (self.name == "Button, QP")
                //    return;

                self.gameObject.SetActive(false);
            };

            SteamworksClientManager.onLoaded += () => {
                var buildId =
                    SteamworksClientManager.instance.GetFieldValue <Client>("steamworksClient").BuildId;

                if (GameBuild == buildId)
                {
                    return;
                }

                Logger.LogWarning($"This version of R2API was built for build id \"{GameBuild}\", you are running \"{buildId}\".");
                Logger.LogWarning("Should any problems arise, please check for a new version before reporting issues.");
            };

            On.RoR2.SteamworksServerManager.UpdateHostName += (orig, self, hostname) => {
                orig(self, $"[MOD] {hostname}");
                var server = ((SteamworksServerManager)self).GetFieldValue <Server>("steamworksServer");
                server.GameTags = "mod," + server.GameTags;
            };
        }
        public static void Init()
        {
            if (Initialized)
            {
                return;
            }
            Initialized = true;

            Manager = new DetourModManager();
            Manager.Ignored.Add(Assembly.GetExecutingAssembly());

            // Load the cecil module generator.
            // Adding this more than once shouldn't hurt.
            HookEndpointManager.OnGenerateCecilModule += GenerateCecilModule;

            // Some mods might forget to undo their hooks.
            HookOnUnloadContent = new Hook(
                typeof(Mod).GetMethod("UnloadContent", BindingFlags.NonPublic | BindingFlags.Instance),
                typeof(TerrariaHooksManager).GetMethod("OnUnloadContent", BindingFlags.NonPublic | BindingFlags.Static)
                );

            // All of our own hooks need to be undone last.
            HookOnUnloadAll = new Hook(
                typeof(ModLoader).GetMethod("Unload", BindingFlags.NonPublic | BindingFlags.Static),
                typeof(TerrariaHooksManager).GetMethod("OnUnloadAll", BindingFlags.NonPublic | BindingFlags.Static)
                );

            // Try to hook the logger to avoid logging "silent" exceptions thrown by TerrariaHooks.
            MethodBase m_LogSilentException =
                typeof(Mod).Assembly.GetType("Terraria.ModLoader.ModCompile+<>c")
                ?.GetMethod("<ActivateExceptionReporting>b__15_0", BindingFlags.NonPublic | BindingFlags.Instance);

            if (m_LogSilentException != null)
            {
                HookOnLogSilentException = new Hook(
                    m_LogSilentException,
                    typeof(TerrariaHooksManager).GetMethod("OnLogSilentException", BindingFlags.NonPublic | BindingFlags.Static)
                    );
            }
        }
Example #7
0
        public void Awake()
        {
            Instance = this;

            Logger     = base.Logger;
            ModManager = new DetourModManager();
            AddHookLogging();
            CheckForIncompatibleAssemblies();

            Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "Cecil");

            if (Environment.GetEnvironmentVariable("R2API_DEBUG") == "true")
            {
                EnableDebug();
            }

            On.RoR2.UnitySystemConsoleRedirector.Redirect += orig => { };

            LoadRoR2ContentEarly.Init();

            var pluginScanner    = new PluginScanner();
            var submoduleHandler = new APISubmoduleHandler(GameBuild, Logger);

            LoadedSubmodules = submoduleHandler.LoadRequested(pluginScanner);
            pluginScanner.ScanPlugins();

            var networkCompatibilityHandler = new NetworkCompatibilityHandler();

            networkCompatibilityHandler.BuildModList();

            RoR2Application.isModded = true;

            SteamworksClientManager.onLoaded += CheckIfUsedOnRightGameVersion;

            VanillaFixes();

            R2APIContentPackProvider.Init();
        }
Example #8
0
        public void Awake()
        {
            Logger     = base.Logger;
            ModManager = new DetourModManager();
            AddHookLogging();
            CheckForIncompatibleAssemblies();
            CheckR2APIPatch();

            Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "Cecil");

            On.RoR2.UnitySystemConsoleRedirector.Redirect += orig => { };

            var pluginScanner    = new PluginScanner();
            var submoduleHandler = new APISubmoduleHandler(GameBuild, Logger);

            LoadedSubmodules = submoduleHandler.LoadRequested(pluginScanner);
            pluginScanner.ScanPlugins();

            var networkCompatibilityHandler = new NetworkCompatibilityHandler();

            networkCompatibilityHandler.BuildModList();

            RoR2Application.isModded = true;

            SteamworksClientManager.onLoaded += CheckIfUsedOnRightGameVersion;

            VanillaFixes();

            // Load RoR2Content early so that modders
            // can take prefabs refs from the fields directly.
            RoR2Content = new RoR2Content();

            // We dont want the game code to remake the RoR2Content instance again
            IL.RoR2.RoR2Application.OnLoad += TakeOurInstanceInstead;

            R2APIContentPackProvider.Init();
        }
Example #9
0
        public R2API()
        {
            Logger     = base.Logger;
            ModManager = new DetourModManager();
            AddHookLogging();

            CheckForIncompatibleAssemblies();

            Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "Cecil");

            On.RoR2.RoR2Application.UnitySystemConsoleRedirector.Redirect += orig => { };
            var submoduleHandler = new APISubmoduleHandler(GameBuild, Logger);

            submoduleHandler.LoadAll(GetType().Assembly);

            RoR2Application.isModded = true;

            On.RoR2.DisableIfGameModded.OnEnable += (orig, self) => {
                // TODO: If we can enable quick play without regrets, uncomment.
                //if (self.name == "Button, QP")
                //    return;

                self.gameObject.SetActive(false);
            };

            On.RoR2.RoR2Application.OnLoad += (orig, self) => {
                orig(self);

                if (GameBuild == self.steamworksClient.BuildId)
                {
                    return;
                }

                Logger.LogWarning($"This version of R2API was built for build id \"{GameBuild}\", you are running \"{self.steamworksClient.BuildId}\".");
                Logger.LogWarning("Should any problems arise, please check for a new version before reporting issues.");
            };
        }
Example #10
0
        internal static void Boot()
        {
            Logger.Log(LogLevel.Info, "core", "Booting Everest");
            Logger.Log(LogLevel.Info, "core", $"AppDomain: {AppDomain.CurrentDomain.FriendlyName ?? "???"}");
            Logger.Log(LogLevel.Info, "core", $"VersionCelesteString: {VersionCelesteString}");

            if (Type.GetType("Mono.Runtime") != null)
            {
                // Mono hates HTTPS.
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => {
                    return(true);
                };
            }

            // enable TLS 1.2 to fix connecting to everestapi.github.io
            ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

            PathGame = Path.GetDirectoryName(typeof(Celeste).Assembly.Location);

            // .NET hates it when strong-named dependencies get updated.
            AppDomain.CurrentDomain.AssemblyResolve += (asmSender, asmArgs) => {
                AssemblyName asmName = new AssemblyName(asmArgs.Name);
                if (!asmName.Name.StartsWith("Mono.Cecil") &&
                    !asmName.Name.StartsWith("YamlDotNet") &&
                    !asmName.Name.StartsWith("NLua"))
                {
                    return(null);
                }

                Assembly asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(other => other.GetName().Name == asmName.Name);
                if (asm != null)
                {
                    return(asm);
                }

                return(Assembly.LoadFrom(Path.Combine(PathGame, asmName.Name + ".dll")));
            };

            // .NET hates to acknowledge manually loaded assemblies.
            AppDomain.CurrentDomain.AssemblyResolve += (asmSender, asmArgs) => {
                AssemblyName asmName = new AssemblyName(asmArgs.Name);
                foreach (Assembly asm in _RelinkedAssemblies)
                {
                    if (asm.GetName().Name == asmName.Name)
                    {
                        return(asm);
                    }
                }

                return(null);
            };

            // Preload some basic dependencies.
            Assembly.Load("MonoMod.RuntimeDetour");
            Assembly.Load("MonoMod.Utils");
            Assembly.Load("Mono.Cecil");
            Assembly.Load("YamlDotNet");
            Assembly.Load("Newtonsoft.Json");
            Assembly.Load("Jdenticon");

            if (!File.Exists(Path.Combine(PathGame, "EverestXDGFlag")))
            {
                XDGPaths    = false;
                PathEverest = PathGame;
            }
            else
            {
                XDGPaths = true;
                string dataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                Directory.CreateDirectory(PathEverest = Path.Combine(dataDir, "Everest"));
                Directory.CreateDirectory(Path.Combine(dataDir, "Everest", "Mods")); // Make sure it exists before content gets initialized
            }

            // Old versions of Everest have used a separate ModSettings folder.
            string modSettingsOld = Path.Combine(PathEverest, "ModSettings");
            string modSettingsRIP = Path.Combine(PathEverest, "ModSettings-OBSOLETE");

            if (Directory.Exists(modSettingsOld) || Directory.Exists(modSettingsRIP))
            {
                Logger.Log(LogLevel.Warn, "core", "THE ModSettings FOLDER IS OBSOLETE AND WILL NO LONGER BE USED!");
                if (Directory.Exists(modSettingsOld) && !Directory.Exists(modSettingsRIP))
                {
                    Directory.Move(modSettingsOld, modSettingsRIP);
                }
            }

            _DetourModManager           = new DetourModManager();
            _DetourModManager.OnILHook += (owner, from, to) => {
                _DetourOwners.Add(owner);
                object target = to.Target;
                _DetourLog.Add($"new ILHook by {owner.GetName().Name}: {from.GetID()} -> {to.Method?.GetID() ?? "???"}" + (target == null ? "" : $" (target: {target})"));
            };
            _DetourModManager.OnHook += (owner, from, to, target) => {
                _DetourOwners.Add(owner);
                _DetourLog.Add($"new Hook by {owner.GetName().Name}: {from.GetID()} -> {to.GetID()}" + (target == null ? "" : $" (target: {target})"));
            };
            _DetourModManager.OnDetour += (owner, from, to) => {
                _DetourOwners.Add(owner);
                _DetourLog.Add($"new Detour by {owner.GetName().Name}: {from.GetID()} -> {to.GetID()}");
            };
            _DetourModManager.OnNativeDetour += (owner, fromMethod, from, to) => {
                _DetourOwners.Add(owner);
                _DetourLog.Add($"new NativeDetour by {owner.GetName().Name}: {fromMethod?.ToString() ?? from.ToString("16X")} -> {to.ToString("16X")}");
            };
            HookEndpointManager.OnAdd += (from, to) => {
                Assembly owner = HookEndpointManager.GetOwner(to) as Assembly ?? typeof(Everest).Assembly;
                _DetourOwners.Add(owner);
                object target = to.Target;
                _DetourLog.Add($"new On.+= by {owner.GetName().Name}: {from.GetID()} -> {to.Method?.GetID() ?? "???"}" + (target == null ? "" : $" (target: {target})"));
                return(true);
            };
            HookEndpointManager.OnModify += (from, to) => {
                Assembly owner = HookEndpointManager.GetOwner(to) as Assembly ?? typeof(Everest).Assembly;
                _DetourOwners.Add(owner);
                object target = to.Target;
                _DetourLog.Add($"new IL.+= by {owner.GetName().Name}: {from.GetID()} -> {to.Method?.GetID() ?? "???"}" + (target == null ? "" : $" (target: {target})"));
                return(true);
            };

            // Before even initializing anything else, make sure to prepare any static flags.
            Flags.Initialize();

            // 0.1 parses into 1 in regions using ,
            // This also somehow sets the exception message language to English.
            CultureInfo.DefaultThreadCurrentCulture   = CultureInfo.InvariantCulture;
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;

            if (!Flags.IsHeadless)
            {
                // Initialize the content helper.
                Content.Initialize();

                // Initialize all main managers before loading any mods.
                TouchInputManager.Instance = new TouchInputManager(Celeste.Instance);
                // Don't add it yet, though - add it in Initialize.
            }

            MainThreadHelper.Instance = new MainThreadHelper(Celeste.Instance);

            // Register our core module and load any other modules.
            new CoreModule().Register();

            // Note: Everest fulfills some mod dependencies by itself.
            new NullModule(new EverestModuleMetadata()
            {
                Name          = "Celeste",
                VersionString = $"{Celeste.Instance.Version.ToString()}-{(typeof(Game).Assembly.FullName.Contains("FNA") ? "fna" : "xna")}"
            }).Register();
            new NullModule(new EverestModuleMetadata()
            {
                Name          = "DialogCutscene",
                VersionString = "1.0.0"
            }).Register();
            new NullModule(new EverestModuleMetadata()
            {
                Name          = "UpdateChecker",
                VersionString = "1.0.2"
            }).Register();

            LuaLoader.Initialize();

            Loader.LoadAuto();

            if (!Flags.IsHeadless)
            {
                // Load stray .bins afterwards.
                Content.Crawl(new MapBinsInModsModContent(Path.Combine(PathEverest, "Mods")));
            }

            // Also let all mods parse the arguments.
            Queue <string> args = new Queue <string>(Args);

            while (args.Count > 0)
            {
                string arg = args.Dequeue();
                foreach (EverestModule mod in _Modules)
                {
                    if (mod.ParseArg(arg, args))
                    {
                        break;
                    }
                }
            }

            // Start requesting the version list ASAP.
            Updater.RequestAll();

            // Request the mod update list as well.
            ModUpdaterHelper.RunAsyncCheckForModUpdates(excludeBlacklist: true);
        }
        public static void Init()
        {
            if (Initialized)
            {
                return;
            }
            Initialized = true;

            Manager = new DetourModManager();
            Manager.Ignored.Add(Assembly.GetExecutingAssembly());

            // Load the cecil module generator.
            // Adding this more than once shouldn't hurt.
            HookEndpointManager.OnGenerateCecilModule += GenerateCecilModule;

            // Some mods might forget to undo their hooks.
            HookOnUnloadContent = new Hook(
                typeof(Mod).GetMethod("UnloadContent", BindingFlags.NonPublic | BindingFlags.Instance),
                typeof(TerrariaHooksManager).GetMethod("OnUnloadContent", BindingFlags.NonPublic | BindingFlags.Static)
                );

            // All of our own hooks need to be undone last.
            MethodBase m_Unload = typeof(ModLoader).GetMethod("Unload", BindingFlags.NonPublic | BindingFlags.Static);

            if (m_Unload != null)
            {
                HookOnUnloadAll = new Hook(
                    m_Unload,
                    typeof(TerrariaHooksManager).GetMethod("OnUnloadAll", BindingFlags.NonPublic | BindingFlags.Static)
                    );
            }
            else
            {
                /* The unofficial tML x64 form is a hot mess of tML 0.10 and 0.11 pre-beta.
                 * As such, mods are only unloaded when they're reloaded.
                 * Luckily, ModContnet.Unload runs right after unloading all mods.
                 * Even more luckily, it pretty much shares the same signature as the old Unload method.
                 */
                MethodBase m_UnloadContent =
                    typeof(Mod).Assembly.GetType("Terraria.ModLoader.ModContent")
                    ?.GetMethod("Unload", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
                if (m_UnloadContent != null)
                {
                    HookOnUnloadAll = new Hook(
                        m_UnloadContent,
                        typeof(TerrariaHooksManager).GetMethod("OnUnloadAll", BindingFlags.NonPublic | BindingFlags.Static)
                        );
                }
                else
                {
                    throw new Exception("Incompatible tML version: Can't find unload hook point");
                }
            }

            // Try to hook the logger to avoid logging "silent" exceptions thrown by TerrariaHooks.
            MethodBase m_LogSilentException =
                typeof(Mod).Assembly.GetType("Terraria.ModLoader.ModCompile+<>c")
                ?.GetMethod("<ActivateExceptionReporting>b__15_0", BindingFlags.NonPublic | BindingFlags.Instance);

            if (m_LogSilentException != null)
            {
                HookOnLogSilentException = new Hook(
                    m_LogSilentException,
                    typeof(TerrariaHooksManager).GetMethod("OnLogSilentException", BindingFlags.NonPublic | BindingFlags.Static)
                    );
            }
        }