/// <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; }
public string ConnectGame(string ip, int port, string myName, string myPassword = null) { battleResult = new BattleResult(); lobbyUserName = myName; lobbyPassword = myPassword; isHosting = false; var script= ScriptGenerator.GenerateConnectScript(ip, port, myName, myPassword); StartSpring(script); return script; }
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; }
public static string SubmitSpringBattleResult(BattleContext context, string password, BattleResult result, List<BattlePlayerResult> players, List<string> extraData) { try { Account acc = AuthServiceClient.VerifyAccountPlain(context.AutohostName, password); if (acc == null) throw new Exception("Account name or password not valid"); AutohostMode mode = context.GetMode(); var db = new ZkDataContext(); if (extraData == null) extraData = new List<string>(); var sb = new SpringBattle { HostAccountID = acc.AccountID, Duration = result.Duration, EngineGameID = result.EngineBattleID, MapResourceID = db.Resources.Single(x => x.InternalName == result.Map).ResourceID, ModResourceID = db.Resources.Single(x => x.InternalName == result.Mod).ResourceID, HasBots = result.IsBots, IsMission = result.IsMission, PlayerCount = players.Count(x => !x.IsSpectator), StartTime = result.StartTime, Title = result.Title, ReplayFileName = result.ReplayName, EngineVersion = result.EngineVersion, }; db.SpringBattles.InsertOnSubmit(sb); foreach (BattlePlayerResult p in players) { sb.SpringBattlePlayers.Add(new SpringBattlePlayer { AccountID = db.Accounts.First(x => x.AccountID == p.LobbyID).AccountID, AllyNumber = p.AllyNumber, CommanderType = p.CommanderType, IsInVictoryTeam = p.IsVictoryTeam, IsSpectator = p.IsSpectator, LoseTime = p.LoseTime }); } db.SubmitChanges(); // awards foreach (string line in extraData.Where(x => x.StartsWith("award"))) { string[] partsSpace = line.Substring(6).Split(new[] { ' ' }, 3); string name = partsSpace[0]; string awardType = partsSpace[1]; string awardText = partsSpace[2]; SpringBattlePlayer player = sb.SpringBattlePlayers.FirstOrDefault(x => x.Account.Name == name); if (player != null) { db.AccountBattleAwards.InsertOnSubmit(new AccountBattleAward { AccountID = player.AccountID, SpringBattleID = sb.SpringBattleID, AwardKey = awardType, AwardDescription = awardText }); } } var text = new StringBuilder(); bool isPlanetwars = false; if (mode == AutohostMode.Planetwars && sb.SpringBattlePlayers.Count(x => !x.IsSpectator) >= 2 && sb.Duration >= GlobalConst.MinDurationForPlanetwars) { // test that factions are not intermingled (each faction only has one ally number) - if they are it wasnt actually PW balanced if ( sb.SpringBattlePlayers.Where(x => !x.IsSpectator && x.Account.Faction != null) .GroupBy(x => x.Account.Faction) .All(grp => grp.Select(x => x.AllyNumber).Distinct().Count() < 2)) { isPlanetwars = true; List<int> winnerTeams = sb.SpringBattlePlayers.Where(x => x.IsInVictoryTeam && !x.IsSpectator).Select(x => x.AllyNumber).Distinct().ToList(); int? winNum = null; if (winnerTeams.Count == 1) { winNum = winnerTeams[0]; if (winNum > 1) { winNum = null; text.AppendLine("ERROR: Invalid winner"); } } PlanetWarsTurnHandler.EndTurn(result.Map, extraData, db, winNum, sb.SpringBattlePlayers.Where(x => !x.IsSpectator).Select(x => x.Account).ToList(), text, sb, sb.SpringBattlePlayers.Where(x => !x.IsSpectator && x.AllyNumber == 0).Select(x => x.Account).ToList()); Global.PlanetWarsMatchMaker.RemoveFromRunningBattles(context.AutohostName); } else { text.AppendLine("Battle wasn't PlanetWars balanced, it counts as a normal team game only"); } } bool noElo = (extraData.FirstOrDefault(x => x.StartsWith("noElo", true, System.Globalization.CultureInfo.CurrentCulture)) != null); try { db.SubmitChanges(); } catch (System.Data.Linq.DuplicateKeyException ex) { Trace.TraceError(ex.ToString()); } Dictionary<int, int> orgLevels = sb.SpringBattlePlayers.Select(x => x.Account).ToDictionary(x => x.AccountID, x => x.Level); sb.CalculateAllElo(noElo, isPlanetwars); foreach (var u in sb.SpringBattlePlayers.Where(x => !x.IsSpectator)) u.Account.CheckLevelUp(); db.SubmitAndMergeChanges(); try { foreach (Account a in sb.SpringBattlePlayers.Where(x => !x.IsSpectator).Select(x => x.Account)) Global.Server.PublishAccountUpdate(a); } catch (Exception ex) { Trace.TraceError("error updating extension data: {0}", ex); } foreach (Account account in sb.SpringBattlePlayers.Select(x => x.Account)) { if (account.Level > orgLevels[account.AccountID]) { try { string message = string.Format("Congratulations {0}! You just leveled up to level {1}. {3}/Users/Detail/{2}", account.Name, account.Level, account.AccountID, GlobalConst.BaseSiteUrl); //text.AppendLine(message); Global.Server.GhostPm(account.Name, message); } catch (Exception ex) { Trace.TraceError("Error sending level up lobby message: {0}", ex); } } } text.AppendLine(string.Format("BATTLE DETAILS AND REPLAY ----> {1}/Battles/Detail/{0} <-----", sb.SpringBattleID, GlobalConst.BaseSiteUrl)); /* // create debriefing room, join players there and output message string channelName = "B" + sb.SpringBattleID; var joinplayers = new List<string>(); joinplayers.AddRange(context.Players.Select(x => x.Name)); // add those who were there at start joinplayers.AddRange(sb.SpringBattlePlayers.Select(x => x.Account.Name)); // add those who played Battle bat = Global.Server.Battles.Values.FirstOrDefault(x => x.Founder.Name == context.AutohostName); // add those in lobby atm var conf = context.GetConfig(); if (bat != null && (conf == null || conf.MinToJuggle == null)) // if not qm room do not join those who are in battle { List<string> inbatPlayers = bat.Users.Keys.ToList(); joinplayers.RemoveAll(x => inbatPlayers.Contains(x)); } foreach (string jp in joinplayers.Distinct().Where(x => x != context.AutohostName)) tas.ForceJoinChannel(jp, channelName); tas.JoinChannel(channelName); // join nightwatch and say it tas.Say(SayPlace.Channel, channelName, text.ToString(), true); tas.LeaveChannel(channelName);*/ //text.Append(string.Format("Debriefing in #{0} - zk://chat/channel/{0} ", channelName)); return text.ToString(); } catch (Exception ex) { Trace.TraceError(ex.ToString()); return ex.ToString(); } }