/// <summary> /// The main entry point for the application. /// </summary> /// <param name="args"></param> public static void Main(string[] args) { // Find Assemblies Manually if necessary (Deprecate app.config) AppDomain.CurrentDomain.AssemblyResolve += AssemblyFinder.CurrentDomain_AssemblyResolve; /* - Initialization - */ DoSquirrelStuff(); // Initialize the console. ConsoleFunctions.Initialize(); // Print startup information. Banner.PrintBanner(); // Get Controller Order Controllers.PrintControllerOrder(); // Unlock DLLs, Removes Zone Information which may prevent DLL injection if DLL was downloaded from e.g. Internet Explorer DllUnlocker.UnblockDlls(); // Setup Server LoaderServer.SetupServer(); // Setup libReloaded Debug Bindings SetuplibReloadedBindings(); /* - Option Parsing, Linking - */ // Parse Arguments ParseArguments(args); // Start game InjectByMethod(args); /* - Load and enter main close polling loop - */ // Add to exited event _gameProcess.GetProcessFromReloadedProcess().EnableRaisingEvents = true; _gameProcess.GetProcessFromReloadedProcess().Exited += (sender, eventArgs) => ProcessSelfReattach(args); // Load modifications for the current game. ModLoader.LoadMods(_gameConfig, _gameProcess); // Stay alive in the background AppDomain.CurrentDomain.ProcessExit += Shutdown; Console.CancelKeyPress += Shutdown; // Sleep infinitely as much as it is necessary. while (true) { Console.ReadLine(); } }
/// <summary> /// Kicks off the individual mods running inside the target process /// specified by our <see cref="_gameProcess"/> variable. /// </summary> private static void InjectMods(string[] commandLineArguments) { // Do not reattach on exit for Steam Shims - they should not reboot if shimmed. if (commandLineArguments.Contains(Strings.Common.LoaderSettingSteamShim)) { _gameProcess.GetProcessFromReloadedProcess().EnableRaisingEvents = true; _gameProcess.GetProcessFromReloadedProcess().Exited += (sender, eventArgs) => Shutdown(null, null); } else { _gameProcess.GetProcessFromReloadedProcess().EnableRaisingEvents = true; _gameProcess.GetProcessFromReloadedProcess().Exited += (sender, eventArgs) => ProcessSelfReattach(commandLineArguments); } ModLoader.LoadMods(_gameConfig, _gameProcess); }
/// <summary> /// Checks whether to reattach Reloaded Mod Loader if the game process /// unexpectedly kills itself and then restarts (a standard for some games' launch procedures). /// </summary> private static void ProcessSelfReattach(string[] args) { // Use stopwatch for soft timing. Stopwatch timeoutStopWatch = new Stopwatch(); timeoutStopWatch.Start(); // Set attach name for reattaching. _attachTargetName = Path.GetFileNameWithoutExtension(_gameConfig.ExecutableLocation); // Spin trying to get game process until timeout. while (timeoutStopWatch.ElapsedMilliseconds < 6000) { // Grab current already running game, did we find it? Not? Try again. ReloadedProcess localGameProcess = ReloadedProcess.GetProcessByName(_attachTargetName); if (localGameProcess == null) { continue; } // Ensure we didn't find some background process that was running all along. if (localGameProcess.GetProcessFromReloadedProcess().StartTime > _processStartTime) { Bindings.PrintInfo($"// Game killed itself, probably due to Steam for restarting. Attempting reattach! | {_attachTargetName}"); Bindings.PrintInfo($"// Consider using the Steam shim."); _gameProcess = localGameProcess; // Disconnect all clients foreach (NetPeer peer in LoaderServer.ReloadedServer.GetPeers()) { LoaderServer.ReloadedServer.DisconnectPeer(peer); } InjectMods(args); // Wait infinitely. while (true) { Console.ReadLine(); } } } // Kill the process itself. Shutdown(null, null); }
/// <summary> /// Checks whether to reattach Reloaded Mod Loader if the game process /// unexpectedly kills itself and then restarts (a standard for some games' launch procedures). /// </summary> /// <param name="arguments">The commandline arguments originally passed to this process.</param> /// <returns>Returns true if another game instance is running, else false.</returns> private static void ProcessSelfReattach(string[] arguments) { // Decides whether bool buildArgumentsList = false; // Auto re-attach if there's another process instance that's up with matching name. // First set the attach name if not set and add to the arguments. if (_attachTargetName == null) { // Set attach name. _attachTargetName = Path.GetFileNameWithoutExtension(_gameConfig.ExecutableLocation); buildArgumentsList = true; } // Use stopwatch for soft timing. Stopwatch timeoutStopWatch = new Stopwatch(); timeoutStopWatch.Start(); // Spin trying to get game process until timeout. while (timeoutStopWatch.ElapsedMilliseconds < 1000) { // Grab current already running game. ReloadedProcess localGameProcess = ReloadedProcess.GetProcessByName(_attachTargetName); // Did we find the process? If not, try again. if (localGameProcess == null) { continue; } // Suspend the resurrected game. localGameProcess.SuspendAllThreads(); // Check if process is newer than our original game process, if it is, restart self. if (localGameProcess.GetProcessFromReloadedProcess().StartTime > _processStartTime) { // If the loader is lacking the "attach" flag. // The reason this is done here is because we want to freeze the // target process as soon as possible, such that we can hook onto it as early as possible. if (buildArgumentsList) { // List of arguments. List <string> argumentsList = arguments.ToList(); // Append attach argument. argumentsList.Add($"{Strings.Common.LoaderSettingAttach}"); // Append attach name. argumentsList.Add(_attachTargetName); // Replace array. arguments = argumentsList.ToArray(); } _gameProcess = localGameProcess; RestartSelf(arguments); break; } // Resume the resurrected game. localGameProcess.ResumeAllThreads(); } // Kill the process itself. Shutdown(null, null); }