示例#1
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
            });
        }
示例#2
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);
            }
        }
示例#3
0
        BalanceTeamsResult PlanetwarsBalance(LobbyHostingContext 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);

                res.Players = context.Players;

                // bots game
                var 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 = 1, BotAI = b.EffectBots, BotName = "Aliens" + cnt++
                        });
                    }

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

                return(res);
            }
        }
示例#4
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);
            }
        }
        //Interface function to comply with LegacyBalance
        public static BalanceTeamsResult BalanceInterface(int teamCount, BalanceMode mode, LobbyHostingContext b, params List <Account>[] unmovablePlayers)
        {
            if (b.Players.Where(y => !y.IsSpectator).Count() > 38) // dont try doing million+ iterations (arbitrarily chosen cap)
            {
                Trace.TraceWarning("PartitionBalance called with too many players: " + b.Players.Where(y => !y.IsSpectator).Count());
                return(new Balancer().LegacyBalance(teamCount, mode, b, unmovablePlayers));
            }
            if (teamCount != 2)
            {
                Trace.TraceWarning("PartitionBalance called with invalid number of teams: " + teamCount);
                return(new Balancer().LegacyBalance(teamCount, mode, b, unmovablePlayers));
            }
            if (unmovablePlayers.Length > 0)
            {
                Trace.TraceWarning("PartitionBalance called with too many unmovable players: " + unmovablePlayers.Length);
                return(new Balancer().LegacyBalance(teamCount, mode, b, unmovablePlayers));
            }
            if (mode == BalanceMode.FactionWise)
            {
                Trace.TraceWarning("PartitionBalance called with FactionWise balance mode, which is unsupported");
                return(new Balancer().LegacyBalance(teamCount, mode, b, unmovablePlayers));
            }
            try
            {
                if (b.IsMatchMakerGame)
                {
                    mode = BalanceMode.Party;
                }

                BalanceTeamsResult ret = new BalanceTeamsResult();

                ret.CanStart = true;
                ret.Players  = b.Players.ToList();
                ret.Bots     = b.Bots.ToList();

                List <PlayerItem> players = new List <PlayerItem>();
                using (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);
                    }
                    players = b.Players.Where(y => !y.IsSpectator).Select(x => new PlayerItem(x.LobbyID, accs.First(a => a.AccountID == x.LobbyID).GetRating(b.ApplicableRating).Elo, x.Clan, x.PartyID)).ToList();
                }

                var dualResult = Balance(mode, players);
                dualResult.Players.ForEach(r => ret.Players.Where(x => x.LobbyID == r.LobbyID).ForEach(x => x.AllyID = r.AllyID));
                ret.Message = dualResult.Message;
                return(ret);
            }
            catch (Exception ex)
            {
                Trace.TraceWarning("PartitionBalance encountered an error: " + ex);
                return(new Balancer().LegacyBalance(teamCount, mode, b, unmovablePlayers));
            }
        }
示例#6
0
        /// <summary>
        ///     Makes <see cref="Springie" /> print a message if two or more people have the same IP
        /// </summary>
        /// <param name="context"></param>
        /// <param name="res">The <see cref="BalanceTeamsResult" /> to write the message to</param>
        static void VerifySpecCheaters(LobbyHostingContext 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

                    foreach (var grp in context.Players.GroupBy(x => ipByLobbyID[x.LobbyID]).Where(x => x.Count() > 1))
                    {
                        res.Message +=
                            $"\nThese people are in same location: {string.Join(", ", grp.Select(x => x.Name))}";
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError("Error checking speccheaters: {0}", ex);
            }
        }
示例#7
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);
            }
        }
示例#8
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);
        }
示例#9
0
        /// <summary>
        ///     Calls <see cref="LegacyBalance" /> with the appropriate parameters depending on game settings and conditions
        /// </summary>
        /// <param name="isGameStart">
        ///     If true and <see cref="AutohostMode" /> is none, do nothing (i.e. don't autobalance custom
        ///     rooms at start)
        /// </param>
        /// <param name="allyCount"></param>
        /// <param name="clanWise"></param>
        /// <param name="config"></param>
        /// <remarks>Also removes bots from team games, and tells people to add bots to a chicken game if absent</remarks>
        static BalanceTeamsResult PerformBalance(
            LobbyHostingContext context,
            bool isGameStart,
            int?allyCount,
            bool?clanWise)
        {
            var res  = new BalanceTeamsResult();
            var mode = context.Mode;

            using (var db = new ZkDataContext())
            {
                switch (mode)
                {
                case AutohostMode.None:
                {
                    if (!isGameStart)
                    {
                        if (allyCount == null || allyCount == 2)
                        {
                            res = PartitionBalance.BalanceInterface(2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context);
                        }
                        else
                        {
                            res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context);
                        }
                    }
                }
                break;

                case AutohostMode.Teams:
                case AutohostMode.Game1v1:
                {
                    res            = PartitionBalance.BalanceInterface(2, clanWise == false ? BalanceMode.Normal : BalanceMode.ClanWise, context);
                    res.DeleteBots = true;
                }
                break;

                case AutohostMode.GameChickens:
                {
                    res.Players = context.Players.ToList();
                    res.Bots    = context.Bots.ToList();
                    foreach (var p in res.Players)
                    {
                        p.AllyID = 0;
                    }
                    foreach (var b in res.Bots)
                    {
                        b.AllyID = 1;
                    }

                    // add chickens via modoptions hackish thingie
                    string chickBot = null;
                    if (context.ModOptions?.TryGetValue("chickenailevel", out chickBot) == true && !string.IsNullOrEmpty(chickBot) && chickBot != "none")
                    {
                        res.Bots.RemoveAll(x => x.BotAI.StartsWith("Chicken:"));
                        res.Bots.Add(new BotTeam()
                            {
                                AllyID = 1, BotName = "default_Chicken", BotAI = chickBot
                            });
                    }

                    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.";
                        var map = db.Resources.FirstOrDefault(x => x.InternalName == context.Map);
                        if (map?.MapIsChickens == true)
                        {
                            res.Bots.Add(new BotTeam()
                                {
                                    AllyID = 1, BotName = "default_Chicken", BotAI = "Chicken: Normal",
                                });
                        }
                        else
                        {
                            for (int i = 1; i <= res.Players.Where(x => !x.IsSpectator).Count(); i++)
                            {
                                res.Bots.Add(new BotTeam()
                                    {
                                        AllyID = 1, BotName = "cai" + i, BotAI = "CAI",
                                    });
                            }
                        }
                        res.Message = "Adding computer AI player for you";
                    }
                }
                break;

                case AutohostMode.GameFFA:
                {
                    res.DeleteBots = true;
                    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);
            }
        }