public static void LinkDirectory(string root, DirectoryInfo currentDir, string destination, out int exitCode, string[] dirExclusions, string[] fileExclusions, string[] fileCopyInstead, bool isSymlink, bool overrideSpecial = false) { exitCode = 1; bool special = overrideSpecial; for (int j = 0; j < dirExclusions.Length; j++) { string exclusion = dirExclusions[j]; string fullPath = Path.Combine(root, exclusion).ToLower(); if (fullPath.Contains(currentDir.FullName.ToLower())) { // special case, one of our subfolders is excluded special = true; break; } } if (special) { // this folder has a child that cant be symlinked Directory.CreateDirectory(destination); CmdUtil.LinkFiles(currentDir.FullName, destination, out exitCode, fileExclusions, fileCopyInstead, isSymlink); DirectoryInfo[] children = currentDir.GetDirectories(); for (int i = 0; i < children.Length; i++) { DirectoryInfo child = children[i]; LinkDirectory(root, child, Path.Combine(destination, child.Name), out exitCode, dirExclusions, fileExclusions, fileCopyInstead, isSymlink); } } else { // we symlink this directly CmdUtil.MkLinkDirectory(currentDir.FullName, destination, out exitCode); } }
public string Play() { List <PlayerInfo> players = profile.PlayerData; Screen[] all = Screen.AllScreens; string backupDir = GameManager.Instance.GetBackupFolder(this.userGame.Game); string binFolder = Path.GetDirectoryName(userGame.ExePath); string rootFolder = ReplaceCaseInsensitive(binFolder, gen.BinariesFolder, ""); int gamePadId = 0; bool first = true; hidetaskbar = false; bool keyboard = false; if (gen.SupportsKeyboard) { // make sure the keyboard player is the last to be started, // so it will get the focus by default KeyboardPlayer player = (KeyboardPlayer)profile.Options["KeyboardPlayer"]; if (player.Value != -1) { keyboard = true; List <PlayerInfo> newPlayers = new List <PlayerInfo>(); for (int i = 0; i < players.Count; i++) { PlayerInfo p = players[i]; if (i == player.Value) { continue; } newPlayers.Add(p); } newPlayers.Add(players[player.Value]); players = newPlayers; } } for (int i = 0; i < players.Count; i++) { PlayerInfo player = players[i]; if (i > 0 && gen.KillMutex.Length > 0) { PlayerInfo before = players[i - 1]; for (;;) { if (exited > 0) { return(""); } Thread.Sleep(100); if (before.ProcessData.KilledMutexes) { break; } } } Rectangle playerBounds = player.MonitorBounds; // find the monitor that has this screen Screen owner = null; for (int j = 0; j < all.Length; j++) { Screen s = all[j]; if (s.Bounds.Contains(playerBounds)) { owner = s; break; } } int width = playerBounds.Width; int height = playerBounds.Height; bool isFullscreen = false; if (owner != null) { Rectangle ob = owner.Bounds; if (playerBounds.X == ob.X && playerBounds.Y == ob.Y && playerBounds.Width == ob.Width && playerBounds.Height == ob.Height) { isFullscreen = true; } } GenericContext context = gen.CreateContext(profile, player, this); context.PlayerID = i; context.IsFullscreen = isFullscreen; context.IsKeyboardPlayer = keyboard && i == players.Count - 1; gen.PrePlay(context); player.IsKeyboardPlayer = context.IsKeyboardPlayer; string saveFile = context.SavePath; if (gen.SaveType != SaveType.None && first) { GameManager.Instance.BeginBackup(gen); GameManager.Instance.BackupFile(gen, saveFile); } // symlink the game folder // find out the folder that contains the game executable string root = GetRootFolder(gen.BinariesFolder); string linkFolder = Path.Combine(backupDir, "Instance" + i); Directory.CreateDirectory(linkFolder); int exitCode; CmdUtil.LinkDirectories(rootFolder, linkFolder, out exitCode, root.ToLower()); string linkBin = Path.Combine(linkFolder, gen.BinariesFolder); if (!string.IsNullOrEmpty(gen.BinariesFolder)) { // this needs fixing, if there are several folder to the exe and they have important files inside, this won't work! TODO Directory.CreateDirectory(linkBin); CmdUtil.LinkDirectories(binFolder, linkBin, out exitCode); } string exePath = Path.Combine(linkBin, this.userGame.Game.ExecutableName); if (context.SymlinkExe) { CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput", "ncoop"); } else { CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput", "ncoop", Path.GetFileNameWithoutExtension(gen.ExecutableName.ToLower())); File.Copy(userGame.ExePath, exePath, true); } // some games have save files inside their game folder, so we need to access them inside the loop this.data[Folder.GameFolder.ToString()] = linkFolder; IniFile file = new IniFile(saveFile); switch (context.SaveType) { case SaveType.INI: for (int j = 0; j < context.ModifySave.Length; j++) { SaveInfo save = context.ModifySave[j]; if (save is IniSaveInfo) { IniSaveInfo ini = (IniSaveInfo)save; file.IniWriteValue(ini.Section, ini.Key, ini.Value); } } break; } string startArgs = context.StartArguments; if (context.CustomXinput) { byte[] xdata = null; if (context.IsKeyboardPlayer) { // TODO: need to make an xinput that answers to no gamepad? xdata = Properties.Resources.xinput4; } else { switch (gamePadId) { case 0: xdata = Properties.Resources.xinput1; break; case 1: xdata = Properties.Resources.xinput2; break; case 2: xdata = Properties.Resources.xinput3; break; case 3: default: xdata = Properties.Resources.xinput4; break; } gamePadId++; } using (Stream str = File.OpenWrite(Path.Combine(linkBin, "xinput1_3.dll"))) { str.Write(xdata, 0, xdata.Length); } string ncoopIni = Path.Combine(linkBin, "ncoop.ini"); using (Stream str = File.OpenWrite(ncoopIni)) { byte[] ini = Properties.Resources.ncoop; str.Write(ini, 0, ini.Length); } IniFile x360 = new IniFile(ncoopIni); x360.IniWriteValue("Options", "HookWindows", context.HookWindows.ToString(CultureInfo.InvariantCulture)); x360.IniWriteValue("Options", "HookGameWindow", context.HookGameWindow.ToString(CultureInfo.InvariantCulture)); x360.IniWriteValue("Options", "HookNeeded", context.HookNeeded.ToString(CultureInfo.InvariantCulture)); } Process proc; if (context.NeedsSteamEmulation) { string steamEmu = GameManager.Instance.ExtractSteamEmu(); if (string.IsNullOrEmpty(steamEmu)) { return("Extraction of SmartSteamEmu failed!"); } string emuExe = Path.Combine(steamEmu, "SmartSteamLoader.exe"); string emuIni = Path.Combine(steamEmu, "SmartSteamEmu.ini"); IniFile emu = new IniFile(emuIni); emu.IniWriteValue("Launcher", "Target", exePath); emu.IniWriteValue("Launcher", "StartIn", Path.GetDirectoryName(exePath)); emu.IniWriteValue("Launcher", "CommandLine", startArgs); emu.IniWriteValue("Launcher", "SteamClientPath", Path.Combine(steamEmu, "SmartSteamEmu.dll")); emu.IniWriteValue("Launcher", "SteamClientPath64", Path.Combine(steamEmu, "SmartSteamEmu64.dll")); emu.IniWriteValue("Launcher", "InjectDll", "0"); emu.IniWriteValue("SmartSteamEmu", "AppId", context.SteamID); if (context.KillMutex.Length > 0) { // to kill the mutexes we need to orphanize the process proc = ProcessUtil.RunOrphanProcess(emuExe); } else { ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = emuExe; proc = Process.Start(startInfo); } player.SteamEmu = true; } else { if (context.KillMutex.Length > 0) { proc = Process.GetProcessById(StartGameUtil.StartGame(exePath, startArgs)); } else { ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = exePath; startInfo.WindowStyle = ProcessWindowStyle.Hidden; startInfo.Arguments = startArgs; startInfo.UseShellExecute = true; startInfo.WorkingDirectory = Path.GetDirectoryName(exePath); proc = Process.Start(startInfo); } if (proc == null) { for (int times = 0; times < 200; times++) { Thread.Sleep(50); Process[] procs = Process.GetProcesses(); string proceName = Path.GetFileNameWithoutExtension(context.ExecutableName).ToLower(); string launcherName = Path.GetFileNameWithoutExtension(context.LauncherExe).ToLower(); for (int j = 0; j < procs.Length; j++) { Process p = procs[j]; string lowerP = p.ProcessName.ToLower(); if (((lowerP == proceName) || lowerP == launcherName) && !attached.Contains(p)) { attached.Add(p); proc = p; break; } } if (proc != null) { break; } } } else { attached.Add(proc); } } ProcessData data = new ProcessData(proc); data.Position = new Point(playerBounds.X, playerBounds.Y); data.Size = new Size(playerBounds.Width, playerBounds.Height); data.KilledMutexes = context.KillMutex.Length == 0; player.ProcessData = data; if (first) { if (context.HideTaskbar) { hidetaskbar = true; } } first = false; } //if (hidetaskbar) //{ // User32.HideTaskbar(); //} return(string.Empty); }
public string Play() { List <PlayerInfo> players = profile.PlayerData; Screen[] all = Screen.AllScreens; string backupDir = GameManager.Instance.GetBackupFolder(this.userGame.Game); string binFolder = Path.GetDirectoryName(userGame.ExePath); string rootFolder = ReplaceCaseInsensitive(binFolder, gen.BinariesFolder, ""); int gamePadId = 0; for (int i = 0; i < players.Count; i++) { PlayerInfo player = players[i]; if (i > 0 && gen.KillMutex.Length > 0) { PlayerInfo before = players[i - 1]; for (;;) { if (exited > 0) { return(""); } Thread.Sleep(100); if (before.screenData.KilledMutexes) { break; } } } Rectangle playerBounds = player.monitorBounds; // find the monitor that has this screen Screen owner = null; for (int j = 0; j < all.Length; j++) { Screen s = all[j]; if (s.Bounds.Contains(playerBounds)) { owner = s; break; } } int width = playerBounds.Width; int height = playerBounds.Height; bool isFullscreen = false; if (owner != null) { Rectangle ob = owner.Bounds; if (playerBounds.X == ob.X && playerBounds.Y == ob.Y && playerBounds.Width == ob.Width && playerBounds.Height == ob.Height) { isFullscreen = true; } } engine.SetValue("Id", i.ToString(CultureInfo.InvariantCulture)); engine.SetValue("Width", width.ToString(CultureInfo.InvariantCulture)); engine.SetValue("Height", height.ToString(CultureInfo.InvariantCulture)); engine.SetValue("IsFullscreen", isFullscreen); // symlink the game folder // find out the folder that contains the game executable string root = GetRootFolder(gen.BinariesFolder); string linkFolder = Path.Combine(backupDir, "Instance" + i); Directory.CreateDirectory(linkFolder); int exitCode; CmdUtil.LinkDirectories(rootFolder, linkFolder, out exitCode, root.ToLower()); string linkBin = Path.Combine(linkFolder, gen.BinariesFolder); if (!string.IsNullOrEmpty(gen.BinariesFolder)) { // this needs fixing, if there are several folder to the exe and they have important files inside, this won't work! TODO Directory.CreateDirectory(linkBin); CmdUtil.LinkDirectories(binFolder, linkBin, out exitCode); } string exePath = Path.Combine(linkBin, this.userGame.Game.ExecutableName); if (gen.SymlinkExe) { CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput"); } else { CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput", Path.GetFileNameWithoutExtension(gen.ExecutableName.ToLower())); File.Copy(userGame.ExePath, exePath, true); } // some games have save files inside their game folder, so we need to access them inside the loop this.data[NucleusFolderEnum.GameFolder.ToString()] = linkFolder; string saveFile = ProcessPath(gen.SavePath); IniFile file = new IniFile(saveFile); switch (gen.SaveType) { case GenericGameSaveType.INI: foreach (var modPair in gen.ModifySave) { string key = modPair.Key; string[] keys = key.Split('/'); engine.Execute(modPair.Value); string val = engine.GetCompletionValue().ToString(); file.IniWriteValue(keys[0], keys[1], val); } break; } string startArgs = gen.StartArguments; byte[] xdata = null; if (gen.SupportsKeyboard && i == (int)profile.Options["KeyboardPlayer"]) { engine.SetValue("Keyboard", true); // need to make an xinput that answers to no gamepad? xdata = Properties.Resources.xinput4; } else { engine.SetValue("Keyboard", false); switch (gamePadId) { case 0: xdata = Properties.Resources.xinput1; break; case 1: xdata = Properties.Resources.xinput2; break; case 2: xdata = Properties.Resources.xinput3; break; case 3: xdata = Properties.Resources.xinput4; break; default: xdata = Properties.Resources.xinput4; break; } gamePadId++; } using (Stream str = File.OpenWrite(Path.Combine(linkBin, "xinput1_3.dll"))) { str.Write(xdata, 0, xdata.Length); } if (!string.IsNullOrEmpty(startArgs)) { startArgs = engine.Execute(startArgs).GetCompletionValue().AsString(); } if (gen.NeedsSteamEmulation) { string steamEmu = GameManager.Instance.ExtractSteamEmu(); string emuExe = Path.Combine(steamEmu, "SmartSteamLoader.exe"); string emuIni = Path.Combine(steamEmu, "SmartSteamEmu.ini"); IniFile emu = new IniFile(emuIni); emu.IniWriteValue("Launcher", "Target", exePath); emu.IniWriteValue("Launcher", "StartIn", Path.GetDirectoryName(exePath)); emu.IniWriteValue("Launcher", "CommandLine", startArgs); emu.IniWriteValue("Launcher", "SteamClientPath", Path.Combine(steamEmu, "SmartSteamEmu.dll")); emu.IniWriteValue("Launcher", "SteamClientPath64", Path.Combine(steamEmu, "SmartSteamEmu64.dll")); emu.IniWriteValue("Launcher", "InjectDll", "0"); emu.IniWriteValue("SmartSteamEmu", "AppId", gen.SteamID); Process proc; if (gen.KillMutex.Length > 0) { // to kill the mutexes we need to orphanize the process proc = ProcessUtil.RunOrphanProcess(emuExe); } else { ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = emuExe; proc = Process.Start(startInfo); } player.Process = proc; player.SteamEmu = true; } else { Process proc; if (gen.KillMutex.Length > 0) { proc = Process.GetProcessById(StartGameUtil.StartGame(exePath, startArgs)); } else { ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = exePath; startInfo.WindowStyle = ProcessWindowStyle.Hidden; startInfo.Arguments = startArgs; startInfo.UseShellExecute = true; startInfo.WorkingDirectory = Path.GetDirectoryName(exePath); proc = Process.Start(startInfo); } if (proc == null) { for (int times = 0; times < 200; times++) { Thread.Sleep(50); Process[] procs = Process.GetProcesses(); string proceName = Path.GetFileNameWithoutExtension(gen.ExecutableName).ToLower(); string launcherName = Path.GetFileNameWithoutExtension(gen.LauncherExe).ToLower(); for (int j = 0; j < procs.Length; j++) { Process p = procs[j]; string lowerP = p.ProcessName.ToLower(); if (((lowerP == proceName) || lowerP == launcherName) && !attached.Contains(p)) { attached.Add(p); proc = p; break; } } if (proc != null) { break; } } } else { attached.Add(proc); } player.Process = proc; } ScreenData data = new ScreenData(); data.Position = new Point(playerBounds.X, playerBounds.Y); data.Size = new Size(playerBounds.Width, playerBounds.Height); data.KilledMutexes = gen.KillMutex.Length == 0; player.screenData = data; } return(string.Empty); }