Ejemplo n.º 1
0
 public void SetForHosting(LobbyHostingContext startContext,
                           string ip,
                           int?port,
                           string myUser,
                           string myPassword)
 {
     LobbyStartContext = startContext;
     EngineVersion     = startContext.EngineVersion;
     IsHosting         = true;
     IpAddress         = ip ?? "127.0.0.1";
     Port          = port ?? 8452;
     MyUserName    = myUser;
     MyPassword    = myPassword;
     ActualPlayers =
         LobbyStartContext.Players.Select(
             x =>
             new BattlePlayerResult(x.Name)
     {
         AllyNumber    = x.AllyID,
         IsSpectator   = x.IsSpectator,
         IsVictoryTeam = false,
         IsIngameReady = false,
         IsIngame      = false,
     }).ToList();
 }
Ejemplo n.º 2
0
        public event EventHandler <SpringLogEventArgs> GameOver; // game has ended


        public string HostGame(LobbyHostingContext startContext, string host, int port)
        {
            if (!File.Exists(paths.GetDedicatedServerPath(startContext.EngineVersion)))
            {
                throw new ApplicationException($"Dedicated server executable not found: {paths.GetDedicatedServerPath(startContext.EngineVersion)}");
            }

            Context = new SpringBattleContext();
            Context.SetForHosting(startContext, host, port, null, null);

            if (!IsRunning)
            {
                talker              = new Talker();
                talker.SpringEvent += talker_SpringEvent;
                Context.IsHosting   = true;

                scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + startContext.FounderName + ".txt").Replace('\\', '/');

                var script = ScriptGenerator.GenerateHostScript(Context, talker.LoopbackPort);
                timer.Start();

                StartDedicated(script);
                return(script);
            }
            else
            {
                Trace.TraceError("Dedicated server already running");
            }
            return(null);
        }
Ejemplo n.º 3
0
        public string HostGame(LobbyHostingContext startContext, string host, int port, string myName, string myPassword)
        {
            if (!File.Exists(paths.GetSpringExecutablePath(startContext.EngineVersion)))
            {
                throw new ApplicationException($"Spring executable not found: {paths.GetSpringExecutablePath(startContext.EngineVersion)}");
            }

            Context = new SpringBattleContext();
            Context.SetForHosting(startContext, host, port, myName, myPassword);

            if (!IsRunning)
            {
                Context.IsHosting = true;

                scriptPath = Utils.MakePath(paths.WritableDirectory, "script_" + myName + ".txt").Replace('\\', '/');

                var script = ScriptGenerator.GenerateHostScript(Context, 0);

                StartSpring(script);
                return(script);
            }
            else
            {
                Trace.TraceError("Spring already running");
            }
            return(null);
        }
Ejemplo n.º 4
0
        public static BalanceTeamsResult BalanceTeams(LobbyHostingContext context, bool isGameStart, int?allyCount, bool?clanWise)
        {
            var playerCount = context.Players.Count(x => !x.IsSpectator);


            if (clanWise == null && (context.Mode == AutohostMode.Teams))
            {
                clanWise = true;
            }


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

            if (context.Mode != AutohostMode.None && context.Mode != AutohostMode.GameChickens)
            {
                if (isGameStart)
                {
                    // dont allow to start alone
                    if (playerCount <= 1)
                    {
                        return(new BalanceTeamsResult
                        {
                            CanStart = false,
                            Message = "Sorry this room type needs more human players, open cooperative battle to fight against bots."
                        });
                    }
                }
            }
            if (isGameStart)
            {
                VerifySpecCheaters(context, res);
            }

            return(res);
        }
Ejemplo n.º 5
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);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        ///     Writes join messages and tells <see cref="Springie" /> to force spectate player if needed
        /// </summary>
        public static PlayerJoinResult AutohostPlayerJoined(LobbyHostingContext context, int accountID)
        {
            var res  = new PlayerJoinResult();
            var mode = context.Mode;

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

                    if (account != null)
                    {
                        var owner = "";
                        if (planet.Account != null)
                        {
                            owner = planet.Account.Name;
                        }
                        var 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 + ", ";
                        }

                        var 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);
                    }
                }
            }

            return(null);
        }
Ejemplo n.º 7
0
        public LobbyHostingContext GetContext()
        {
            var ret = new LobbyHostingContext();

            ret.FounderName      = FounderName;
            ret.Map              = MapName;
            ret.Mod              = ModName;
            ret.Title            = Title;
            ret.EngineVersion    = EngineVersion;
            ret.IsMission        = IsMission;
            ret.Players          = Users.Values.Where(x => x != null).Select(x => x.ToPlayerTeam()).ToList();
            ret.Bots             = Bots.Values.Where(x => x != null).Select(x => x.ToBotTeam()).ToList();
            ret.ModOptions       = new Dictionary <string, string>(ModOptions);
            ret.Mode             = Mode;
            ret.IsMatchMakerGame = IsMatchMakerBattle;
            ret.BattleID         = BattleID;
            return(ret);
        }
Ejemplo n.º 8
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);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        ///     Picks a map and writes a message if applicable
        /// </summary>
        /// <param name="context">The battle whose map needs selection</param>
        /// <remarks>
        ///     <para>
        ///         For Planetwars, picks the map given by the Planetwars matchmaker; else picks a featured map with the
        ///         appropriate tags
        ///     </para>
        ///     <para>For team and chickens games, picks a map of appropriate size based on current player count</para>
        ///     <para>
        ///         For FFA, prefer maps that have a number of boxes equal to player count, or at least a number of boxes that is
        ///         a multiple of player count
        ///     </para>
        /// </remarks>
        public static Resource GetRecommendedMap(LobbyHostingContext context, MapSupportLevel minimumSupportLevel = MapSupportLevel.Featured, IQueryable <Resource> candidates = null)
        {
            var mode = context.Mode;

            using (var db = new ZkDataContext())
            {
                List <Resource> list         = null;
                var             humanPlayers = context.Players.Count(x => !x.IsSpectator);
                var             botPlayers   = context.Bots.Count;
                var             allyteams    = context.Players.Where(x => !x.IsSpectator).Select(p => p.AllyID).Union(context.Bots.Select(b => b.AllyID)).Distinct().Count();

                var level = context.IsMatchMakerGame ? MapSupportLevel.MatchMaker : minimumSupportLevel;


                switch (mode)
                {
                case AutohostMode.GameChickens:
                    if (!context.Bots.Any(b => b.IsChicken))
                    {
                        mode = AutohostMode.Teams;
                    }
                    break;

                case AutohostMode.GameFFA:
                    allyteams = humanPlayers;
                    break;

                case AutohostMode.None:
                    if (allyteams > 2)
                    {
                        mode = AutohostMode.GameFFA;
                    }
                    if (context.Players.Where(x => !x.IsSpectator).Select(p => p.AllyID).Distinct().Count() == 1 && botPlayers > 0 && context.Bots.Any(b => b.IsChicken))
                    {
                        mode = AutohostMode.GameChickens;
                    }
                    if (humanPlayers == 2 && botPlayers == 0 && allyteams == 2)
                    {
                        mode = AutohostMode.Game1v1;
                    }
                    break;
                }
                var ret = candidates ?? db.Resources.AsQueryable();
                switch (mode)
                {
                case AutohostMode.Teams:
                case AutohostMode.None:

                    ret = ret.Where(
                        x => x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsTeams != false && x.MapIsSpecial != true);
                    if (humanPlayers > 11)
                    {
                        ret = ret.Where(x => x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth > 16 * 16);
                    }
                    else if (humanPlayers > 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 (humanPlayers > 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 =
                        ret.Where(
                            x => x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIs1v1 == true && x.MapIsSpecial != true).ToList();
                    break;

                case AutohostMode.GameChickens:
                    if (!UseNormalMapForChickens)
                    {
                        ret =
                            ret.Where(
                                x =>
                                x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsSpecial != true && x.MapIsChickens == true);
                    }
                    if (!ret.Any() || UseNormalMapForChickens)
                    {
                        ret = ret.Where(
                            x =>
                            x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsSpecial != true &&
                            (x.MapWaterLevel == 1));
                        if (humanPlayers > 5)
                        {
                            ret = ret.Where(x => x.MapHeight * x.MapHeight + x.MapWidth * x.MapWidth > 16 * 16);
                        }
                        else if (humanPlayers > 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 (humanPlayers > 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 =
                        ret.Where(
                            x => x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsFfa == true && x.MapFFAMaxTeams == allyteams)
                        .ToList();
                    if (!list.Any())
                    {
                        list =
                            ret.Where(
                                x =>
                                x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsFfa == true &&
                                (humanPlayers % x.MapFFAMaxTeams == 0)).ToList();
                    }
                    if (!list.Any())
                    {
                        list = ret.Where(x => x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsFfa == true).ToList();
                    }

                    break;
                }
                if (list != null)
                {
                    var r = new Random();
                    if (list.Count > 0)
                    {
                        var resource = list[r.Next(list.Count)];
                        return(resource);
                    }
                }
            }
            return(null);
        }
Ejemplo n.º 10
0
        /// <summary>
        ///     Sets up all the things that Springie needs to know for the battle: how to balance, who to get extra commanders,
        ///     what PlanetWars structures to create, etc.
        /// </summary>
        public static LobbyHostingContext GetDedicatedServerStartSetup(LobbyHostingContext context)
        {
            var ret = context;

            try
            {
                var mode = context.Mode;

                var commProfiles = new LuaTable();
                var db           = new ZkDataContext();

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


                // write Planetwars details to modoptions (for widget)
                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["attackingFaction"]      = attacker.Shortcut;
                    ret.ModOptions["attackingFactionName"]  = attacker.Name;
                    ret.ModOptions["attackingFactionColor"] = attacker.Color;
                    if (defender != null)
                    {
                        ret.ModOptions["defendingFaction"]      = defender.Shortcut;
                        ret.ModOptions["defendingFactionName"]  = defender.Name;
                        ret.ModOptions["defendingFactionColor"] = defender.Color;
                    }
                    else
                    {
                        ret.ModOptions["defendingFaction"]      = "Mercenary";
                        ret.ModOptions["defendingFactionName"]  = "Local militia";
                        ret.ModOptions["defendingFactionColor"] = "#CCCCCC";
                    }
                    ret.ModOptions["planet"] = planet.Name;
                }

                // write player custom keys (level, elo, is muted, etc.)
                foreach (var p in context.Players)
                {
                    var user = db.Accounts.Where(x => x.AccountID == p.LobbyID).Include(x => x.RelalationsByOwner).FirstOrDefault();
                    if (user != null)
                    {
                        var userParams = new Dictionary <string, string>();
                        ret.UserParameters[p.Name] = userParams;

                        userParams["LobbyID"]     = user.AccountID.ToString();
                        userParams["CountryCode"] = user.HideCountry ? "??" : user.Country;

                        var userBanMuted = Punishment.GetActivePunishment(user.AccountID, null, null, x => x.BanMute) != null;
                        if (userBanMuted)
                        {
                            userParams["muted"] = "1";
                        }
                        userParams["faction"]  = user.Faction != null ? user.Faction.Shortcut : "";
                        userParams["clan"]     = user.Clan != null ? user.Clan.Shortcut : "";
                        userParams["clanfull"] = user.Clan != null ? user.Clan.ClanName : "";

                        userParams["level"] = user.Level.ToString();
                        //userParams["mm_elo"] = Math.Round(user.EffectiveMmElo).ToString();
                        //userParams["casual_elo"] = Math.Round(user.EffectiveElo).ToString();

                        userParams["elo"] = Math.Round(user.GetBestRating().Elo).ToString();

                        userParams["icon"]      = user.GetIconName();
                        userParams["avatar"]    = user.Avatar;
                        userParams["badges"]    = string.Join(",", user.GetBadges());
                        userParams["admin"]     = user.AdminLevel >= AdminLevel.Moderator ? "1" : "0";
                        userParams["room_boss"] = p.Name == context.FounderName ? "1" : "0";
                        if (p.PartyID.HasValue)
                        {
                            userParams["PartyID"] = p.PartyID.ToString();
                        }

                        var userSpecChatBlocked = Punishment.GetActivePunishment(user.AccountID, null, null, x => x.BanSpecChat) != null;;
                        userParams["can_spec_chat"] = userSpecChatBlocked ? "0" : "1";

                        userParams["ignored"] = string.Join(",", user.RelalationsByOwner.Where(x => x.Relation == Relation.Ignore).Select(x => x.Target.Name));
                        userParams["friends"] = string.Join(",", user.RelalationsByOwner.Where(x => x.Relation == Relation.Friend).Select(x => x.Target.Name));

                        if (!p.IsSpectator)
                        {
                            // set valid PW structure attackers
                            if (mode == AutohostMode.Planetwars)
                            {
                                userParams["pwRank"] = (user.AccountRolesByAccountID.Where(
                                                            x =>
                                                            !x.RoleType.IsClanOnly &&
                                                            (x.RoleType.RestrictFactionID == null || x.RoleType.RestrictFactionID == user.FactionID)).OrderBy(x => x.RoleType.DisplayOrder).Select(x => (int?)x.RoleType.DisplayOrder).FirstOrDefault() ?? 999).ToString();


                                var 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["canAttackPwStructures"] = "1";
                                }

                                userParams["pwInstructions"] = Convert.ToBase64String(Encoding.UTF8.GetBytes(GetPwInstructions(planet, user, db, attacker)));
                            }

                            if (accountIDsWithExtraComms.Contains(user.AccountID))
                            {
                                userParams["extracomm"] = "1";
                            }

                            var commProfileIDs       = new LuaTable();
                            var userCommandersBanned = Punishment.GetActivePunishment(user.AccountID, null, null, x => x.BanCommanders) != null;
                            if (!userCommandersBanned)
                            {
                                // set up commander data
                                foreach (var c in user.Commanders.Where(x => x.Unlock != null && x.ProfileNumber <= GlobalConst.CommanderProfileCount)
                                         )
                                {
                                    try
                                    {
                                        var commProfile = new LuaTable();

                                        if (string.IsNullOrEmpty(c.Name) || c.Name.Any(x => x == '"'))
                                        {
                                            c.Name = c.CommanderID.ToString();
                                        }
                                        commProfiles.Add("c" + c.CommanderID, commProfile);
                                        commProfileIDs.Add("c" + c.CommanderID);

                                        // process decoration icons
                                        var decorations = new LuaTable();
                                        foreach (var d in
                                                 c.CommanderDecorations.Where(x => x.Unlock != null).OrderBy(x => x.SlotID).Select(x => x.Unlock))
                                        {
                                            var 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);
                                                    var entry = new LuaTable();
                                                    entry.Add("image", iconName);
                                                    decorations.Add("icon_" + iconPosition.ToLower(), entry);
                                                }
                                            }
                                            else
                                            {
                                                decorations.Add(d.Code);
                                            }
                                        }

                                        commProfile["name"]        = c.Name.Substring(0, Math.Min(25, c.Name.Length));
                                        commProfile["chassis"]     = c.Unlock.Code;
                                        commProfile["decorations"] = decorations;

                                        var modules = new LuaTable();
                                        commProfile["modules"] = modules;

                                        for (var i = 1; i <= GlobalConst.NumCommanderLevels; i++)
                                        {
                                            var modulesForLevel = new LuaTable();
                                            modules.Add(modulesForLevel);
                                            var modulesOrdered = c.CommanderModules.Where(x => x.CommanderSlot.MorphLevel == i).ToList();
                                            var slots          = db.CommanderSlots.ToList().Where(x => x.MorphLevel == i && (x.ChassisID == null || (x.ChassisID == c.ChassisUnlockID))).ToList();
                                            slots.Sort(delegate(CommanderSlot x, CommanderSlot y)
                                            {
                                                UnlockTypes type1 = x.UnlockType;
                                                UnlockTypes type2 = y.UnlockType;
                                                if (type1 == UnlockTypes.WeaponManualFire || type1 == UnlockTypes.WeaponBoth)
                                                {
                                                    type1 = UnlockTypes.Weapon;
                                                }
                                                if (type2 == UnlockTypes.WeaponManualFire || type2 == UnlockTypes.WeaponBoth)
                                                {
                                                    type2 = UnlockTypes.Weapon;
                                                }
                                                int result = type1.CompareTo(type2);
                                                if (result == 0)
                                                {
                                                    return(x.CommanderSlotID.CompareTo(y.CommanderSlotID));
                                                }
                                                else
                                                {
                                                    return(result);
                                                }
                                            });
                                            foreach (var slot in slots)
                                            {
                                                String value  = String.Empty;
                                                var    module = c.CommanderModules.FirstOrDefault(x => x.SlotID == slot.CommanderSlotID);
                                                if (module != null)
                                                {
                                                    value = module.Unlock.Code;
                                                }
                                                modulesForLevel.Add(value);
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Trace.TraceError(ex.ToString());
                                        throw new ApplicationException(
                                                  $"Error processing commander: {c.CommanderID} - {c.Name} of player {user.AccountID} - {user.Name}",
                                                  ex);
                                    }
                                }
                            }
                            else
                            {
                                userParams["jokecomm"] = "1";
                            }

                            userParams["commanders"] = commProfileIDs.ToBase64String();
                        }
                    }
                }
                ret.ModOptions["commanderTypes"] = commProfiles.ToBase64String();

                // set PW structures
                if (mode == AutohostMode.Planetwars)
                {
                    var owner = planet.Faction != null ? planet.Faction.Shortcut : "";

                    var pwStructures = new LuaTable();
                    foreach (
                        var s in planet.PlanetStructures.Where(x => x.StructureType != null && !string.IsNullOrEmpty(x.StructureType.IngameUnitName)))
                    {
                        pwStructures.Add(s.StructureType.IngameUnitName,
                                         new LuaTable
                        {
                            { "unitname", s.StructureType.IngameUnitName },
                            { "owner", s.Account?.Name },
                            { "canBeEvacuated", s.StructureType.IsIngameEvacuable },
                            { "canBeDestroyed", s.StructureType.IsIngameDestructible },
                            //{ "isDestroyed", s.IsDestroyed ? true : false },
                            {
                                "name", $"{owner} {s.StructureType.Name} ({(s.Account != null ? s.Account.Name : "unowned")})"
                            },
                            { "description", s.StructureType.Description }
                        });
                    }
                    ret.ModOptions["planetwarsStructures"] = pwStructures.ToBase64String();
                }

                return(ret);
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                throw;
            }
        }
Ejemplo n.º 11
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);
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        ///     The function that actually moves players arounds
        /// </summary>
        /// <param name="teamCount"></param>
        /// <param name="mode"></param>
        /// <param name="b"></param>
        /// <param name="unmovablePlayers"></param>
        /// <returns></returns>
        public BalanceTeamsResult LegacyBalance(int teamCount, BalanceMode mode, LobbyHostingContext b, params List <Account>[] unmovablePlayers)
        {
            var ret = new BalanceTeamsResult();

            if (b.IsMatchMakerGame)
            {
                mode = BalanceMode.Party;                     // override, for matchmaker mode is always party
            }
            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(b.IsMatchMakerGame, unmovablePlayers[i].ToArray())
                        {
                            CanBeMoved = false
                        });
                        accs.RemoveAll(x => unmovables.Any(y => y.AccountID == x.AccountID));
                    }
                }

                balanceItems = new List <BalanceItem>();
                if (mode == BalanceMode.Party)
                {
                    var clanGroups = accs.GroupBy(x => b.Players.First(p => p.Name == x.Name).PartyID ?? x.AccountID).ToList();
                    if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize))
                    {
                        mode = BalanceMode.Normal;
                    }
                    else
                    {
                        balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray())));
                    }
                }

                if (mode == BalanceMode.ClanWise)
                {
                    var clanGroups = accs.GroupBy(x => b.Players.First(p => p.Name == x.Name).PartyID ?? 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(b.IsMatchMakerGame, 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(b.IsMatchMakerGame, x.ToArray())));
                }

                if (mode == BalanceMode.Normal)
                {
                    balanceItems.Clear();
                    balanceItems.AddRange(accs.Select(x => new BalanceItem(b.IsMatchMakerGame, 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.EloAvg);
                    var maxElo = bestTeams.Max(x => x.EloAvg);
                    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);
                }
                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));
                    text       += string.Format("={0}%)", (int)Math.Round((1.0 / (1.0 + Math.Pow(10, ((team.EloAvg - bestTeams.Where(x => !x.Equals(team)).Select(x => x.EloAvg).Average())) / 400.0))) * 100.0 * 2 / bestTeams.Count));
                    lastTeamElo = team.EloAvg;

                    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);
        }
Ejemplo n.º 13
0
        //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));
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        ///     Picks a map and writes a message if applicable
        /// </summary>
        /// <param name="context">The battle whose map needs selection</param>
        /// <remarks>
        ///     <para>
        ///         For Planetwars, picks the map given by the Planetwars matchmaker; else picks a featured map with the
        ///         appropriate tags
        ///     </para>
        ///     <para>For team and chickens games, picks a map of appropriate size based on current player count</para>
        ///     <para>
        ///         For FFA, prefer maps that have a number of boxes equal to player count, or at least a number of boxes that is
        ///         a multiple of player count
        ///     </para>
        /// </remarks>
        public static Resource GetRecommendedMap(LobbyHostingContext context)
        {
            var mode = context.Mode;

            using (var db = new ZkDataContext())
            {
                List <Resource> list    = null;
                var             players = context.Players.Count(x => !x.IsSpectator);

                var level = context.IsMatchMakerGame ? MapSupportLevel.MatchMaker : MapSupportLevel.Featured;

                switch (mode)
                {
                case AutohostMode.Teams:
                case AutohostMode.None:
                    var ret =
                        db.Resources.Where(
                            x => x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && 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.MapSupportLevel >= level && x.MapIs1v1 == true && x.MapIsSpecial != true).ToList();
                    break;

                case AutohostMode.GameChickens:
                    ret =
                        db.Resources.Where(
                            x =>
                            x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && 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.MapSupportLevel >= level && x.MapIsFfa == true && x.MapFFAMaxTeams == players)
                        .ToList();
                    if (!list.Any())
                    {
                        list =
                            db.Resources.Where(
                                x =>
                                x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsFfa == true &&
                                (players % x.MapFFAMaxTeams == 0)).ToList();
                    }
                    if (!list.Any())
                    {
                        list = db.Resources.Where(x => x.TypeID == ResourceType.Map && x.MapSupportLevel >= level && x.MapIsFfa == true).ToList();
                    }

                    break;
                }
                if (list != null)
                {
                    var r = new Random();
                    if (list.Count > 0)
                    {
                        var resource = list[r.Next(list.Count)];
                        return(resource);
                    }
                }
            }
            return(null);
        }
Ejemplo n.º 15
0
        /// <summary>
        ///     Sets up all the things that Springie needs to know for the battle: how to balance, who to get extra commanders,
        ///     what PlanetWars structures to create, etc.
        /// </summary>
        public static LobbyHostingContext GetDedicatedServerStartSetup(LobbyHostingContext context)
        {
            var ret = context;

            try
            {
                var mode = context.Mode;

                var commProfiles = new LuaTable();
                var db           = new ZkDataContext();

                // calculate to whom to send extra comms
                var accountIDsWithExtraComms = new Dictionary <int, int>();
                if (mode == AutohostMode.Planetwars || mode == AutohostMode.GameFFA || mode == AutohostMode.Teams)
                {
                    var groupedByTeam = context.Players.Where(x => !x.IsSpectator).GroupBy(x => x.AllyID).OrderByDescending(x => x.Count());
                    var biggest       = groupedByTeam.FirstOrDefault();
                    if (biggest != null)
                    {
                        foreach (var other in groupedByTeam.Skip(1))
                        {
                            var cnt = biggest.Count() - other.Count();
                            if (cnt > 0)
                            {
                                // example case: 3 players on this team, 8 players on largest team
                                // 5 bonus comms to dole out to this team
                                // per_player = 1 (integer result of 5/3)
                                // remainder: 2, so now cnt = 2
                                // iterate over all players in this team
                                //  first player: cnt == 2, >0 so we give him a second extra comm
                                //  second player: cnt == 1, >0 so same deal
                                //  from now on cnt <= 0 so the last player only gets the one extra comm
                                int per_player = cnt / other.Count();
                                cnt = cnt % other.Count();
                                foreach (var a in other
                                         .Select(x => db.Accounts.First(y => y.AccountID == x.LobbyID))
                                         .OrderByDescending(x => x.GetRating(RatingCategory.Casual).Elo))
                                {
                                    accountIDsWithExtraComms.Add(a.AccountID, per_player + (cnt > 0 ? 1 : 0));
                                    cnt--;
                                }
                            }
                        }
                    }
                }


                // write Planetwars details to modoptions (for widget)
                Faction attacker = null;
                Faction defender = null;
                Planet  planet   = null;
                if (mode == AutohostMode.Planetwars)
                {
                    var galaxy = db.Galaxies.First(x => x.IsDefault);
                    planet   = galaxy.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["attackingFaction"]      = attacker.Shortcut;
                    ret.ModOptions["attackingFactionName"]  = attacker.Name;
                    ret.ModOptions["attackingFactionColor"] = attacker.Color;
                    if (defender != null)
                    {
                        ret.ModOptions["defendingFaction"]      = defender.Shortcut;
                        ret.ModOptions["defendingFactionName"]  = defender.Name;
                        ret.ModOptions["defendingFactionColor"] = defender.Color;
                    }
                    else
                    {
                        ret.ModOptions["defendingFaction"]      = "Mercenary";
                        ret.ModOptions["defendingFactionName"]  = "Local militia";
                        ret.ModOptions["defendingFactionColor"] = "#CCCCCC";
                    }
                    ret.ModOptions["planet"]        = planet.Name;
                    ret.ModOptions["pw_galaxyTurn"] = galaxy.Turn.ToString();

                    ret.ModOptions["pw_baseIP"]            = GlobalConst.BaseInfluencePerBattle.ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_dropshipIP"]        = planet.GetEffectiveShipIpBonus(attacker).ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_defenseIP"]         = planet.GetEffectiveIpDefense().ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_attackerIP"]        = (planet.PlanetFactions.FirstOrDefault(x => x.FactionID == attacker.FactionID)?.Influence ?? 0).ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_maxIP"]             = GlobalConst.PlanetWarsMaximumIP.ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_neededIP"]          = GlobalConst.InfluenceToCapturePlanet.ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_attackerWinLoseCC"] = GlobalConst.PlanetWarsAttackerWinLoseCcMultiplier.ToString(CultureInfo.InvariantCulture);
                    ret.ModOptions["pw_defenderWinKillCC"] = GlobalConst.PlanetWarsDefenderWinKillCcMultiplier.ToString(CultureInfo.InvariantCulture);
                }

                // write player custom keys (level, elo, is muted, etc.)
                foreach (var p in context.Players)
                {
                    var user = db.Accounts.Where(x => x.AccountID == p.LobbyID).Include(x => x.RelalationsByOwner).FirstOrDefault();
                    if (user != null)
                    {
                        var userParams = new Dictionary <string, string>();
                        ret.UserParameters[p.Name] = userParams;

                        userParams["LobbyID"]     = user.AccountID.ToString();
                        userParams["CountryCode"] = user.HideCountry ? "??" : user.Country;

                        var userBanMuted = Punishment.GetActivePunishment(user.AccountID, null, null, null, x => x.BanMute) != null;
                        if (userBanMuted)
                        {
                            userParams["muted"] = "1";
                        }
                        userParams["faction"]  = user.Faction != null ? user.Faction.Shortcut : "";
                        userParams["clan"]     = user.Clan != null ? user.Clan.Shortcut : "";
                        userParams["clanfull"] = user.Clan != null ? user.Clan.ClanName : "";

                        userParams["level"] = user.Level.ToString();
                        //userParams["mm_elo"] = Math.Round(user.EffectiveMmElo).ToString();
                        //userParams["casual_elo"] = Math.Round(user.EffectiveElo).ToString();

                        userParams["elo"]       = Math.Round(user.GetRating(context.ApplicableRating).Elo).ToString();
                        userParams["elo_order"] = context.Players.Where(x => !x.IsSpectator)
                                                  .Select(x => db.Accounts.First(y => y.AccountID == x.LobbyID))
                                                  .Where(x => x.GetRating(context.ApplicableRating).Elo > user.GetRating(context.ApplicableRating).Elo)
                                                  .Count()
                                                  .ToString();

                        userParams["icon"]      = user.GetIconName();
                        userParams["avatar"]    = user.Avatar;
                        userParams["badges"]    = string.Join(",", user.GetBadges());
                        userParams["admin"]     = user.AdminLevel >= AdminLevel.Moderator ? "1" : "0";
                        userParams["room_boss"] = p.Name == context.FounderName ? "1" : "0";
                        if (p.PartyID.HasValue)
                        {
                            userParams["PartyID"] = p.PartyID.ToString();
                        }

                        var userSpecChatBlocked = Punishment.GetActivePunishment(user.AccountID, null, null, null, x => x.BanSpecChat) != null;;
                        userParams["can_spec_chat"] = userSpecChatBlocked ? "0" : "1";

                        userParams["ignored"] = string.Join(",", user.RelalationsByOwner.Where(x => x.Relation == Relation.Ignore).Select(x => x.Target.Name));
                        userParams["friends"] = string.Join(",", user.RelalationsByOwner.Where(x => x.Relation == Relation.Friend).Select(x => x.Target.Name));

                        if (!p.IsSpectator)
                        {
                            // set valid PW structure attackers
                            if (mode == AutohostMode.Planetwars)
                            {
                                userParams["pwRank"] = (user.AccountRolesByAccountID.Where(
                                                            x =>
                                                            !x.RoleType.IsClanOnly &&
                                                            (x.RoleType.RestrictFactionID == null || x.RoleType.RestrictFactionID == user.FactionID)).OrderBy(x => x.RoleType.DisplayOrder).Select(x => (int?)x.RoleType.DisplayOrder).FirstOrDefault() ?? 999).ToString();


                                var 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["canAttackPwStructures"] = "1";
                                }

                                userParams["pwInstructions"] = Convert.ToBase64String(Encoding.UTF8.GetBytes(GetPwInstructions(planet, user, db, attacker)));
                            }

                            if (accountIDsWithExtraComms.ContainsKey(user.AccountID))
                            {
                                userParams["extracomm"] = accountIDsWithExtraComms[user.AccountID].ToString();
                            }

                            var commProfileIDs       = new LuaTable();
                            var userCommandersBanned = Punishment.GetActivePunishment(user.AccountID, null, null, null, x => x.BanCommanders) != null;
                            if (!userCommandersBanned)
                            {
                                // set up commander data
                                foreach (var c in user.Commanders.Where(x => x.Unlock != null && x.ProfileNumber <= GlobalConst.CommanderProfileCount)
                                         )
                                {
                                    try
                                    {
                                        var commProfile = new LuaTable();

                                        if (string.IsNullOrEmpty(c.Name) || c.Name.Any(x => x == '"'))
                                        {
                                            c.Name = c.CommanderID.ToString();
                                        }
                                        commProfiles.Add("c" + c.CommanderID, commProfile);
                                        commProfileIDs.Add("c" + c.CommanderID);

                                        // process decoration icons
                                        var decorations = new LuaTable();
                                        foreach (var d in
                                                 c.CommanderDecorations.Where(x => x.Unlock != null).OrderBy(x => x.SlotID).Select(x => x.Unlock))
                                        {
                                            var 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);
                                                    var entry = new LuaTable();
                                                    entry.Add("image", iconName);
                                                    decorations.Add("icon_" + iconPosition.ToLower(), entry);
                                                }
                                            }
                                            else
                                            {
                                                decorations.Add(d.Code);
                                            }
                                        }

                                        commProfile["name"]        = LuaTable.SanitizeString(c.Name.Substring(0, Math.Min(25, c.Name.Length))) ?? "dummy";
                                        commProfile["chassis"]     = c.Unlock.Code;
                                        commProfile["decorations"] = decorations;

                                        var modules = new LuaTable();
                                        commProfile["modules"] = modules;

                                        for (var i = 1; i <= GlobalConst.NumCommanderLevels; i++)
                                        {
                                            var modulesForLevel = new LuaTable();
                                            modules.Add(modulesForLevel);
                                            //var modulesOrdered = c.CommanderModules.Where(x => x.CommanderSlot.MorphLevel == i).ToList();
                                            var slots = db.CommanderSlots.ToList().Where(x => x.MorphLevel == i && (x.ChassisID == null || (x.ChassisID == c.ChassisUnlockID))).ToList();
                                            slots.Sort(delegate(CommanderSlot x, CommanderSlot y)
                                            {
                                                UnlockTypes type1 = x.UnlockType;
                                                UnlockTypes type2 = y.UnlockType;
                                                if (type1 == UnlockTypes.WeaponManualFire || type1 == UnlockTypes.WeaponBoth)
                                                {
                                                    type1 = UnlockTypes.Weapon;
                                                }
                                                if (type2 == UnlockTypes.WeaponManualFire || type2 == UnlockTypes.WeaponBoth)
                                                {
                                                    type2 = UnlockTypes.Weapon;
                                                }
                                                int result = type1.CompareTo(type2);
                                                if (result == 0)
                                                {
                                                    return(x.CommanderSlotID.CompareTo(y.CommanderSlotID));
                                                }
                                                else
                                                {
                                                    return(result);
                                                }
                                            });
                                            foreach (var slot in slots)
                                            {
                                                String value  = String.Empty;
                                                var    module = c.CommanderModules.FirstOrDefault(x => x.SlotID == slot.CommanderSlotID);
                                                if (module != null)
                                                {
                                                    value = module.Unlock.Code;
                                                }
                                                modulesForLevel.Add(value);
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Trace.TraceError(ex.ToString());
                                        throw new ApplicationException(
                                                  $"Error processing commander: {c.CommanderID} - {c.Name} of player {user.AccountID} - {user.Name}",
                                                  ex);
                                    }
                                }
                            }
                            else
                            {
                                userParams["jokecomm"] = "1";
                            }

                            userParams["commanders"] = commProfileIDs.ToBase64String();
                        }
                    }
                }
                ret.ModOptions["commanderTypes"] = commProfiles.ToBase64String();

                /* General-purpose identifier.
                 * Prefer the more specific ones below when possible */
                ret.ModOptions["serverType"] = "ZKLS";

                /* Access to commands normally accessible only by the host.
                 * Lua calls prepend the / on their own, but not the autohost,
                 * so /say doesn't need it, but the cheat command does */
                ret.ModOptions["cheatCommandPrefix"] = "say !hostsay /";

                /* The server is listening for SPRINGIE strings (the game can skip those otherwise).
                 * See https://github.com/ZeroK-RTS/Zero-K-Infrastructure/blob/master/Shared/LobbyClient/DedicatedServer.cs#L317 */
                ret.ModOptions["sendSpringieData"] = "1";

                // set PW structures
                if (mode == AutohostMode.Planetwars)
                {
                    var owner = planet.Faction != null ? planet.Faction.Shortcut : "";

                    var pwStructures = new LuaTable();
                    foreach (
                        var s in planet.PlanetStructures.Where(x => x.StructureType != null && !string.IsNullOrEmpty(x.StructureType.IngameUnitName)))
                    {
                        pwStructures.Add(s.StructureType.IngameUnitName,
                                         new LuaTable
                        {
                            { "unitname", s.StructureType.IngameUnitName },
                            { "owner", s.Account?.Name },
                            { "canBeEvacuated", s.StructureType.IsIngameEvacuable },
                            { "canBeDestroyed", s.StructureType.IsIngameDestructible },
                            { "isInactive", !s.IsActive },
                            {
                                "name", $"{owner} {s.StructureType.Name} ({(s.Account != null ? s.Account.Name : "unowned")})"
                            },
                            { "description", s.StructureType.Description }
                        });
                    }
                    ret.ModOptions["planetwarsStructures"] = pwStructures.ToBase64String();
                }

                return(ret);
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                throw;
            }
        }