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; }
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(); }
/// <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; }
/// <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.Elo*x.EloWeight) .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; if (defender != null) ret.ModOptions["defendingFaction"] = defender.Shortcut; 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.Country; var userBanMuted = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanMute); 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(); var elo = user.EffectiveMmElo; userParams["elo"] = Math.Round(elo).ToString(); userParams["skill_order"] = ((context.IsMatchMakerGame ? user.CompetitiveRank : user.CasualRank) ?? int.MaxValue).ToString(); // send order of skills (For lists). Note this should be improved by sendng normalized list instead of ranks userParams["avatar"] = user.Avatar; userParams["admin"] = user.IsZeroKAdmin ? "1" : "0"; var userSpecChatBlocked = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanSpecChat); 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) { 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"; } } if (accountIDsWithExtraComms.Contains(user.AccountID)) userParams["extracomm"] = "1"; var commProfileIDs = new LuaTable(); var userCommandersBanned = user.PunishmentsByAccountID.Any(x => !x.IsExpired && x.BanCommanders); 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 = x.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" + s.StructureTypeID, new LuaTable { { "unitname", s.StructureType.IngameUnitName }, //{ "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; } }
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.Select(x => x.ToPlayerTeam()).ToList(); ret.Bots = Bots.Values.Select(x => x.ToBotTeam()).ToList(); ret.ModOptions = new Dictionary<string, string>(ModOptions); ret.Mode = Mode; ret.IsMatchMakerGame = IsMatchMakerBattle; return ret; }
/// <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> 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.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; } 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; }
/// <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); } }
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); // todo hackvar info = PlanetWarsMatchMaker.GetBattleInfo(context.AutohostName); PlanetWarsMatchMaker.AttackOption info = null; if (info == null) { res.Message = "Start battle using matchmaker"; res.CanStart = false; return res; } /* foreach (var matchUser in info.Attackers) AddPwPlayer(context, matchUser, res, 0); foreach (var 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); } // 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 = 2, BotAI = b.EffectBots, BotName = "Aliens" + cnt++ }); res.Message += "This planet is infested by aliens, fight for your survival"; return res; } */ return res; } }
/// <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) res = new Balancer().LegacyBalance(allyCount ?? 2, clanWise == true ? BalanceMode.ClanWise : BalanceMode.Normal, context); } break; case AutohostMode.Teams: 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.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.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 res.Bots.Add(new BotTeam() { AllyID = 1, BotName = "cai", 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; } }
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; }
static void AddPwPlayer(LobbyHostingContext context, string matchUser, BalanceTeamsResult res, int allyID) { var player = context.Players.FirstOrDefault(x => x.Name == matchUser); if (player == null) { player = new PlayerTeam { Name = matchUser }; ConnectedUser us; // todo hack if (Global.Server.ConnectedUsers.TryGetValue(matchUser, out us)) player.LobbyID = us.User.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 }); }
/// <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; }
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; }