/// <summary> /// Starts spring game /// </summary> /// <param name="client">tasclient to get current battle from</param> /// <param name="priority">spring process priority</param> /// <param name="affinity">spring process cpu affinity</param> /// <param name="scriptOverride">if set, overrides generated script with supplied one</param> /// <param name="userName">lobby user name - used to submit score</param> /// <param name="passwordHash">lobby password hash - used to submit score</param> /// <returns>generates script</returns> public string StartGame(TasClient client, ProcessPriorityClass?priority, int?affinity, string scriptOverride, bool useSafeMode = false, bool useMultithreaded = false, BattleContext contextOverride = null, Battle battleOverride = null) { if (!File.Exists(paths.Executable) && !File.Exists(paths.DedicatedServer)) { throw new ApplicationException(string.Format("Spring or dedicated server executable not found: {0}, {1}", paths.Executable, paths.DedicatedServer)); } this.client = client; wasKilled = false; if (!IsRunning) { gameEndedOk = false; IsBattleOver = false; lobbyUserName = client.UserName; lobbyPassword = client.UserPassword; battleResult = new BattleResult(); talker = new Talker(); talker.SpringEvent += talker_SpringEvent; var battle = battleOverride ?? client.MyBattle; isHosting = client != null && battle != null && battle.Founder.Name == client.MyUser.Name; if (isHosting) { scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + battle.Founder + ".txt").Replace('\\', '/'); } else { scriptPath = Utils.MakePath(paths.WritableDirectory, "script.txt").Replace('\\', '/'); } statsPlayers.Clear(); statsData.Clear(); StartContext = null; string script; if (!string.IsNullOrEmpty(scriptOverride)) { battleResult.IsMission = true; isHosting = false; script = scriptOverride; } else { List <UserBattleStatus> players; battleGuid = Guid.NewGuid(); var service = GlobalConst.GetSpringieService(); SpringBattleStartSetup startSetup = null; if (isHosting && GlobalConst.IsZkMod(battle.ModName)) { try { StartContext = contextOverride ?? battle.GetContext(); startSetup = service.GetSpringBattleStartSetup(StartContext); if (startSetup.BalanceTeamsResult != null) { StartContext.Players = startSetup.BalanceTeamsResult.Players; StartContext.Bots = startSetup.BalanceTeamsResult.Bots; } connectedPlayers.Clear(); foreach (var p in StartContext.Players) { p.IsIngame = true; } } catch (Exception ex) { Trace.TraceError("Error getting start setup: {0}", ex); } } script = battle.GenerateScript(out players, client.MyUser, talker.LoopbackPort, battleGuid.ToString(), startSetup); battleResult.IsMission = battle.IsMission; battleResult.IsBots = battle.Bots.Any(); battleResult.Title = battle.Title; battleResult.Mod = battle.ModName; battleResult.Map = battle.MapName; battleResult.EngineVersion = paths.SpringVersion; talker.SetPlayers(players); statsPlayers = players.ToDictionary(x => x.Name, x => new BattlePlayerResult { LobbyID = x.LobbyUser.AccountID, AllyNumber = x.AllyNumber, CommanderType = null, // todo commandertype IsSpectator = x.IsSpectator, IsVictoryTeam = false, }); } if (isHosting) { timer.Start(); } File.WriteAllText(scriptPath, script); LogLines = new StringBuilder(); var optirun = Environment.GetEnvironmentVariable("OPTIRUN"); process = new Process(); process.StartInfo.CreateNoWindow = true; List <string> arg = new List <string>(); if (string.IsNullOrEmpty(optirun)) { if (UseDedicatedServer) { process.StartInfo.FileName = paths.DedicatedServer; process.StartInfo.WorkingDirectory = Path.GetDirectoryName(paths.DedicatedServer); } else { process.StartInfo.FileName = useMultithreaded ? paths.MtExecutable : paths.Executable; process.StartInfo.WorkingDirectory = Path.GetDirectoryName(paths.Executable); } } else { Trace.TraceInformation("Using optirun {0} to start the game (OPTIRUN env var defined)", optirun); process.StartInfo.FileName = optirun; arg.Add(string.Format("\"{0}\"", (useMultithreaded ? paths.MtExecutable : paths.Executable))); } arg.Add(string.Format("--config \"{0}\"", paths.GetSpringConfigPath())); if (useSafeMode) { arg.Add("--safemode"); } arg.Add(string.Format("\"{0}\"", scriptPath)); //Trace.TraceInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); process.StartInfo.Arguments = string.Join(" ", arg); process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Exited += springProcess_Exited; process.ErrorDataReceived += process_ErrorDataReceived; process.OutputDataReceived += process_OutputDataReceived; process.EnableRaisingEvents = true; gamePrivateMessages = new Dictionary <string, int>(); battleResult.StartTime = DateTime.UtcNow; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); if (IsRunning && SpringStarted != null) { SpringStarted(this, EventArgs.Empty); } Utils.StartAsync(() => { Thread.Sleep(1000); try { if (priority != null) { process.PriorityClass = priority.Value; } if (affinity != null) { process.ProcessorAffinity = (IntPtr)affinity.Value; } } catch (Exception ex) { Trace.TraceWarning("Error setting spring process affinity: {0}", ex); } }); return(script); } else { Trace.TraceError("Spring already running"); } return(null); }