コード例 #1
0
        protected override bool PerformInit(TasSayEventArgs e, string[] words, out string question, out int winCount) {
            winCount = 0;
            question = null;
            if (spring.IsRunning)
            {
                question = "Exit this game?";
                int cnt = 0;
                context = spring.StartContext;
                foreach (var p in context.Players.Where(x => !x.IsSpectator))
                {
                    if (p.IsIngame || tas.MyBattle.Users.ContainsKey(p.Name))
                    {
                        //Note: "ExistingUsers" is empty if users disconnected from lobby but still ingame.

                        bool afk = tas.ExistingUsers.ContainsKey(p.Name) && tas.ExistingUsers[p.Name].IsAway;
                        if (!afk) cnt++;
                    }
                }
                winCount = cnt / 2 + 1;
                return true;
            }
            else
            {
                AutoHost.Respond(tas, spring, e, "game not running");
                return false;
            }
        }
コード例 #2
0
        protected override bool PerformInit(TasSayEventArgs e, string[] words, out string question, out int winCount) {
            if (spring.IsRunning)
            {
                context = spring.StartContext;
                voteStarter = context.Players.FirstOrDefault(x => x.Name == e.UserName && !x.IsSpectator);
                if (voteStarter != null)
                {
                    question = string.Format("Resign team {0}?", voteStarter.AllyID + 1);
                    int cnt = 0, total = 0;
                    foreach (var p in context.Players.Where(x => x.AllyID == voteStarter.AllyID && !x.IsSpectator))
                    {
                        total++;
                        if (p.IsIngame || tas.MyBattle.Users.ContainsKey(p.Name))
                        {
                            //Note: "ExistingUsers" is empty if users disconnected from lobby but still ingame.

                            bool afk = tas.ExistingUsers.ContainsKey(p.Name) && tas.ExistingUsers[p.Name].IsAway;
                            if (!afk) cnt++;
                        }
                    }
                    winCount = (cnt * 3 / 5) + 1;
                    if (total > 1 && winCount == 1) winCount = 2; // prevents most pathological cases (like a falsely AFK partner in 2v2)
                    return true;
                }
            }
            AutoHost.Respond(tas, spring, e, "You cannot resign now");
            question = null;
            winCount = 0;
            return false;
        }
コード例 #3
0
        /// <summary>
        /// Generates script for hosting a game
        /// </summary>
        public static string GenerateHostScript(BattleContext startContext, SpringBattleStartSetup startSetup, int loopbackListenPort,
                                                string zkSearchTag, string host, int port, string myname = null, string mypassword = null)
        {
            var previousCulture = Thread.CurrentThread.CurrentCulture;
            try {
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                var script = new StringBuilder();

                script.AppendLine("[GAME]");
                script.AppendLine("{");

                script.AppendFormat("  ZkSearchTag={0};\n", zkSearchTag);
                script.AppendFormat("  Mapname={0};\n", startContext.Map);

                script.AppendFormat("  StartPosType={0};\n", startContext.IsMission ? 3 : 2);

                script.AppendFormat("  GameType={0};\n", startContext.Mod);
                script.AppendFormat("  ModHash=1;\n");
                script.AppendFormat("  MapHash=1;\n");

                script.AppendFormat("  AutohostPort={0};\n", loopbackListenPort);
                script.AppendLine();
                script.AppendFormat("  HostIP={0};\n", host);
                script.AppendFormat("  HostPort={0};\n", port);
                //script.AppendFormat("  SourcePort={0};\n", 8300);
                script.AppendFormat("  IsHost=1;\n");
                script.AppendLine();

                if (!string.IsNullOrEmpty(myname)) script.AppendFormat("  MyPlayerName={0};\n", myname);
                if (!string.IsNullOrEmpty(mypassword) || !string.IsNullOrEmpty(myname)) script.AppendFormat("  MyPasswd={0};\n", mypassword??myname);

                GeneratePlayerSection(script, startContext, startSetup);

                return script.ToString();
            } finally {
                Thread.CurrentThread.CurrentCulture = previousCulture;
            }
        }
コード例 #4
0
        public static PlayerJoinResult AutohostPlayerJoined(BattleContext context, int accountID) {
            var res = new PlayerJoinResult();
            var db = new ZkDataContext();
            AutohostMode mode = context.GetMode();

            if (mode == AutohostMode.Planetwars) {
                Planet planet = db.Galaxies.Single(x => x.IsDefault).Planets.SingleOrDefault(x => x.Resource.InternalName == context.Map);
                if (planet == null) {
                    res.PublicMessage = "Invalid map";
                    return res;
                }
                Account account = db.Accounts.Find(accountID); // accountID is in fact lobbyID

                if (account != null) {
                    var config = context.GetConfig();
                    if (account.Level < config.MinLevel)
                    {
                        res.PrivateMessage = string.Format("Sorry, PlanetWars is competive online campaign for experienced players. You need to be at least level {0} to play here. To increase your level, play more games on other hosts or open multiplayer game and play against computer AI bots.  You can still spectate this game, however.", config.MinLevel);
                        res.ForceSpec = true;
                        return res;
                    }


                    string owner = "";
                    if (planet.Account != null) owner = planet.Account.Name;
                    string facRoles = string.Join(",",
                                                  account.AccountRolesByAccountID.Where(x => !x.RoleType.IsClanOnly).Select(x => x.RoleType.Name).ToList());
                    if (!string.IsNullOrEmpty(facRoles)) facRoles += " of " + account.Faction.Name + ", ";

                    string clanRoles = string.Join(",",
                                                   account.AccountRolesByAccountID.Where(x => x.RoleType.IsClanOnly).Select(x => x.RoleType.Name).ToList());
                    if (!string.IsNullOrEmpty(clanRoles)) clanRoles += " of " + account.Clan.ClanName;

                    res.PublicMessage = string.Format("Greetings {0} {1}{2}, welcome to {3} planet {4} {6}/PlanetWars/Planet/{5}",
                                                      account.Name,
                                                      facRoles,
                                                      clanRoles,
                                                      owner,
                                                      planet.Name,
                                                      planet.PlanetID,
                                                      GlobalConst.BaseSiteUrl);

                    return res;
                }
            }
            Account acc = db.Accounts.Find(accountID); // accountID is in fact lobbyID

            if (acc != null)
            {
                AutohostConfig config = context.GetConfig();
                if (acc.Level < config.MinLevel)
                {
                    res.PrivateMessage = string.Format("Sorry, you need to be at least level {0} to play here. To increase your level, play more games on other hosts or open multiplayer game and play against computer AI bots. You can still spectate this game, however.",
                                                           config.MinLevel);
                    res.ForceSpec = true;
                    return res;
                }
                else if (acc.Level > config.MaxLevel)
                {
                    res.PrivateMessage = string.Format("Sorry, your level must be {0} or lower to play here. Pick on someone your own size! You can still spectate this game, however.",
                                                           config.MaxLevel);
                    res.ForceSpec = true;
                    return res;
                }

                // FIXME: use 1v1 Elo for 1v1
                if (acc.EffectiveElo < config.MinElo)
                {
                    res.PrivateMessage = string.Format("Sorry, you need to have an Elo rating of at least {0} to play here. Win games against human opponents to raise your Elo. You can still spectate this game, however.",
                                                           config.MinElo);
                    res.ForceSpec = true;
                    return res;
                }
                else if (acc.EffectiveElo > config.MaxElo)
                {
                    res.PrivateMessage = string.Format("Sorry, your Elo rating must be {0} or lower to play here. Pick on someone your own size! You can still spectate this game, however.",
                                                           config.MaxElo);
                    res.ForceSpec = true;
                    return res;
                }
            }

            return null;
        }
コード例 #5
0
        static void VerifySpecCheaters(BattleContext context, BalanceTeamsResult res) {
            try {
                // find specs with same IP as some player and kick them
                using (var db = new ZkDataContext()) {
                    var ids = context.Players.Select(y => (int?)y.LobbyID).ToList();
                    var ipByLobbyID = db.Accounts.Where(x => ids.Contains(x.AccountID))
                                        .ToDictionary(x => x.AccountID, x => x.AccountIPs.OrderByDescending(y => y.LastLogin).Select(y=>y.IP).FirstOrDefault());
                    // lobbyid -> ip mapping

                    var mode = context.GetMode();
                    // kick same ip specs for starred and non chickens
                    /*
                    if (mode != AutohostMode.None && mode != AutohostMode.GameChickens) {
						foreach (var p in context.Players.Where(x => x.IsSpectator)) {
							var ip = ipByLobbyID[p.LobbyID];
							if (context.Players.Any(x => !x.IsSpectator && ipByLobbyID[x.LobbyID] == ip)) Global.Nightwatch.Tas.AdminKickFromLobby(p.Name, "Spectators from same location as players are not allowed here!");
						}
					}*/

                    foreach (var grp in context.Players.GroupBy(x => ipByLobbyID[x.LobbyID]).Where(x => x.Count() > 1)) res.Message += string.Format("\nThese people are in same location: {0}", string.Join(", ", grp.Select(x => x.Name)));
                }
            } catch (Exception ex) {
                Trace.TraceError("Error checking speccheaters: {0}", ex);
            }
        }
コード例 #6
0
 static void AddPwPlayer(BattleContext context, string matchUser, BalanceTeamsResult res, int allyID)
 {
     PlayerTeam player = context.Players.FirstOrDefault(x => x.Name == matchUser);
     if (player == null)
     {
         player = new PlayerTeam() { Name = matchUser };
         User us;
         if (Global.Nightwatch.Tas.GetExistingUser(matchUser, out us)) player.LobbyID = us.AccountID;
         else
         {
             var db = new ZkDataContext();
             var acc = Account.AccountByName(db, matchUser);
             if (acc != null) player.LobbyID = acc.AccountID;
         }
     }
     res.Players.Add(new PlayerTeam { AllyID = allyID , IsSpectator = false, Name = player.Name, LobbyID = player.LobbyID, TeamID = player.TeamID });
 }
コード例 #7
0
        BalanceTeamsResult PlanetwarsBalance(BattleContext context) {
            var res = new BalanceTeamsResult();
            res.CanStart = true;
            res.DeleteBots = true;

            using (var db = new ZkDataContext()) {
                res.Message = "";
                var planet = db.Galaxies.Single(x => x.IsDefault).Planets.First(x => x.Resource.InternalName == context.Map);

                var info = Global.PlanetWarsMatchMaker.GetBattleInfo(context.AutohostName);
                if (info == null)
                {
                    res.Message = "Start battle using matchmaker";
                    res.CanStart = false;
                    return res;
                } 

                foreach (string matchUser in info.Attackers)
                {
                    AddPwPlayer(context, matchUser, res, 0);
                }

                foreach (string matchUser in info.Defenders)
                {
                    AddPwPlayer(context, matchUser, res, 1);
                }

                foreach (var p in context.Players.Where(x => !res.Players.Any(y => y.Name == x.Name)))
                {
                    p.IsSpectator = true;
                    res.Players.Add(p);
                }

                var teamNum = 1;
                foreach (var p in res.Players)
                {
                    p.TeamID = teamNum++; // normalize teams
                }
                
                // bots game
                int cnt = 0;
                if (planet.PlanetStructures.Any(x => !string.IsNullOrEmpty(x.StructureType.EffectBots)))
                {
                    foreach (var b in planet.PlanetStructures.Select(x => x.StructureType).Where(x => !string.IsNullOrEmpty(x.EffectBots))) res.Bots.Add(new BotTeam { AllyID = 2, BotAI = b.EffectBots, BotName = "Aliens" + cnt++ });

                    res.Message += string.Format("This planet is infested by aliens, fight for your survival");
                    return res;
                }

                
                return res;
            }
        }
コード例 #8
0
        static BalanceTeamsResult PerformBalance(BattleContext context,
                                                 bool isGameStart,
                                                 int? allyCount,
                                                 bool? clanWise,
                                                 AutohostConfig config,
                                                 int playerCount) {
            var res = new BalanceTeamsResult();
            var mode = context.GetMode();

            using (var db = new ZkDataContext()) {
                if (!CheckPlayersMinimumConditions(context, db, config, ref res.Message)) {
                    res.CanStart = false;
                    return res;
                }

                switch (mode) {
                    case AutohostMode.None:
                    {
                        if (!isGameStart) res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context);
                    }
                        break;
                    case AutohostMode.Generic:
                    {
                        if (allyCount == null && res.Bots != null && res.Bots.Any())
                        {
                            res.Players = context.Players.ToList();
                            res.Bots = context.Bots.Where(x => x.Owner != context.AutohostName).ToList();
                            foreach (var p in res.Players) p.AllyID = 0;
                            foreach (var b in res.Bots) b.AllyID = 1;
                        }
                        else
                        {
                            var map = db.Resources.Single(x => x.InternalName == context.Map);
                            res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 2,
                                clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise,
                                context);
                            res.DeleteBots = mode == AutohostMode.Teams;
                        }
                        return res;
                    }
                    
                    case AutohostMode.Teams:
                    {
                        var map = db.Resources.Single(x => x.InternalName == context.Map);
                        res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context);
                        res.DeleteBots = mode == AutohostMode.Teams;
                        return res;
                    }
                    case AutohostMode.Game1v1:
                    {
                        res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context);
                        res.DeleteBots = true;
                    }
                        break;

                    case AutohostMode.GameChickens:
                    {
                        res.Players = context.Players.ToList();
                        res.Bots = context.Bots.Where(x => x.Owner != context.AutohostName).ToList();
                        foreach (var p in res.Players) p.AllyID = 0;
                        foreach (var b in res.Bots) b.AllyID = 1;

                        if (!res.Bots.Any() && res.Players.Count > 0) {
                            res.Message = "Add some bot (computer player) as your enemy. Use button on bottom left. Chicken or CAI is recommended.";
                            res.CanStart = false;
                            /*else
                                    {
                                        res.Bots.Add(new BotTeam() { AllyID = 1, TeamID = 16, BotName = "default_Chicken", BotAI = "Chicken: Normal", });
                                        res.Message = "Adding a normal chickens bot for you";
                                    }*/
                        }
                    }
                        break;
                    case AutohostMode.GameFFA:
                    {
                        var map = db.Resources.Single(x => x.InternalName == context.Map);
                        if (map.MapFFAMaxTeams != null)
                            res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams.Value,
                                                               clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise,
                                                               context);
                        else
                            res = new Balancer().LegacyBalance(allyCount ?? map.MapFFAMaxTeams ?? 8,
                                                               clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise,
                                                               context);
                        return res;
                    }
                    case AutohostMode.Planetwars:

                        return new Balancer().PlanetwarsBalance(context);
                }
                return res;
            }
        }
コード例 #9
0
        static void GeneratePlayerSection(StringBuilder script, BattleContext startContext, SpringBattleStartSetup setup)
        {
            // ordinary battle stuff

            var userNum = 0;
            var teamNum = 0;
            var aiNum = 0;

            foreach (var u in startContext.Players) {
                ScriptAddUser(script, userNum, u, teamNum, setup.UserParameters.FirstOrDefault(x => x.LobbyID == u.LobbyID));

                if (!u.IsSpectator) {
                    ScriptAddTeam(script, teamNum, userNum, u.AllyID);
                    teamNum++;
                }

                foreach (var b in startContext.Bots.Where(x => x.Owner == u.Name)) {
                    ScriptAddBot(script, aiNum, teamNum, userNum, b.BotAI, b.BotName);
                    aiNum++;
                    ScriptAddTeam(script, teamNum, userNum, b.AllyID);
                    teamNum++;
                }
                userNum++;
            }

            // ALLIANCES AND START BOXES
            var startboxes = new StringBuilder();
            startboxes.Append("return { ");
            script.AppendLine();
            for (var allyNumber = 0; allyNumber < Spring.MaxAllies; allyNumber++) {
                script.AppendFormat("[ALLYTEAM{0}]\n", allyNumber);
                script.AppendLine("{");
                script.AppendLine("     NumAllies=0;");
                BattleRect rect;
                if (startContext.Rectangles!=null && startContext.Rectangles.TryGetValue(allyNumber, out rect)) {
                    double left = 0, top = 0, right = 1, bottom = 1;
                    rect.ToFractions(out left, out top, out right, out bottom);
                    startboxes.AppendFormat(CultureInfo.InvariantCulture, "[{0}] = ", allyNumber);
                    startboxes.Append("{ ");
                    startboxes.AppendFormat(CultureInfo.InvariantCulture, "{0}, {1}, {2}, {3}", left, top, right, bottom);
                    startboxes.Append(" }, ");
                }
                script.AppendLine("}");
            }

            startboxes.Append("}");
            script.AppendLine();

            script.AppendLine("  [MODOPTIONS]");
            script.AppendLine("  {");

            script.AppendFormat("    startboxes={0};\n", startboxes.ToString());

            var options = new Dictionary<string, string>(startContext.ModOptions);

            // replace/add custom modoptions from startsetup (if they exist)
            if (setup != null && setup.ModOptions != null) foreach (var entry in setup.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("}");
        }
コード例 #10
0
 static bool CheckPlayersMinimumConditions(BattleContext battleContext,
                                           ZkDataContext dataContext,
                                           AutohostConfig config,
                                           ref string actionsDescription) {
     var ok = true;
     foreach (
         var p in
             battleContext.Players.Where(x => !x.IsSpectator)
                          .Select(x => new { player = x, account = dataContext.Accounts.First(y => y.AccountID == x.LobbyID) })) {
         if ((config.MinLevel != null && p.account.Level < config.MinLevel) || (config.MaxLevel != null && p.account.Level > config.MaxLevel) ||
             (config.MinElo != null && p.account.EffectiveElo < config.MinElo) ||
             (config.MaxElo != null && p.account.EffectiveElo > config.MaxElo)) {
             SpecPlayerOnCondition(p.player,
                                   p.account,
                                   string.Format(
                                       "Sorry, you cannot play here because of skill limits. You can spectate/observe this game however."));
             actionsDescription += string.Format("{0} cannot play here because of skill limits\n", p.account.Name);
             ok = false;
         }
     }
     return ok;
 }
コード例 #11
0
        public static void SplitAutohost(BattleContext context, bool forceStart = false) {
            var tas = Global.Nightwatch.Tas;
            try {
                //find first one that isnt running and is using same mode (by name)
                var splitTo =
                    tas.ExistingBattles.Values.FirstOrDefault(
                        x =>
                        !x.Founder.IsInGame && x.NonSpectatorCount == 0 && x.Founder.Name != context.AutohostName && !x.IsPassworded &&
                        x.Founder.Name.TrimNumbers() ==
                        context.AutohostName.TrimNumbers());

                if (splitTo != null) {
                    // set same map 
                    tas.Say(SayPlace.User, splitTo.Founder.Name, "!map " + context.Map, false);

                    var db = new ZkDataContext();
                    var ids = context.Players.Where(y => !y.IsSpectator).Select(x => (int?)x.LobbyID).ToList();
                    var users = db.Accounts.Where(x => ids.Contains(x.AccountID)).ToList();
                    var toMove = new List<Account>();

                    var moveCount = Math.Ceiling(users.Count/2.0);

                    /*if (users.Count%2 == 0 && users.Count%4 != 0) {
                        // in case of say 18 people, move 10 nubs out, keep 8 pros
                        moveCount = users.Count/2 + 1;
                    }*/

                    // split while keeping clan groups together
                    // note disabled splittinhg by clan - use "x.ClanID ?? x.LobbyID" for clan balance
                    foreach (var clanGrp in users.GroupBy(x => x.ClanID ?? x.AccountID).OrderBy(x => x.Average(y => y.EffectiveElo))) {
                        toMove.AddRange(clanGrp);
                        if (toMove.Count >= moveCount) break;
                    }

                    try {
                        foreach (var m in toMove) tas.ForceJoinBattle(m.Name, splitTo.BattleID);
                        Thread.Sleep(5000);
                        tas.Say(SayPlace.User, context.AutohostName, "!lock 180", false);
                        tas.Say(SayPlace.User, splitTo.Founder.Name, "!lock 180", false);
                        if (context.GetMode() == AutohostMode.Planetwars) {
                            tas.Say(SayPlace.User, context.AutohostName, "!map", false);
                            Thread.Sleep(500);
                            tas.Say(SayPlace.User, splitTo.Founder.Name, "!map", false);
                        }
                        else tas.Say(SayPlace.User, splitTo.Founder.Name, "!map " + context.Map, false);
                        if (forceStart) {
                            tas.Say(SayPlace.User, splitTo.Founder.Name, "!balance", false);
                            tas.Say(SayPlace.User, context.AutohostName, "!balance", false);
                            tas.Say(SayPlace.User, splitTo.Founder.Name, "!forcestart", false);
                            tas.Say(SayPlace.User, context.AutohostName, "!forcestart", false);
                        }

                        tas.Say(SayPlace.User, context.AutohostName, "!endvote", false);
                        tas.Say(SayPlace.User, splitTo.Founder.Name, "!endvote", false);

                        tas.Say(SayPlace.User, context.AutohostName, "!start", false);
                        tas.Say(SayPlace.User, splitTo.Founder.Name, "!start", false);
                    } catch (Exception ex) {
                        Trace.TraceError("Error when splitting: {0}", ex);
                    } 
                }
            } catch (Exception ex) {
                Trace.TraceError(ex.ToString());
            }
        }
コード例 #12
0
        static bool listOnlyThatLevelsModules = false;  // may cause bugs

        public static SpringBattleStartSetup GetSpringBattleStartSetup(BattleContext context) {
            try {
                AutohostMode mode = context.GetMode();
                var ret = new SpringBattleStartSetup();

                if (mode == AutohostMode.Planetwars)
                {
                    ret.BalanceTeamsResult = Balancer.BalanceTeams(context, true,null, null);
                    context.Players = ret.BalanceTeamsResult.Players;
                }
                
                var commanderTypes = new LuaTable();
                var db = new ZkDataContext();

                var accountIDsWithExtraComms = new List<int>();
                // calculate to whom to send extra comms
                if (mode == AutohostMode.Planetwars || mode == AutohostMode.Generic || mode == AutohostMode.GameFFA ||
                    mode == AutohostMode.Teams) {
                    IOrderedEnumerable<IGrouping<int, PlayerTeam>> groupedByTeam =
                        context.Players.Where(x => !x.IsSpectator).GroupBy(x => x.AllyID).OrderByDescending(x => x.Count());
                    IGrouping<int, PlayerTeam> biggest = groupedByTeam.FirstOrDefault();
                    if (biggest != null) {
                        foreach (var other in groupedByTeam.Skip(1)) {
                            int cnt = biggest.Count() - other.Count();
                            if (cnt > 0) {
                                foreach (Account a in
                                    other.Select(x => db.Accounts.First(y => y.AccountID == x.LobbyID)).OrderByDescending(x => x.Elo*x.EloWeight).Take(
                                        cnt)) accountIDsWithExtraComms.Add(a.AccountID);
                            }
                        }
                    }
                }

                bool is1v1 = context.Players.Where(x => !x.IsSpectator).ToList().Count == 2 && context.Bots.Count == 0;



                Faction attacker = null;
                Faction defender = null;
                Planet planet = null;
                if (mode == AutohostMode.Planetwars) {
                    planet = db.Galaxies.First(x => x.IsDefault).Planets.First(x => x.Resource.InternalName == context.Map);
                    attacker =
                        context.Players.Where(x => x.AllyID == 0 && !x.IsSpectator)
                            .Select(x => db.Accounts.First(y => y.AccountID == x.LobbyID))
                            .Where(x => x.Faction != null)
                            .Select(x => x.Faction)
                            .First();

                    defender = planet.Faction;

                    if (attacker == defender) defender = null;

                    ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "attackingFaction", Value = attacker.Shortcut });
                    if (defender != null) ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "defendingFaction", Value = defender.Shortcut });
                    ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "planet", Value = planet.Name });
                }


                
                foreach (PlayerTeam p in context.Players) {
                    Account user = db.Accounts.Find(p.LobbyID);
                    if (user != null) {
                        var userParams = new List<SpringBattleStartSetup.ScriptKeyValuePair>();
                        ret.UserParameters.Add(new SpringBattleStartSetup.UserCustomParameters { LobbyID = p.LobbyID, Parameters = userParams });

                        bool userBanMuted = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanMute);
                        if (userBanMuted) userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "muted", Value = "1" });
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair
                                       { Key = "faction", Value = user.Faction != null ? user.Faction.Shortcut : "" });
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair
                                       { Key = "clan", Value = user.Clan != null ? user.Clan.Shortcut : "" });
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "level", Value = user.Level.ToString() });
                        double elo =  mode == AutohostMode.Planetwars ? user.EffectivePwElo : (is1v1 ? user.Effective1v1Elo : user.EffectiveElo);
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "elo", Value = Math.Round(elo).ToString() }); // elo for ingame is just ordering for auto /take
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "avatar", Value = user.Avatar });
                        userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "admin", Value = (user.IsZeroKAdmin ? "1" : "0") });

                        if (!p.IsSpectator) {
                            if (mode == AutohostMode.Planetwars)
                            {
                                bool allied = user.Faction != null && defender != null && user.Faction != defender &&
                                              defender.HasTreatyRight(user.Faction, x => x.EffectPreventIngamePwStructureDestruction == true, planet);

                                if (!allied && user.Faction != null && (user.Faction == attacker || user.Faction == defender)) {
                                    userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "canAttackPwStructures", Value = "1" });
                                }
                            }

                            var pu = new LuaTable();
                            bool userUnlocksBanned = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanUnlocks);
                            bool userCommandersBanned = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanCommanders);

                            if (!userUnlocksBanned) {
                                if (mode != AutohostMode.Planetwars || user.Faction == null) foreach (Unlock unlock in user.AccountUnlocks.Select(x => x.Unlock)) pu.Add(unlock.Code);
                                else {
                                    foreach (Unlock unlock in
                                        user.AccountUnlocks.Select(x => x.Unlock).Union(user.Faction.GetFactionUnlocks().Select(x => x.Unlock)).Where(x => x.UnlockType == UnlockTypes.Unit)) pu.Add(unlock.Code);
                                }
                            }

                            userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "unlocks", Value = pu.ToBase64String() });

                            if (accountIDsWithExtraComms.Contains(user.AccountID)) userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "extracomm", Value = "1" });

                            var pc = new LuaTable();

                            if (!userCommandersBanned) {
                                foreach (Commander c in user.Commanders.Where(x => x.Unlock != null && x.ProfileNumber <= GlobalConst.CommanderProfileCount)) {
                                    try {
                                        if (string.IsNullOrEmpty(c.Name) || c.Name.Any(x => x == '"') )
                                        {
                                            c.Name = c.CommanderID.ToString();
                                        }
                                        LuaTable morphTable = new LuaTable();
                                        pc["[\"" + c.Name + "\"]"] = morphTable;

                                        // process decoration icons
                                        LuaTable decorations = new LuaTable();
                                        foreach (Unlock d in
                                                        c.CommanderDecorations.Where(x => x.Unlock != null).OrderBy(
                                                            x => x.SlotID).Select(x => x.Unlock))
                                        {
                                            CommanderDecorationIcon iconData = db.CommanderDecorationIcons.FirstOrDefault(x => x.DecorationUnlockID == d.UnlockID);
                                            if (iconData != null)
                                            {
                                                string iconName = null, iconPosition = null;
                                                // FIXME: handle avatars and preset/custom icons
                                                if (iconData.IconType == (int)DecorationIconTypes.Faction)
                                                {
                                                    iconName = user.Faction != null ? user.Faction.Shortcut : null;
                                                }
                                                else if (iconData.IconType == (int)DecorationIconTypes.Clan)
                                                {
                                                    iconName = user.Clan != null ? user.Clan.Shortcut : null;
                                                }

                                                if (iconName != null)
                                                {
                                                    iconPosition = CommanderDecoration.GetIconPosition(d);
                                                    LuaTable entry = new LuaTable();
                                                    entry.Add("image", iconName);
                                                    decorations.Add("icon_" + iconPosition.ToLower(), entry);
                                                }
                                            }
                                            else decorations.Add(d.Code);
                                        }
                                        

                                        string prevKey = null;
                                        for (int i = 0; i <= GlobalConst.NumCommanderLevels; i++) {
                                            string key = string.Format("c{0}_{1}_{2}", user.AccountID, c.ProfileNumber, i);
                                            morphTable.Add(key);    // TODO: maybe don't specify morph series in player data, only starting unit

                                            var comdef = new LuaTable();
                                            commanderTypes[key] = comdef;

                                            comdef["chassis"] = c.Unlock.Code + i;

                                            var modules = new LuaTable();
                                            comdef["modules"] = modules;
                                            
                                            comdef["decorations"] = decorations;

                                            comdef["name"] = c.Name.Substring(0, Math.Min(25, c.Name.Length)) + " level " + i;

                                            //if (i < GlobalConst.NumCommanderLevels)
                                            //{
                                            //    comdef["next"] = string.Format("c{0}_{1}_{2}", user.AccountID, c.ProfileNumber, i+1);
                                            //}
                                            //comdef["owner"] = user.Name;

                                            if (i > 0)
                                            {
                                                comdef["cost"] = c.GetTotalMorphLevelCost(i);

                                                if (listOnlyThatLevelsModules)
                                                {
                                                    if (prevKey != null) comdef["prev"] = prevKey;
                                                    prevKey = key;
                                                    foreach (Unlock m in
                                                        c.CommanderModules.Where(x => x.CommanderSlot.MorphLevel == i && x.Unlock != null).OrderBy(
                                                            x => x.Unlock.UnlockType).ThenBy(x => x.SlotID).Select(x => x.Unlock)) modules.Add(m.Code);
                                                }
                                                else
                                                {
                                                    foreach (Unlock m in
                                                        c.CommanderModules.Where(x => x.CommanderSlot.MorphLevel <= i && x.Unlock != null).OrderBy(
                                                            x => x.Unlock.UnlockType).ThenBy(x => x.SlotID).Select(x => x.Unlock)) modules.Add(m.Code);
                                                }
                                            }
                                        }
                                    } catch (Exception ex) {
                                        Trace.TraceError(ex.ToString());
                                        throw new ApplicationException(
                                            string.Format("Error processing commander: {0} - {1} of player {2} - {3}",
                                                          c.CommanderID,
                                                          c.Name,
                                                          user.AccountID,
                                                          user.Name),
                                            ex);
                                    }
                                }
                            }
                            else userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "jokecomm", Value = "1" });

                            userParams.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "commanders", Value = pc.ToBase64String() });
                        }
                    }
                }

                ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair { Key = "commanderTypes", Value = commanderTypes.ToBase64String() });
                if (mode == AutohostMode.Planetwars)
                {
                    string owner = planet.Faction != null ? planet.Faction.Shortcut : "";

                    var pwStructures = new LuaTable();
                    foreach (PlanetStructure s in planet.PlanetStructures.Where(x => x.StructureType!= null && !string.IsNullOrEmpty(x.StructureType.IngameUnitName))) {
                        pwStructures.Add("s" + s.StructureTypeID,
                                         new LuaTable
                                         {
                                             { "unitname", s.StructureType.IngameUnitName },
                                             //{ "isDestroyed", s.IsDestroyed ? true : false },
                                             { "name", string.Format("{0} {1} ({2})", owner, s.StructureType.Name, s.Account!= null ? s.Account.Name:"unowned") },
                                             { "description", s.StructureType.Description }
                                         });
                    }
                    ret.ModOptions.Add(new SpringBattleStartSetup.ScriptKeyValuePair
                                       { Key = "planetwarsStructures", Value = pwStructures.ToBase64String() });
                }

                return ret;
            } catch (Exception ex) {
                Trace.TraceError(ex.ToString());
                throw;
            }
        }
コード例 #13
0
        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;
        }
コード例 #14
0
 public BattleContext GetContext()
 {
     var ret = new BattleContext();
     ret.AutohostName = Founder.Name;
     ret.Map = MapName;
     ret.Mod = ModName;
     ret.Title = Title;
     ret.EngineVersion = EngineVersion;
     ret.IsMission = IsMission;
     ret.Rectangles = new Dictionary<int, BattleRect>(Rectangles);
     ret.Players = Users.Values.Where(x => x.SyncStatus != SyncStatuses.Unknown).Select(x => x.ToPlayerTeam()).ToList();
     ret.Bots = Bots.Values.Select(x => x.ToBotTeam()).ToList();
     ret.ModOptions = ModOptions;
     return ret;
 }
コード例 #15
0
        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();
            }
        }
コード例 #16
0
		public static RecommendedMapResult GetRecommendedMap(BattleContext context, bool pickNew) {
			var mode = context.GetMode();
		    var config = context.GetConfig();
			var res = new RecommendedMapResult();
			using (var db = new ZkDataContext()) {
				if (mode == AutohostMode.Planetwars)
				{

				    var info = Global.PlanetWarsMatchMaker.GetBattleInfo(context.AutohostName);
				    if (info != null)
				    {
				        res.MapName = info.Map;
                        res.Message = String.Format("Welcome to planet {0} {2}/PlanetWars/Planet/{1} attacked", info.Name, info.PlanetID, GlobalConst.BaseSiteUrl);
				    } else res.MapName = context.Map;
				}
				else { 
					if (!pickNew) {
						// autohost is not managed or has valid featured map - check disabled
    					res.MapName = context.Map;
						return res;
					}
					List<Resource> list = null;
					var players = context.Players.Count(x => !x.IsSpectator);
                    if (config != null && config.SplitBiggerThan != null && players > config.SplitBiggerThan) players = players/2; // expect the split
					switch (mode) {
                        case AutohostMode.Generic:
                        case AutohostMode.Teams:
                        case AutohostMode.None:
							var ret = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsTeams != false && x.MapIsSpecial != true);
							if (players > 11) ret = ret.Where(x => (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) > 16*16);
							else if (players > 8) ret = ret.Where(x => (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) > 16*16 && (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) <= 24*24);
                            else if (players > 5) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24 || x.MapIs1v1 == true);
							else ret = ret.Where(x => (x.MapHeight*x.MapHeight + x.MapWidth*x.MapWidth) <= 16*16 || x.MapIs1v1 == true);
							list = ret.ToList();

							break;
						case AutohostMode.Game1v1:
							list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIs1v1 == true && x.MapIsSpecial != true).ToList();
							break;
						case AutohostMode.GameChickens:
							ret = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsSpecial != true && (x.MapIsChickens == true || x.MapWaterLevel == 1));
                            if (players > 5) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16);
                            else if (players > 4) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) > 16 * 16 && (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24);
                            else if (players > 2) ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 24 * 24 || x.MapIs1v1 == true);
                            else ret = ret.Where(x => (x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth) <= 16 * 16 || x.MapIs1v1 == true);
							list = ret.ToList();

							break;
						case AutohostMode.GameFFA:
							list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true && x.MapFFAMaxTeams == players).ToList();
							if (!list.Any()) list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true && (players%x.MapFFAMaxTeams == 0)).ToList();
							if (!list.Any()) list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.FeaturedOrder != null && x.MapIsFfa == true).ToList();

							break;
					}
					if (list != null) {
						var r = new Random();
                        if (list.Count > 0)  res.MapName = list[r.Next(list.Count)].InternalName;
					}
				}
			}
			return res;
		}
コード例 #17
0
        /// <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;
        }
コード例 #18
0
        BalanceTeamsResult LegacyBalance(int teamCount, BalanceMode mode, BattleContext b, params List<Account>[] unmovablePlayers) {
            var ret = new BalanceTeamsResult();

            try {
                ret.CanStart = true;
                ret.Players = b.Players.ToList();

                var db = new ZkDataContext();
                var nonSpecList = b.Players.Where(y => !y.IsSpectator).Select(y => (int?)y.LobbyID).ToList();
                var accs =
                    db.Accounts.Where(x => nonSpecList.Contains(x.AccountID)).ToList();
                if (accs.Count < 1) {
                    ret.CanStart = false;
                    return ret;
                }
                if (teamCount < 1) teamCount = 1;
                if (teamCount > accs.Count) teamCount = accs.Count;
                if (teamCount == 1) {
                    foreach (var p in ret.Players) p.AllyID = 0;
                    return ret;
                }

                maxTeamSize = (int)Math.Ceiling(accs.Count/(double)teamCount);

                teams.Clear();
                for (var i = 0; i < teamCount; i++) {
                    var team = new BalanceTeam();
                    teams.Add(team);
                    if (unmovablePlayers != null && unmovablePlayers.Length > i) {
                        var unmovables = unmovablePlayers[i];
                        team.AddItem(new BalanceItem(unmovablePlayers[i].ToArray()) { CanBeMoved = false });
                        accs.RemoveAll(x => unmovables.Any(y => y.AccountID == x.AccountID));
                    }
                }

                balanceItems = new List<BalanceItem>();
                if (mode == BalanceMode.ClanWise) {
                    var clanGroups = accs.GroupBy(x => x.ClanID ?? x.AccountID).ToList();
                    if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize)) mode = BalanceMode.Normal;
                    else balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(x.ToArray())));
                }
                if (mode == BalanceMode.FactionWise) {
                    balanceItems.Clear();
                    var factionGroups = accs.GroupBy(x => x.FactionID ?? x.AccountID).ToList();
                    balanceItems.AddRange(factionGroups.Select(x => new BalanceItem(x.ToArray())));
                } 

                if (mode == BalanceMode.Normal) {
                    balanceItems.Clear();
                    balanceItems.AddRange(accs.Select(x => new BalanceItem(x)));
                }

                var sw = new Stopwatch();
                sw.Start();
                RecursiveBalance(0);
                sw.Stop();

                if (bestTeams == null)
                {
                    var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                    fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                    return fallback;
                }

                var minSize = bestTeams.Min(x => x.Count);
                var maxSize = bestTeams.Max(x => x.Count);
                var sizesWrong = maxSize/(double)minSize > MaxTeamSizeDifferenceRatio;

                // cbalance failed, rebalance using normal
                if (mode == BalanceMode.ClanWise && (bestTeams == null || GetTeamsDifference(bestTeams) > MaxCbalanceDifference || sizesWrong))
                    return new Balancer().LegacyBalance(teamCount, BalanceMode.Normal, b, unmovablePlayers);
                        // cbalance failed, rebalance using normal

                if (sizesWrong && mode == BalanceMode.FactionWise) {
                    var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                    fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                    return fallback ; // fallback standard balance if PW balance fails
                    /*ret.CanStart = false;
                    ret.Message = string.Format("Failed to balance - too many people from same faction");
                    return ret;*/
                }

                if (unmovablePlayers != null && unmovablePlayers.Length > 0) {
                    var minElo = bestTeams.Min(x => x.AvgElo);
                    var maxElo = bestTeams.Max(x => x.AvgElo);
                    if (maxElo - minElo > GlobalConst.MaxPwEloDifference) {
                        var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                        fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                        return fallback; // fallback standard balance if PW balance fails
                        /*
                        ret.CanStart = false;
                        ret.Message = string.Format("Team difference is too big - win chance {0}% - spectate some or wait for more people",
                                                    Utils.GetWinChancePercent(maxElo - minElo));
                        return ret;*/
                    }
                }

                if (bestTeams == null) {
                    ret.CanStart = false;
                    ret.Message =
                        string.Format(
                            "Failed to balance {0} - too many people from same clan or faction (in teams game you can try !random and !forcestart)");
                    return ret;
                }
                else {
                    if (unmovablePlayers == null || unmovablePlayers.Length == 0) bestTeams = bestTeams.Shuffle(); // permute when not unmovable players present

                    var text = "( ";

                    var lastTeamElo = 0.0;
                    var allyNum = 0;
                    foreach (var team in bestTeams) {
                        if (allyNum > 0) text += " : ";
                        text += string.Format("{0}", (allyNum + 1));
                        if (allyNum > 0) text += string.Format("={0}%)", Utils.GetWinChancePercent(lastTeamElo - team.AvgElo));
                        lastTeamElo = team.AvgElo;

                        foreach (var u in team.Items.SelectMany(x => x.LobbyId)) ret.Players.Single(x => x.LobbyID == u).AllyID = allyNum;
                        allyNum++;
                    }
                    text += ")";

                    ret.Message = String.Format("{0} players balanced {2} to {1} teams {3}. {4} combinations checked, spent {5}ms of CPU time",
                                                bestTeams.Sum(x => x.Count),
                                                teamCount,
                                                mode,
                                                text,
                                                iterationsChecked,
                                                sw.ElapsedMilliseconds);
                }
            } catch (Exception ex) {
                Trace.TraceError(ex.ToString());
                ret.Message = ex.ToString();
                ret.CanStart = false;
            }
            return ret;
        }
コード例 #19
0
        public  BattleContext GetContext()
        {
            var ret = new BattleContext();
            ret.AutohostName = Founder.Name;
            ret.Map = MapName;
            ret.Mod = ModName;
            ret.Players = Users.Where(x=>x.SyncStatus != SyncStatuses.Unknown).Select(x => new PlayerTeam() { AllyID = x.AllyNumber, Name = x.Name, LobbyID = x.LobbyUser.LobbyID, TeamID = x.TeamNumber, IsSpectator = x.IsSpectator }).ToList();

            ret.Bots = Bots.Select(x => new BotTeam() { BotName = x.Name, AllyID = x.AllyNumber, TeamID = x.TeamNumber, Owner = x.owner, BotAI = x.aiLib }).ToList();
            return ret;
        }
コード例 #20
0
        public static BalanceTeamsResult BalanceTeams(BattleContext context, bool isGameStart, int? allyCount, bool? clanWise) {
            var config = context.GetConfig();
            var playerCount = context.Players.Count(x => !x.IsSpectator);

            // game is managed, is bigger than split limit and wants to start -> split into two and issue starts
            if (isGameStart && context.GetMode() != AutohostMode.None && config.SplitBiggerThan != null && config.SplitBiggerThan < playerCount) {
                new Thread(() =>
                    {
                        try {
                            SplitAutohost(context, true);
                        } catch (Exception ex) {
                            Trace.TraceError("Error when splitting game:{0}", ex);
                        }
                    }).Start();
                return new BalanceTeamsResult
                       {
                           CanStart = false,
                           Message =
                               string.Format("Game too big - splitting into two - max players is {0} here",
                                             config.SplitBiggerThan)
                       };
            }

            
            if (clanWise == null && (config.AutohostMode == AutohostMode.Generic || config.AutohostMode == AutohostMode.Teams)) clanWise = true;

            var res = PerformBalance(context, isGameStart, allyCount, clanWise, config, playerCount);

            if (context.GetMode() != AutohostMode.Planetwars) // planetwars skip other checks
            {

                if (isGameStart)
                {
                    if (playerCount < (config.MinToStart ?? 0))
                    {
                        res.Message = string.Format("This host needs at least {0} people to start", config.MinToStart);
                        res.CanStart = false;
                        return res;
                    }
                    if (playerCount > (config.MaxToStart ?? 99))
                    {
                        res.Message = string.Format("This host can only start with at most {0} players", config.MaxToStart);
                        res.CanStart = false;
                        return res;
                    }

                    // dont allow to start alone
                    if (playerCount <= 1)
                    {
                        if (res.DeleteBots)
                            return new BalanceTeamsResult
                            {
                                CanStart = false,
                                Message = "You cannot play alone on this host, wait for players or join another game room and play with bots."
                            };
                        if (!context.Bots.Any())
                            return new BalanceTeamsResult
                            {
                                CanStart = false,
                                Message = "Cannot play alone, you can add bots using button on bottom left."
                            };
                    }
                }
            }
            if (isGameStart) VerifySpecCheaters(context, res);

            return res;
        }