public void Dispose() { talker?.UnsubscribeEvents(this); talker?.Dispose(); timer?.Dispose(); process?.UnsubscribeEvents(this); Context = null; scriptPath = null; gamePrivateMessages = null; process = null; talker = null; }
/// <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) { 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; isHosting = client != null && client.MyBattle != null && client.MyBattle.Founder.Name == client.MyUser.Name; if (isHosting) { scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + client.MyBattle.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 = new SpringieService() { Proxy = null }; SpringBattleStartSetup startSetup = null; if (isHosting && GlobalConst.IsZkMod(client.MyBattle.ModName)) { try { StartContext = client.MyBattle.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 = client.MyBattle.GenerateScript(out players, client.MyUser, talker.LoopbackPort, battleGuid.ToString(), startSetup); battleResult.IsMission = client.MyBattle.IsMission; battleResult.IsBots = client.MyBattle.Bots.Any(); battleResult.Title = client.MyBattle.Title; battleResult.Mod = client.MyBattle.ModName; battleResult.Map = client.MyBattle.MapName; battleResult.EngineVersion = paths.SpringVersion; talker.SetPlayers(players); statsPlayers = players.ToDictionary(x => x.Name, x => new BattlePlayerResult { LobbyID = x.LobbyUser.LobbyID, AllyNumber = x.AllyNumber, CommanderType = null, // todo commandertype IsSpectator = x.IsSpectator, IsVictoryTeam = false, Rank = x.LobbyUser.Rank, }); } 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())); process.StartInfo.EnvironmentVariables["OMP_WAIT_POLICY"] = "ACTIVE"; 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); }
private void talker_SpringEvent(object sender, Talker.SpringEventArgs e) { //this.client.Say(SayPlace.Battle, "",string.Format("type:{0} param:{1} player:{2}-{3} text:{4}",e.EventType.ToString(), e.Param,e.PlayerNumber, e.PlayerName, e.Text),false); try { switch (e.EventType) { case Talker.SpringEventType.PLAYER_JOINED: if (StartContext != null) { foreach (var p in StartContext.Players.Where(x => x.Name == e.PlayerName)) { connectedPlayers[p.Name] = true; p.IsIngame = true; } } if (PlayerJoined != null) PlayerJoined(this, new SpringLogEventArgs(e.PlayerName)); break; case Talker.SpringEventType.PLAYER_LEFT: if (StartContext != null) { foreach (var p in StartContext.Players.Where(x => x.Name == e.PlayerName)) { connectedPlayers[p.Name] = false; p.IsIngame = false; } } if (e.Param == 0 && PlayerDisconnected != null) PlayerDisconnected(this, new SpringLogEventArgs(e.PlayerName)); if (PlayerLeft != null) PlayerLeft(this, new SpringLogEventArgs(e.PlayerName)); break; case Talker.SpringEventType.GAME_LUAMSG: HandleSpecialMessages(e); break; case Talker.SpringEventType.PLAYER_CHAT: if (e.Param == 255) HandleSpecialMessages(e); // only public chat if (PlayerSaid != null && (e.Param == Talker.TO_EVERYONE || e.Param == Talker.TO_EVERYONE_LEGACY) && !string.IsNullOrEmpty(e.PlayerName)) PlayerSaid(this, new SpringLogEventArgs(e.PlayerName, e.Text)); break; case Talker.SpringEventType.PLAYER_DEFEATED: StatsMarkDead(e.PlayerName, true); if (PlayerLost != null) PlayerLost(this, new SpringLogEventArgs(e.PlayerName)); break; case Talker.SpringEventType.SERVER_GAMEOVER: if (StartContext != null) foreach (var p in StartContext.Players) p.IsIngame = false; IsBattleOver = true; if (battleResult.IngameStartTime != null) { gameEndedOk = true; battleResult.Duration = (int)DateTime.UtcNow.Subtract(battleResult.IngameStartTime ?? battleResult.StartTime).TotalSeconds; if (GameOver != null) GameOver(this, new SpringLogEventArgs(e.PlayerName)); } else { //gameover before gamestart client.Say(SayPlace.Battle, "", "DEBUG: recieved GAMEOVER before STARTPLAYING!", true); } break; case Talker.SpringEventType.PLAYER_READY: if (e.Param == 1) statsPlayers[e.PlayerName].IsIngameReady = true; break; case Talker.SpringEventType.SERVER_STARTPLAYING: battleResult.IngameStartTime = DateTime.UtcNow; foreach (var p in statsPlayers) { p.Value.IsIngameReady = true; } foreach (var p in StartContext.Players) { bool state; if (!connectedPlayers.TryGetValue(p.Name, out state) || !state) p.IsIngame = false; } BattleStarted(this, EventArgs.Empty); break; case Talker.SpringEventType.SERVER_QUIT: if (StartContext != null) foreach (var p in StartContext.Players) p.IsIngame = false; IsBattleOver = true; //Program.main.AutoHost.SayBattle("dbg quit "); //if (GameOver != null) GameOver(this, new SpringLogEventArgs(e.PlayerName)); break; } } catch (Exception ex) { Trace.TraceError("Error processing spring message:{0}", ex); } }
private void springProcess_Exited(object sender, EventArgs e) { var isCrash = process.ExitCode != 0 && !wasKilled; try { if (!process.WaitForExit(2000)) process.Kill(); } catch {} process = null; talker.Close(); talker = null; Thread.Sleep(1000); var logText = LogLines.ToString(); ParseInfolog(logText, isCrash); try { File.WriteAllText(Path.Combine(paths.WritableDirectory, string.Format("infolog_{0}.txt", battleResult.EngineBattleID)), logText); } catch (Exception ex) { Trace.TraceWarning("Error saving infolog: {0}", ex); } GameExited = DateTime.Now; if (StartContext != null) foreach (var p in StartContext.Players) p.IsIngame = false; IsBattleOver = true; if (SpringExited != null) SpringExited(this, new EventArgs<bool>(isCrash)); }
private void HandleSpecialMessages(Talker.SpringEventArgs e) { try { if (string.IsNullOrEmpty(e.Text) || !e.Text.StartsWith("SPRINGIE:")) return; int count; if (!gamePrivateMessages.TryGetValue(e.Text, out count)) count = 0; count++; gamePrivateMessages[e.Text] = count; if (count != 2) return; // only send if count matches 2 exactly var text = e.Text.Substring(9); if (text.StartsWith("READY:")) { var name = text.Substring(6); BattlePlayerResult entry; if (statsPlayers.TryGetValue(name, out entry)) entry.IsIngameReady = true; } if (text == "FORCE") ForceStart(); statsData.Add(text); } catch (Exception ex) { Trace.TraceError("Error while processing '{0}' :{1}", e.Text, ex); } }
/// <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; }
private void HandleSpecialMessages(Talker.SpringEventArgs e) { try { if (string.IsNullOrEmpty(e.Text) || !e.Text.StartsWith("SPRINGIE:")) return; int count; if (!gamePrivateMessages.TryGetValue(e.Text, out count)) count = 0; count++; gamePrivateMessages[e.Text] = count; if (count != 2) return; // only send if count matches 2 exactly var text = e.Text.Substring(9); if (text.StartsWith("READY:")) { var name = text.Substring(6); var entry = Context.ActualPlayers.FirstOrDefault(x => x.Name == name); if (entry != null) entry.IsIngameReady = true; } if (text == "FORCE") ForceStart(); Context.OutputExtras.Add(text); } catch (Exception ex) { Trace.TraceError("Error while processing '{0}' :{1}", e.Text, ex); } }
private void talker_SpringEvent(object sender, Talker.SpringEventArgs e) { try { switch (e.EventType) { case Talker.SpringEventType.PLAYER_JOINED: var entry = Context?.GetOrAddPlayer(e.PlayerName); if (entry != null) entry.IsIngame = true; PlayerJoined?.Invoke(this, new SpringLogEventArgs(e.PlayerName)); break; case Talker.SpringEventType.PLAYER_LEFT: entry = Context?.GetOrAddPlayer(e.PlayerName); if (entry != null) entry.IsIngame = false; if (e.Param == 0) PlayerDisconnected?.Invoke(this, new SpringLogEventArgs(e.PlayerName)); PlayerLeft?.Invoke(this, new SpringLogEventArgs(e.PlayerName)); break; case Talker.SpringEventType.GAME_LUAMSG: HandleSpecialMessages(e); break; case Talker.SpringEventType.PLAYER_CHAT: if (e.Param == 255) HandleSpecialMessages(e); else AddToLogs(e); // only public chat if ((PlayerSaid != null) && ((e.Param == Talker.TO_EVERYONE) || (e.Param == Talker.TO_EVERYONE_LEGACY)) && !string.IsNullOrEmpty(e.PlayerName)) PlayerSaid(this, new SpringLogEventArgs(e.PlayerName, e.Text)); break; case Talker.SpringEventType.PLAYER_DEFEATED: MarkPlayerDead(e.PlayerName, true); if (PlayerLost != null) PlayerLost(this, new SpringLogEventArgs(e.PlayerName)); break; case Talker.SpringEventType.SERVER_GAMEOVER: if (!Context.GameEndedOk) // server gameover runs multiple times { foreach (var p in Context.ActualPlayers) { if (!p.IsIngame && !p.IsSpectator) MarkPlayerDead(p.Name, true); p.IsIngame = false; } // set victory team for all allied with currently alive foreach (var p in Context.ActualPlayers.Where(x => !x.IsSpectator && (x.LoseTime == null))) foreach (var q in Context.ActualPlayers.Where(x => !x.IsSpectator && (x.AllyNumber == p.AllyNumber))) q.IsVictoryTeam = true; if (Context.IngameStartTime != null) { Context.GameEndedOk = true; Context.Duration = (int)DateTime.UtcNow.Subtract(Context.IngameStartTime ?? Context.StartTime).TotalSeconds; GameOver?.Invoke(this, new SpringLogEventArgs(e.PlayerName)); } else Trace.TraceWarning("recieved GAMEOVER before STARTPLAYING!"); Task.Delay(10000).ContinueWith(x => ExitGame()); } break; case Talker.SpringEventType.PLAYER_READY: if (e.Param == 1) { entry = Context.GetOrAddPlayer(e.PlayerName); if (entry != null) entry.IsIngameReady = true; } break; case Talker.SpringEventType.SERVER_STARTPLAYING: Context.ReplayName = e.ReplayFileName; Context.EngineBattleID = e.GameID; Context.IngameStartTime = DateTime.UtcNow; foreach (var p in Context.ActualPlayers.Where(x => !x.IsSpectator)) p.IsIngameReady = true; BattleStarted(this, EventArgs.Empty); break; case Talker.SpringEventType.SERVER_QUIT: if (LobbyStartContext != null) foreach (var p in Context.ActualPlayers) p.IsIngame = false; //if (GameOver != null) GameOver(this, new SpringLogEventArgs(e.PlayerName)); break; } } catch (Exception ex) { Trace.TraceError("Error processing spring message:{0}", ex); } }
private void dedicatedProcess_Exited(object sender, EventArgs e) { Context.IsCrash = (process.ExitCode != 0) && !Context.WasKilled; process.UnsubscribeEvents(this); try { if (!process.WaitForExit(2000)) process.Kill(); } catch { } process = null; talker.UnsubscribeEvents(this); talker?.Close(); talker = null; Thread.Sleep(1000); if (LobbyStartContext != null) foreach (var p in Context.ActualPlayers) p.IsIngame = false; if (File.Exists(scriptPath)) { try { File.Delete(scriptPath); } catch { } } DedicatedServerExited?.Invoke(this, Context); AnyDedicatedExited?.Invoke(this, Context); }
private void AddToLogs(Talker.SpringEventArgs e) { try { if (string.IsNullOrEmpty(e.Text) || string.IsNullOrEmpty(e.PlayerName)) return; var s = "CHATLOG:" + e.PlayerName + " "; switch (e.Param) { case Talker.TO_EVERYONE: s = s + "<PUBLIC> "; break; case Talker.TO_ALLIES: s = s + "<ALLY> "; break; case Talker.TO_SPECTATORS: s = s + "<SPEC> "; break; default: s = s + "<PRIV> "; break; } s = s + e.Text; Context.OutputExtras.Add(s); } catch (Exception ex) { Trace.TraceError("Error while processing '{0}' :{1}", e.Text, ex); } }
public event EventHandler<SpringLogEventArgs> GameOver; // game has ended public string HostGame(LobbyHostingContext startContext, string host, int port) { if (!File.Exists(paths.GetDedicatedServerPath(startContext.EngineVersion))) throw new ApplicationException($"Dedicated server executable not found: {paths.GetDedicatedServerPath(startContext.EngineVersion)}"); Context = new SpringBattleContext(); Context.SetForHosting(startContext, host, port, null, null); if (!IsRunning) { talker = new Talker(); talker.SpringEvent += talker_SpringEvent; Context.IsHosting = true; scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + startContext.FounderName + ".txt").Replace('\\', '/'); var script = ScriptGenerator.GenerateHostScript(Context, talker.LoopbackPort); timer.Start(); StartDedicated(script); return script; } else Trace.TraceError("Dedicated server already running"); return null; }
public string HostGame(BattleContext context, string host, int port, string myName = null, string myPassword = 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)); wasKilled = false; string script = null; if (!IsRunning) { gameEndedOk = false; IsBattleOver = false; //lobbyUserName = client.UserName; //lobbyPassword = client.UserPassword; battleResult = new BattleResult(); talker = new Talker(); talker.SpringEvent += talker_SpringEvent; isHosting = true; if (isHosting) scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + myName + ".txt").Replace('\\', '/'); else scriptPath = Utils.MakePath(paths.WritableDirectory, "script.txt").Replace('\\', '/'); statsPlayers.Clear(); statsData.Clear(); battleGuid = Guid.NewGuid(); var service = GlobalConst.GetSpringieService(); SpringBattleStartSetup startSetup = null; if (isHosting && GlobalConst.IsZkMod(context.Mod)) { try { StartContext = context; 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 = ScriptGenerator.GenerateHostScript(StartContext, startSetup, talker.LoopbackPort, battleGuid.ToString(), host,port, myName, myPassword); statsPlayers = StartContext.Players.ToDictionary(x => x.Name, x => new BattlePlayerResult { LobbyID = x.LobbyID, AllyNumber = x.AllyID, CommanderType = null, // todo commandertype IsSpectator = x.IsSpectator, IsVictoryTeam = false, }); } if (isHosting) timer.Start(); StartSpring(script); return script; } else Trace.TraceError("Spring already running"); return null; }
private void springProcess_Exited(object sender, EventArgs e) { Context.IsCrash = process.ExitCode != 0 && !Context.WasKilled; process.UnsubscribeEvents(this); try { if (!process.WaitForExit(2000)) process.Kill(); } catch {} process = null; talker.UnsubscribeEvents(this); talker?.Close(); talker = null; Thread.Sleep(1000); var logText = Context.LogLines.ToString(); if (!string.IsNullOrEmpty(Context.InfoLogFileName)) { try { logText = File.ReadAllText(Context.InfoLogFileName); File.Delete(Context.InfoLogFileName); } catch (Exception ex) { Trace.TraceWarning("Error reading infolog: {0}",ex.Message); } } if (Context.IsHosting) ParseInfolog(logText); try { File.WriteAllText(Path.Combine(paths.WritableDirectory, $"infolog_{Context.EngineBattleID}.txt"), logText); } catch (Exception ex) { Trace.TraceWarning("Error saving infolog: {0}", ex); } GameExited = DateTime.Now; if (LobbyStartContext != null) foreach (var p in Context.ActualPlayers) p.IsIngame = false; SpringExited?.Invoke(this, Context); AnySpringExited?.Invoke(this, Context); }