public override void PrePlayPlayer(PlayerInfo playerInfo, int index, HandlerContext context) { if (handlerData.SymlinkGame || handlerData.HardcopyGame) { List <string> dirExclusions = new List <string>(); List <string> fileExclusions = new List <string>(); List <string> fileCopies = new List <string>(); // symlink the game folder (and not the bin folder, if we have one) linkFolder = Path.Combine(tempDir, "Instance" + index); try { if (Directory.Exists(linkFolder)) { Directory.Delete(linkFolder, true); } } catch { } Directory.CreateDirectory(linkFolder); linkWorkingDir = linkFolder; if (!string.IsNullOrEmpty(handlerData.BinariesFolder)) { linkWorkingDir = Path.Combine(linkFolder, handlerData.BinariesFolder); dirExclusions.Add(handlerData.BinariesFolder); } exePath = Path.Combine(linkWorkingDir, Path.GetFileName(this.userGame.ExePath)); if (!string.IsNullOrEmpty(handlerData.WorkingFolder)) { linkWorkingDir = Path.Combine(linkFolder, handlerData.WorkingFolder); dirExclusions.Add(handlerData.WorkingFolder); } // some games have save files inside their game folder, so we need to access them inside the loop handlerData.RegisterAdditional(Folder.InstancedGameFolder.ToString(), linkFolder); if (handlerData.Hook.CustomDllEnabled) { fileExclusions.Add("xinput1_3.dll"); fileExclusions.Add("ncoop.ini"); } if (!handlerData.SymlinkExe) { fileCopies.Add(handlerData.ExecutableName.ToLower()); } // additional ignored files by the generic info if (handlerData.FileSymlinkExclusions != null) { string[] symlinkExclusions = handlerData.FileSymlinkExclusions; for (int k = 0; k < symlinkExclusions.Length; k++) { string s = symlinkExclusions[k]; // make sure it's lower case fileExclusions.Add(s.ToLower()); } } if (handlerData.FileSymlinkCopyInstead != null) { string[] fileSymlinkCopyInstead = handlerData.FileSymlinkCopyInstead; for (int k = 0; k < fileSymlinkCopyInstead.Length; k++) { string s = fileSymlinkCopyInstead[k]; // make sure it's lower case fileCopies.Add(s.ToLower()); } } if (handlerData.DirSymlinkExclusions != null) { string[] symlinkExclusions = handlerData.DirSymlinkExclusions; for (int k = 0; k < symlinkExclusions.Length; k++) { string s = symlinkExclusions[k]; // make sure it's lower case dirExclusions.Add(s.ToLower()); } } string[] fileExclusionsArr = fileExclusions.ToArray(); string[] fileCopiesArr = fileCopies.ToArray(); if (handlerData.HardcopyGame) { // copy the directory //int exitCode; //FileUtil.CopyDirectory(rootFolder, new DirectoryInfo(rootFolder), linkFolder, out exitCode, dirExclusions.ToArray(), fileExclusionsArr, true); } else { int exitCode; //CmdUtil.LinkDirectory(rootFolder, new DirectoryInfo(rootFolder), linkFolder, out exitCode, dirExclusions.ToArray(), fileExclusionsArr, fileCopiesArr, true); WinDirectoryUtil.LinkDirectory(rootFolder, new DirectoryInfo(rootFolder), linkFolder, out exitCode, dirExclusions.ToArray(), fileExclusionsArr, fileCopiesArr, true); if (!handlerData.SymlinkExe) { //File.Copy(userGame.ExePath, exePath, true); } } } else { exePath = userGame.ExePath; linkWorkingDir = rootFolder; linkFolder = workingFolder; } context.ExePath = exePath; context.RootInstallFolder = exeFolder; context.RootFolder = linkFolder; }
private static void ExecuteTask(StartGameData data) { switch (data.Task) { case GameStarterTask.StartGame: { string gamePath = data.Parameters[0]; string gameArgs = data.Parameters[1]; string gameWorkingDir = data.Parameters[2]; ConsoleU.WriteLine($"Start game: EXE: {gamePath} ARGS: {gameArgs} WORKDIR: {gameWorkingDir}", Palette.Feedback); StartGame(gamePath, gameArgs, gameWorkingDir); } break; case GameStarterTask.KillMutex: { Log.WriteLine($"Kill Mutex Task"); string procId = data.Parameters[0]; string[] mutexes = new string[data.Parameters.Length - 1]; for (int j = 1; j < data.Parameters.Length; j++) { string m = data.Parameters[j]; mutexes[j - 1] = m; } KillMutex(procId, mutexes); WriteToDataFile(Assembly.GetEntryAssembly().Location, true.ToString()); } break; case GameStarterTask.RenameMutex: { Log.WriteLine($"Rename Mutex Task"); string procId = data.Parameters[0]; string[] mutexes = new string[data.Parameters.Length - 1]; for (int j = 1; j < data.Parameters.Length; j++) { string m = data.Parameters[j]; mutexes[j - 1] = m; } KillMutex(procId, mutexes); WriteToDataFile(Assembly.GetEntryAssembly().Location, true.ToString()); } break; case GameStarterTask.ScanKillMutex: { Log.WriteLine($"Scan Kill Mutex"); List <int> processIds = new List <int>(); for (int j = 0; j < data.Parameters.Length; j++) { string scanMutexDataRaw = data.Parameters[j]; ScanMutexData scanMutex = JsonConvert.DeserializeObject <ScanMutexData>(scanMutexDataRaw); Log.WriteLine($"Kill Mutex for process {scanMutex.ProcessName}"); for (; ;) { Process[] procs = Process.GetProcessesByName(scanMutex.ProcessName); if (procs == null || procs.Length == 0) { Thread.Sleep(250); } else { // kill mutexes bool killedMutexes = false; for (int k = 0; k < procs.Length; k++) { Process p = procs[k]; if (processIds.Contains(p.Id)) { continue; } // start other process, as the mutexes are only truly killed // when the process is ended if (scanMutex.ShouldRename) { StartGameUtil.RenameMutex(p, scanMutex.Mutexes); } else { StartGameUtil.KillMutex(p, scanMutex.Mutexes); } //KillMutex(p.Id.ToString(), scanMutex.Mutexes); processIds.Add(p.Id); killedMutexes = true; break; } if (killedMutexes) { Log.WriteLine($"Killed all mutexes for process {scanMutex.ProcessName}"); WriteToDataFile(Assembly.GetEntryAssembly().Location, true.ToString()); break; } } } } } break; case GameStarterTask.MultipleTasks: { Log.WriteLine($"Multiple tasks"); for (int j = 0; j < data.Parameters.Length; j++) { string taskDataRaw = data.Parameters[j]; StartGameData taskData = JsonConvert.DeserializeObject <StartGameData>(taskDataRaw); Log.WriteLine($"Executing task {j + 1}"); ExecuteTask(taskData); } } break; case GameStarterTask.QueryMutex: { string procId = data.Parameters[0]; string[] mutexes = new string[data.Parameters.Length - 1]; for (int j = 1; j < data.Parameters.Length; j++) { string m = data.Parameters[j]; mutexes[j - 1] = m; } } break; case GameStarterTask.ListMonitors: break; case GameStarterTask.ScanGames: { // initialize game manager to read available handlers GameManager gameManager = new GameManager(); List <string> games = new List <string>(); for (int j = 0; j < data.Parameters.Length; j++) { string driveName = data.Parameters[j]; //SearchStorageInfo info = JsonConvert.DeserializeObject<SearchStorageInfo>(storageData); DriveInfo drive = new DriveInfo(driveName); if (!drive.IsReady) { continue; } Log.WriteLine($"> Searching drive {drive.Name} for game executables"); Dictionary <ulong, FileNameAndParentFrn> allExes = new Dictionary <ulong, FileNameAndParentFrn>(); MFTReader mft = new MFTReader(); mft.Drive = drive.RootDirectory.FullName; // TODO: search only for specific games? mft.EnumerateVolume(out allExes, new string[] { ".exe" }); foreach (KeyValuePair <UInt64, FileNameAndParentFrn> entry in allExes) { FileNameAndParentFrn file = (FileNameAndParentFrn)entry.Value; string name = file.Name; string lower = name.ToLower(); string path = mft.GetFullPath(file); if (path.Contains("$Recycle.Bin") || path.Contains(@"\Instance")) { // noope continue; } if (GameManager.Instance.AnyGame(lower)) { Log.WriteLine($"Found game at path: {path}"); games.Add(path); } } } WriteToDataFile(Assembly.GetEntryAssembly().Location, JsonConvert.SerializeObject(games)); } break; case GameStarterTask.SymlinkFolders: for (int j = 0; j < data.Parameters.Length; j++) { string symData = data.Parameters[j]; Log.WriteLine($"Symlink game instance {j + 1}"); SymlinkGameData gameData = JsonConvert.DeserializeObject <SymlinkGameData>(symData); int exitCode; WinDirectoryUtil.LinkDirectory(gameData.SourcePath, new DirectoryInfo(gameData.SourcePath), gameData.DestinationPath, out exitCode, gameData.DirExclusions, gameData.FileExclusions, gameData.FileCopies, true); } WriteToDataFile(Assembly.GetEntryAssembly().Location, true.ToString()); break; } }