void tas_MyBattleMapChanged(object sender, BattleInfoEventArgs e1) { lastMapChange = DateTime.Now; Battle b = tas.MyBattle; string mapName = b.MapName.ToLower(); if (SpawnConfig == null) { ComResetOptions(TasSayEventArgs.Default, new string[] { }); } try { var serv = new SpringieService(); string commands = serv.GetMapCommands(mapName); if (!string.IsNullOrEmpty(commands)) { foreach (string c in commands.Split('\n').Where(x => !string.IsNullOrEmpty(x))) { RunCommand(c); } } } catch (Exception ex) { Trace.TraceError("Error procesing map commands: {0}", ex); } }
protected override void SuccessAction() { try { bool val; var moves = tas.MyBattle.Users.Where(x => x.Name != tas.MyBattle.Founder.Name) .Where(x => !userVotes.TryGetValue(x.Name, out val) || val) .Select(x => new MovePlayerEntry() { BattleHost = host, PlayerName = x.Name }) .ToArray(); // move all that didnt vote "no" var serv = new SpringieService(); serv.MovePlayers(tas.UserName, tas.UserPassword, moves.ToArray()); } catch (Exception ex) { ah.SayBattle(ex.ToString()); } }
public void UpdateAll() { try { using (var serv = new SpringieService()) { serv.Timeout = 5000; var configs = serv.GetClusterConfigs(Config.ClusterNode); lock (autoHosts) { foreach (var conf in configs) { if (!autoHosts.Any(x => x.config.Login == conf.Login)) { SpawnAutoHost(conf, null); } else { foreach (var ah in autoHosts.Where(x => x.config.Login == conf.Login && x.SpawnConfig == null)) { ah.config = conf; } } } var todel = autoHosts.Where(x => !configs.Any(y => y.Login == x.config.Login)).ToList(); foreach (var ah in todel) { StopAutohost(ah); } } } } catch (Exception ex) { Trace.TraceError("Error in periodic updates: {0}", ex); } }
public override void End() { bool val; try { var moves = tas.MyBattle.Users.Where(x => x.Name != tas.MyBattle.Founder.Name) .Where(x => userVotes.TryGetValue(x.Name, out val) && val) .Select(x => new MovePlayerEntry() { BattleHost = host, PlayerName = x.Name }) .ToArray(); // move those that voted yes if there are at least 2 if (moves.Length > 1) { var serv = new SpringieService(); serv.MovePlayers(tas.UserName, tas.UserPassword, moves.ToArray()); } } catch (Exception ex) { ah.SayBattle(ex.ToString()); } base.End(); }
private void ParseInfolog(string text, bool isCrash) { if (string.IsNullOrEmpty(text)) { Trace.TraceWarning("Infolog is empty"); return; } try { var hasError = false; var modName = battleResult.Mod; var mapName = battleResult.Map; var isCheating = false; int? score = null; int scoreFrame = 0; string gameId = null; string demoFileName = null; string missionVars = ""; foreach (var cycleline in text.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries)) { var line = cycleline; var gameframe = 0; if (line.StartsWith("[DedicatedServer]")) { line = line.Replace("[DedicatedServer] ", ""); } if (line.StartsWith("[")) { var idx = line.IndexOf("] "); if (idx > 0) { int.TryParse(line.Substring(1, idx - 1), out gameframe); if (idx >= 0) { line = line.Substring(idx + 2); } } } // FIXME: why are these even null in the first place? if (mapName == null && line.StartsWith("Using map")) { mapName = line.Substring(10).Trim(); } if (modName == null && line.StartsWith("Using game")) { modName = line.Substring(11).Trim(); } if (line.StartsWith("recording demo")) { demoFileName = Path.GetFileName(line.Substring(15).Trim()); // 91.0 } else if (line.StartsWith("[DedicatedServer] recording demo")) { demoFileName = Path.GetFileName(line.Substring(33).Trim()); // 95.0 and later } if (line.StartsWith("Using demofile")) { return; // do nothing if its demo } if (line.StartsWith("GameID: ") && gameId == null) { gameId = line.Substring(8).Trim(); } if (line.StartsWith("STATS:")) { statsData.Add(line.Substring(6)); } if (line.Contains("SCORE: ") && !isCheating && battleResult.IsMission) { var match = Regex.Match(line, "SCORE: ([^ ]+)"); if (match.Success) { // game score var data = match.Groups[1].Value; //Trace.TraceInformation("Score data (raw) : " + data); data = Encoding.ASCII.GetString(Convert.FromBase64String(match.Groups[1].Value)); //Trace.TraceInformation("Score data (decoded) : " + data); var parts = data.Split('/'); score = 0; if (parts.Length > 1) { score = Convert.ToInt32(parts[1]); gameframe = Convert.ToInt32(parts[0]); } else { score = Convert.ToInt32(data); } scoreFrame = gameframe; } } if (line.Contains("MISSIONVARS:") && battleResult.IsMission) { var match = Regex.Match(line, "MISSIONVARS: ([^ ]+)"); missionVars = match.Groups[1].Value.Trim(); Trace.TraceInformation(string.Format("Mission variables: {0} (original line: {1})", missionVars, line)); } // obsolete, hanlded by pm messages //if (line.StartsWith("STATS:")) statsData.Add(line.Substring(6)); if (line.StartsWith("Cheating!") || line.StartsWith("Cheating is enabled!")) { isCheating = true; } if (line.StartsWith("Error") || line.StartsWith("LuaRules") || line.StartsWith("Internal error") || line.StartsWith("LuaCOB") || (line.StartsWith("Failed to load") && !line.Contains("duplicate name"))) { hasError = true; } } if (score != null || !String.IsNullOrEmpty(missionVars)) { Trace.TraceInformation("Submitting score for mission " + modName); try { using (var service = new ContentService { Proxy = null }) { service.SubmitMissionScoreCompleted += (s, e) => { if (e.Error != null) { if (e.Error is WebException) { Trace.TraceWarning("Error sending score: {0}", e.Error); } else { Trace.TraceError("Error sending score: {0}", e.Error); } } }; service.SubmitMissionScoreAsync(lobbyUserName, Utils.HashLobbyPassword(lobbyPassword), modName, score ?? 0, scoreFrame / 30, missionVars); } } catch (Exception ex) { Trace.TraceError(string.Format("Error sending mission score: {0}", ex)); } } var modOk = GlobalConst.IsZkMod(modName); // submit main stats if (!isCheating && !isCrash && modOk && gameEndedOk) { if (isHosting) { var service = new SpringieService() { Proxy = null }; var mis = new ContentService() { Proxy = null }; try { battleResult.EngineBattleID = gameId; battleResult.ReplayName = demoFileName; // set victory team for all allied with currently alive foreach (var p in statsPlayers.Values.Where(x => !x.IsSpectator && x.LoseTime == null)) { foreach (var q in statsPlayers.Values.Where(x => !x.IsSpectator && x.AllyNumber == p.AllyNumber)) { q.IsVictoryTeam = true; } } if (StartContext != null) { var result = service.SubmitSpringBattleResult(StartContext, lobbyPassword, battleResult, Enumerable.ToArray(statsPlayers.Values), statsData.ToArray()); if (result != null) { foreach (var line in result.Split('\n')) { client.Say(TasClient.SayPlace.Battle, "", line, true); } } } } catch (Exception ex) { Trace.TraceError("Error sending game result: {0}", ex); } } if (statsData.Count > 1) { // must be more than 1 line - 1 is player list var statsService = new StatsCollector { Proxy = null }; try { statsService.SubmitGameEx(gameId, modName, mapName, statsData.ToArray()); } catch (Exception ex) { Trace.TraceError("Error sending game stats: {0}", ex); } } } } catch (Exception ex) { Trace.TraceError("Error processing spring log: {0}", 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) { 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); }
void tas_BattleUserJoined(object sender, BattleUserEventArgs e1) { if (e1.BattleID != tas.MyBattleID) { return; } string name = e1.UserName; if (tas.ExistingUsers[name].BanLobby) { tas.Kick(name); return; } string welc = config.Welcome; if (welc != "") { welc = welc.Replace("%1", name); welc = welc.Replace("%2", GetUserLevel(name).ToString()); welc = welc.Replace("%3", MainConfig.SpringieVersion); SayBattlePrivate(name, welc); } if (spring.IsRunning) { spring.AddUser(e1.UserName, e1.ScriptPassword); TimeSpan started = DateTime.Now.Subtract(spring.GameStarted); started = new TimeSpan((int)started.TotalHours, started.Minutes, started.Seconds); SayBattlePrivate(name, String.Format("GAME IS CURRENTLY IN PROGRESS, PLEASE WAIT TILL IT ENDS! Running for {0}", started)); SayBattlePrivate(name, "If you say !notify, I will PM you when game ends."); } if (SpawnConfig == null) { try { var serv = new SpringieService(); PlayerJoinResult ret = serv.AutohostPlayerJoined(tas.MyBattle.GetContext(), tas.ExistingUsers[name].LobbyID); if (ret != null) { if (!string.IsNullOrEmpty(ret.PrivateMessage)) { tas.Say(TasClient.SayPlace.User, name, ret.PrivateMessage, false); } if (!string.IsNullOrEmpty(ret.PublicMessage)) { tas.Say(TasClient.SayPlace.Battle, "", ret.PublicMessage, true); } if (ret.ForceSpec) { tas.ForceSpectator(name); } if (ret.Kick) { tas.Kick(name); } } } catch (Exception ex) { SayBattle("ServerManage error: " + ex, false); } } if (SpawnConfig != null && SpawnConfig.Owner == name) // owner joins, set him boss { ComBoss(TasSayEventArgs.Default, new[] { name }); } }