/// <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); }
public static void ScriptAddUser(StringBuilder script, int userNum, List <UserBattleStatus> playersExport, SpringBattleStartSetup startSetup, int teamNum, UserBattleStatus status) { var export = status.Clone(); export.TeamNumber = teamNum; playersExport.Add(status); // PLAYERS script.AppendFormat(" [PLAYER{0}]\n", userNum); script.AppendLine(" {"); script.AppendFormat(" Name={0};\n", status.Name); script.AppendFormat(" Spectator={0};\n", status.IsSpectator ? 1 : 0); if (!status.IsSpectator) { script.AppendFormat(" Team={0};\n", teamNum); } if (status.LobbyUser != null) { script.AppendFormat(" Rank={0};\n", status.LobbyUser.Rank); script.AppendFormat(" CountryCode={0};\n", status.LobbyUser.Country); script.AppendFormat(" LobbyID={0};\n", status.LobbyUser.LobbyID); script.AppendFormat(" LobbyRank={0};\n", status.LobbyUser.Rank); } if (status.ScriptPassword != null) { script.AppendFormat(" Password={0};\n", status.ScriptPassword); } if (startSetup != null) { var entry = startSetup.UserParameters.FirstOrDefault(x => x.LobbyID == status.LobbyUser.LobbyID); if (entry != null) { foreach (var kvp in entry.Parameters) { script.AppendFormat(" {0}={1};\n", kvp.Key, kvp.Value); } } } script.AppendLine(" }"); }
void GeneratePlayerSection(List <UserBattleStatus> playersExport, User localUser, SpringBattleStartSetup startSetup, List <UserBattleStatus> users, StringBuilder script, List <StartPos> positions, List <BotBattleStatus> bots) { if (mod != null && mod.IsMission) // mission stuff { var aiNum = 0; var declaredTeams = new HashSet <int>(); var orderedUsers = users.OrderBy(x => x.TeamNumber).ToList(); for (var i = 0; i < orderedUsers.Count; i++) { var u = orderedUsers[i]; ScriptAddUser(script, i, playersExport, startSetup, u.TeamNumber, u); if (!u.IsSpectator && !declaredTeams.Contains(u.TeamNumber)) { ScriptAddTeam(script, u.TeamNumber, positions, i, u, mod, Details); declaredTeams.Add(u.TeamNumber); } } for (var i = 0; i < orderedUsers.Count; i++) { var u = orderedUsers[i]; foreach (var b in bots.Where(x => x.owner == u.Name)) { ScriptAddBot(script, aiNum++, b.TeamNumber, i, b); if (!declaredTeams.Contains(b.TeamNumber)) { ScriptAddTeam(script, b.TeamNumber, positions, i, b, mod, Details); declaredTeams.Add(b.TeamNumber); } } } } else { // ordinary battle stuff var userNum = 0; var teamNum = 0; var aiNum = 0; //players is excluding self (so "springie doesn't appear as spec ingame") & excluding bots (bots is added later for each owner) foreach (var u in users.Where(u => !bots.Any(b => b.Name == u.Name)).OrderBy(x => x.TeamNumber).Where(x => x.Name != localUser.Name)) { ScriptAddUser(script, userNum, playersExport, startSetup, teamNum, u); if (!u.IsSpectator) { ScriptAddTeam(script, teamNum, positions, userNum, u, mod, Details); teamNum++; } foreach (var b in bots.Where(x => x.owner == u.Name)) { ScriptAddBot(script, aiNum, teamNum, userNum, b); aiNum++; ScriptAddTeam(script, teamNum, positions, userNum, b, mod, Details); teamNum++; } userNum++; } } // ALLIANCES script.AppendLine(); foreach (var allyNumber in users.Where(x => !x.IsSpectator).Select(x => x.AllyNumber).Union(bots.Select(x => x.AllyNumber)).Union(Rectangles.Keys).Distinct()) { // get allies from each player, bot and rectangles (for koth) script.AppendFormat("[ALLYTEAM{0}]\n", allyNumber); script.AppendLine("{"); script.AppendFormat(" NumAllies={0};\n", 0); double left = 0, top = 0, right = 1, bottom = 1; BattleRect rect; if (Rectangles.TryGetValue(allyNumber, out rect)) { rect.ToFractions(out left, out top, out right, out bottom); } script.AppendFormat(CultureInfo.InvariantCulture, " StartRectLeft={0};\n", left); script.AppendFormat(CultureInfo.InvariantCulture, " StartRectTop={0};\n", top); script.AppendFormat(CultureInfo.InvariantCulture, " StartRectRight={0};\n", right); script.AppendFormat(CultureInfo.InvariantCulture, " StartRectBottom={0};\n", bottom); script.AppendLine("}"); } script.AppendLine(); script.AppendFormat(" NumRestrictions={0};\n", DisabledUnits.Count); script.AppendLine(); if (!mod.IsMission) { script.AppendLine(" [RESTRICT]"); script.AppendLine(" {"); for (var i = 0; i < DisabledUnits.Count; ++i) { script.AppendFormat(" Unit{0}={1};\n", i, DisabledUnits[i]); script.AppendFormat(" Limit{0}=0;\n", i); } script.AppendLine(" }"); script.AppendLine(" [MODOPTIONS]"); script.AppendLine(" {"); var options = new Dictionary <string, string>(); // put standard modoptions to options dictionary foreach (var o in mod.Options.Where(x => x.Type != OptionType.Section)) { var v = o.Default; if (ModOptions.ContainsKey(o.Key)) { v = ModOptions[o.Key]; } options[o.Key] = v; } // replace/add custom modoptions from startsetup (if they exist) if (startSetup != null && startSetup.ModOptions != null) { foreach (var entry in startSetup.ModOptions) { options[entry.Key] = entry.Value; } } // write final options to script foreach (var kvp in options) { script.AppendFormat(" {0}={1};\n", kvp.Key, kvp.Value); } script.AppendLine(" }"); } script.AppendLine("}"); }
/// <summary> /// Generates script /// </summary> /// <param name="playersExport">list of players</param> /// <param name="localUser">myself</param> /// <param name="loopbackListenPort">listen port for autohost interface</param> /// <param name="zkSearchTag">hackish search tag</param> /// <param name="startSetup">structure with custom extra data</param> /// <returns></returns> public string GenerateScript(out List <UserBattleStatus> playersExport, User localUser, int loopbackListenPort, string zkSearchTag, SpringBattleStartSetup startSetup) { var previousCulture = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; playersExport = new List <UserBattleStatus>(); var isHost = localUser.Name == Founder.Name; var myUbs = Users.SingleOrDefault(x => x.Name == localUser.Name); if (!isHost) { var sb = new StringBuilder(); sb.AppendLine("[GAME]"); sb.AppendLine("{"); sb.AppendFormat("HostIP={0};\n", Ip); sb.AppendFormat("HostPort={0};\n", HostPort); sb.AppendLine("IsHost=0;"); sb.AppendFormat("MyPlayerName={0};\n", localUser.Name); if (myUbs != null) { if (myUbs.ScriptPassword != null) { sb.AppendFormat("MyPasswd={0};\n", myUbs.ScriptPassword); } } else { sb.AppendFormat("MyPasswd={0};\n", localUser.Name); // used for mid-game join .. if no userbattlestatus, use own name } sb.AppendLine("}"); return(sb.ToString()); } else { if (mod == null) { throw new ApplicationException("Mod not downloaded yet"); } var script = new StringBuilder(); script.AppendLine("[GAME]"); script.AppendLine("{"); script.AppendFormat(" ZkSearchTag={0};\n", zkSearchTag); script.AppendFormat(" Mapname={0};\n", MapName); if (mod.IsMission) { script.AppendFormat(" StartPosType=3;\n"); } else { if (Details.StartPos == BattleStartPos.Choose) { script.AppendFormat(" StartPosType=2;\n"); } else { script.AppendFormat(" StartPosType=3;\n"); // workaround for random/fixed } // script.AppendFormat(" StartPosType={0};\n", (int)Details.StartPos); } script.AppendFormat(" GameType={0};\n", ModName); if (ModHash.HasValue) { script.AppendFormat(" ModHash={0};\n", ModHash.Value != 0 ? (uint)ModHash.Value : 1); } // hack dont set to 1 when dedi srever is patched if (MapHash.HasValue) { script.AppendFormat(" MapHash={0};\n", MapHash.Value != 0 ? (uint)MapHash.Value : 1); } script.AppendFormat(" AutohostPort={0};\n", loopbackListenPort); script.AppendLine(); script.AppendFormat(" HostIP={0};\n", Ip); script.AppendFormat(" HostPort={0};\n", HostPort); script.AppendFormat(" SourcePort={0};\n", 8300); script.AppendFormat(" IsHost=1;\n"); script.AppendLine(); //script.AppendFormat(" MyPlayerName={0};\n", localUser.Name); var positions = map.Positions != null?map.Positions.ToList() : new List <StartPos>(); if (Details.StartPos == BattleStartPos.Random) { positions = positions.Shuffle(); } List <UserBattleStatus> users; List <BotBattleStatus> bots; if (startSetup != null && startSetup.BalanceTeamsResult != null && startSetup.BalanceTeamsResult.Players != null) { // if there is a balance results as a part of start setup, use values from this (override lobby state) users = new List <UserBattleStatus>(this.Users.Select(x => x.Clone())); bots = new List <BotBattleStatus>(this.Bots.Select(x => (BotBattleStatus)x.Clone())); foreach (var p in startSetup.BalanceTeamsResult.Players) { var us = users.FirstOrDefault(x => x.Name == p.Name); if (us == null) { us = new UserBattleStatus(p.Name, new User() { LobbyID = p.LobbyID }, Password); users.Add(us); } us.TeamNumber = p.TeamID; us.IsSpectator = p.IsSpectator; us.AllyNumber = p.AllyID; } foreach (var p in startSetup.BalanceTeamsResult.Bots) { var bot = bots.FirstOrDefault(x => x.Name == p.BotName); if (bot == null) { bot = new BotBattleStatus(p.BotName, p.Owner, p.BotAI); bots.Add(bot); } bot.AllyNumber = bot.AllyNumber; bot.TeamNumber = bot.TeamNumber; } foreach (var u in users.Where(x => !startSetup.BalanceTeamsResult.Players.Any(y => y.Name == x.Name))) { u.IsSpectator = true; } // spec those not known at the time of balance } else { users = this.Users; bots = this.Bots; } GeneratePlayerSection(playersExport, localUser, startSetup, users, script, positions, bots); return(script.ToString()); } } finally { Thread.CurrentThread.CurrentCulture = previousCulture; } }
public static void GeneratePlayerSection(List <UserBattleStatus> playersExport, List <UserBattleStatus> users, StringBuilder script, List <BotBattleStatus> bots, IDictionary <int, BattleRect> _rectangles, Dictionary <string, string> _modOptions, User localUser = null, SpringBattleStartSetup startSetup = null ) { // ordinary battle stuff var userNum = 0; var teamNum = 0; var aiNum = 0; //players is excluding self (so "springie doesn't appear as spec ingame") & excluding bots (bots is added later for each owner) var non_botUsers = users.Where(u => !bots.Any(b => b.Name == u.Name)); //.OrderBy(x => x.TeamNumber); if (localUser != null) //I am a server { non_botUsers = non_botUsers.Where(x => x.Name != localUser.Name); } foreach (var u in non_botUsers.OrderBy(x => x.TeamNumber)) { ScriptAddUser(script, userNum, playersExport, startSetup, teamNum, u); if (!u.IsSpectator) { ScriptAddTeam(script, teamNum, userNum, u); teamNum++; } foreach (var b in bots.Where(x => x.owner == u.Name)) { ScriptAddBot(script, aiNum, teamNum, userNum, b); aiNum++; ScriptAddTeam(script, teamNum, userNum, b); teamNum++; } userNum++; } // ALLIANCES script.AppendLine(); foreach (var allyNumber in users.Where(x => !x.IsSpectator).Select(x => x.AllyNumber).Union(bots.Select(x => x.AllyNumber)).Union(_rectangles.Keys).Distinct()) { // get allies from each player, bot and rectangles (for koth) script.AppendFormat("[ALLYTEAM{0}]\n", allyNumber); script.AppendLine("{"); script.AppendFormat(" NumAllies={0};\n", 0); double left = 0, top = 0, right = 1, bottom = 1; BattleRect rect; if (_rectangles.TryGetValue(allyNumber, out rect)) { rect.ToFractions(out left, out top, out right, out bottom); } script.AppendFormat(CultureInfo.InvariantCulture, " StartRectLeft={0};\n", left); script.AppendFormat(CultureInfo.InvariantCulture, " StartRectTop={0};\n", top); script.AppendFormat(CultureInfo.InvariantCulture, " StartRectRight={0};\n", right); script.AppendFormat(CultureInfo.InvariantCulture, " StartRectBottom={0};\n", bottom); script.AppendLine("}"); } script.AppendLine(); script.AppendLine(" [MODOPTIONS]"); script.AppendLine(" {"); var options = new Dictionary <string, string>(_modOptions); // replace/add custom modoptions from startsetup (if they exist) if (startSetup != null && startSetup.ModOptions != null) { foreach (var entry in startSetup.ModOptions) { options[entry.Key] = entry.Value; } } // write final options to script foreach (var kvp in options) { script.AppendFormat(" {0}={1};\n", kvp.Key, kvp.Value); } script.AppendLine(" }"); script.AppendLine("}"); }
/// <summary> /// Generates script /// </summary> /// <param name="playersExport">list of players</param> /// <param name="localUser">myself</param> /// <param name="loopbackListenPort">listen port for autohost interface</param> /// <param name="zkSearchTag">hackish search tag</param> /// <param name="startSetup">structure with custom extra data</param> /// <returns></returns> public string GenerateScript(out List <UserBattleStatus> playersExport, User localUser, int loopbackListenPort, string zkSearchTag, SpringBattleStartSetup startSetup) { var previousCulture = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; playersExport = new List <UserBattleStatus>(); var isHost = localUser.Name == Founder.Name; var myUbs = Users[localUser.Name]; if (!isHost) { var sb = new StringBuilder(); sb.AppendLine("[GAME]"); sb.AppendLine("{"); sb.AppendFormat("HostIP={0};\n", Ip); sb.AppendFormat("HostPort={0};\n", HostPort); sb.AppendLine("IsHost=0;"); sb.AppendFormat("MyPlayerName={0};\n", localUser.Name); if (myUbs != null) { if (myUbs.ScriptPassword != null) { sb.AppendFormat("MyPasswd={0};\n", myUbs.ScriptPassword); } } else { sb.AppendFormat("MyPasswd={0};\n", localUser.Name); // used for mid-game join .. if no userbattlestatus, use own name } sb.AppendLine("}"); return(sb.ToString()); } else { var script = new StringBuilder(); script.AppendLine("[GAME]"); script.AppendLine("{"); script.AppendFormat(" ZkSearchTag={0};\n", zkSearchTag); script.AppendFormat(" Mapname={0};\n", MapName); script.AppendFormat(" StartPosType=2;\n"); script.AppendFormat(" GameType={0};\n", ModName); script.AppendFormat(" ModHash=1;\n"); script.AppendFormat(" MapHash=1;\n"); script.AppendFormat(" AutohostPort={0};\n", loopbackListenPort); script.AppendLine(); script.AppendFormat(" HostIP={0};\n", Ip); script.AppendFormat(" HostPort={0};\n", HostPort); script.AppendFormat(" SourcePort={0};\n", 8300); script.AppendFormat(" IsHost=1;\n"); script.AppendLine(); //script.AppendFormat(" MyPlayerName={0};\n", localUser.Name); List <UserBattleStatus> users; List <BotBattleStatus> bots; if (startSetup != null && startSetup.BalanceTeamsResult != null && startSetup.BalanceTeamsResult.Players != null) { // if there is a balance results as a part of start setup, use values from this (override lobby state) users = Users.Values.ToList(); bots = new List <BotBattleStatus>(this.Bots.Values.Select(x => (BotBattleStatus)x.Clone())); foreach (var p in startSetup.BalanceTeamsResult.Players) { var us = users.FirstOrDefault(x => x.Name == p.Name); if (us == null) { us = new UserBattleStatus(p.Name, new User() { AccountID = p.LobbyID }, Password); // TODO this "password" use does not look right users.Add(us); } us.TeamNumber = p.TeamID; us.IsSpectator = p.IsSpectator; us.AllyNumber = p.AllyID; } foreach (var p in startSetup.BalanceTeamsResult.Bots) { var bot = bots.FirstOrDefault(x => x.Name == p.BotName); if (bot == null) { bot = new BotBattleStatus(p.BotName, p.Owner, p.BotAI); bots.Add(bot); } bot.AllyNumber = bot.AllyNumber; bot.TeamNumber = bot.TeamNumber; } foreach (var u in users.Where(x => !startSetup.BalanceTeamsResult.Players.Any(y => y.Name == x.Name))) { u.IsSpectator = true; } // spec those not known at the time of balance } else { users = this.Users.Values.ToList(); bots = this.Bots.Values.ToList(); } GeneratePlayerSection(playersExport, users, script, bots, Rectangles, ModOptions, localUser, startSetup); return(script.ToString()); } } finally { Thread.CurrentThread.CurrentCulture = previousCulture; } }