namespace Supercell.Laser.Server.Logic.Game { using System.Collections.Concurrent; using Supercell.Laser.Logic.Battle.Structures; using Supercell.Laser.Logic.Battle; using Supercell.Laser.Logic.Command.Home; using Supercell.Laser.Logic.Data; using Supercell.Laser.Logic.Home.Items; using Supercell.Laser.Logic.Message.Battle; using Supercell.Laser.Logic.Message.Home; using Supercell.Laser.Logic.Message.Team; using Supercell.Laser.Logic.Notification; using Supercell.Laser.Logic.Team; using Supercell.Laser.Logic.Util; using Supercell.Laser.Server.Networking; using Supercell.Laser.Server.Networking.Session; public static class Teams { // Fix 8: ConcurrentDictionary + Interlocked счётчик — необходимо перед // распараллеливанием Matchmaking.Update(). StartGame из разных слотов может // вызываться одновременно и обращаться к Teams.Get/Remove. private static ConcurrentDictionary Entries; private static long TeamIdCounter; public static void Init() { Entries = new ConcurrentDictionary(); TeamIdCounter = 0; } public static int Count => Entries.Count; public static TeamEntry Create() { TeamEntry entry = new TeamEntry(); // Interlocked.Increment — атомарный инкремент без отдельного лока. entry.Id = Interlocked.Increment(ref TeamIdCounter); Entries.TryAdd(entry.Id, entry); return entry; } public static void Remove(long id) { Entries.TryRemove(id, out _); } public static void StartGame(TeamEntry team) { try { if (team.Type == 0) { foreach (TeamMember member in team.Members) { var session0 = Sessions.GetSession(member.AccountId); if (session0 == null) continue; Connection connection = session0.Connection; connection.Send(new TeamGameStartingMessage() { LocationId = team.LocationId, Slot = team.EventSlot }); Matchmaking.RequestMatchmake(connection, team.EventSlot, team.Id); member.IsReady = false; } } if (team.Type == 1) { BattleMode battle = new BattleMode(team.LocationId); if (team.BattlePlayerMap != null) battle.SetPlayerMap(team.BattlePlayerMap); battle.Id = Battles.Add(battle); List entries = new List(); List sortedEntries = new List(); foreach (TeamMember member in team.Members) { var session1 = Sessions.GetSession(member.AccountId); if (session1 == null) continue; Connection connection = session1.Connection; MatchmakingEntry entry = new MatchmakingEntry(connection); entry.PrefferedTeam = member.TeamIndex; entries.Add(entry); member.IsReady = false; } if (GameModeUtil.HasTwoTeams(battle.GetGameModeVariation())) { for (int i = 0; i < entries.Count; i++) { sortedEntries.Add(entries[i]); } for (int i = 0; i < sortedEntries.Count; i++) { UDPSocket socket = UDPGateway.CreateSocket(); socket.TCPConnection = sortedEntries[i].Connection; socket.Battle = battle; sortedEntries[i].Connection.UdpSessionId = socket.SessionId; int teamIndex = sortedEntries[i].PrefferedTeam; BattlePlayer player = BattlePlayer.Create(sortedEntries[i].Connection.Home, sortedEntries[i].Connection.Avatar, i, teamIndex); player.TeamId = sortedEntries[i].PlayerTeamId; sortedEntries[i].Player = player; battle.AddPlayer(player, sortedEntries[i].Connection.UdpSessionId); } List team1BotsCharacters = new List(); List team2BotsCharacters = new List(); for (int i = battle.GetTeamPlayersCount(0); i < battle.GetPlayersCountWithGameModeVariation() / 2; i++) { if (team.DisabledBots.Contains(i)) continue; bool isBotValid = false; int botCharacter = -1; while (!isBotValid) { botCharacter = 16000000 + MatchmakingSlot.botBrawlers.OrderBy(f => Guid.NewGuid()).First(); isBotValid = !team1BotsCharacters.Contains(botCharacter); if (!isBotValid) isBotValid = !GameModeUtil.HasTwoTeams(battle.GetGameModeVariation()); } team1BotsCharacters.Add(botCharacter); CharacterData data = DataTables.Get(16).GetDataByGlobalId(botCharacter); BattlePlayer bot = BattlePlayer.CreateBotInfo((i - entries.Count + 2).ToString(), battle.GetPlayers().Count(), 0, botCharacter); battle.AddPlayer(bot, -1); } for (int i = battle.GetPlayersCountWithGameModeVariation() / 2 + battle.GetTeamPlayersCount(1); i < battle.GetPlayersCountWithGameModeVariation(); i++) { if (team.DisabledBots.Contains(i)) continue; bool isBotValid = false; int botCharacter = -1; while (!isBotValid) { botCharacter = 16000000 + MatchmakingSlot.botBrawlers.OrderBy(f => Guid.NewGuid()).First(); isBotValid = !team2BotsCharacters.Contains(botCharacter); if (!isBotValid) isBotValid = !GameModeUtil.HasTwoTeams(battle.GetGameModeVariation()); } team2BotsCharacters.Add(botCharacter); CharacterData data = DataTables.Get(16).GetDataByGlobalId(botCharacter); BattlePlayer bot = BattlePlayer.CreateBotInfo((i - entries.Count + 2).ToString(), battle.GetPlayers().Count(), 1, botCharacter); battle.AddPlayer(bot, -1); } } else if (GameModeUtil.HasFiveTeams(battle.GetGameModeVariation())) { sortedEntries = entries; for (int i = 0; i < entries.Count; i++) { UDPSocket socket = UDPGateway.CreateSocket(); socket.TCPConnection = sortedEntries[i].Connection; socket.Battle = battle; sortedEntries[i].Connection.UdpSessionId = socket.SessionId; int teamIndex = battle.GetGameModeVariation() == 9 ? i / 2 : i; BattlePlayer player = BattlePlayer.Create(sortedEntries[i].Connection.Home, sortedEntries[i].Connection.Avatar, i, teamIndex); player.TeamId = sortedEntries[i].PlayerTeamId; sortedEntries[i].Player = player; battle.AddPlayer(player, sortedEntries[i].Connection.UdpSessionId); } for (int i = entries.Count; i < battle.GetPlayersCountWithGameModeVariation(); i++) { int botCharacter = 16000000 + MatchmakingSlot.botBrawlers.OrderBy(f => Guid.NewGuid()).First(); int teamIndex = battle.GetGameModeVariation() == 9 ? i / 2 : i; CharacterData data = DataTables.Get(16).GetDataByGlobalId(botCharacter); BattlePlayer bot = BattlePlayer.CreateBotInfo(data.ItemName.ToUpper(), i, teamIndex, botCharacter); battle.AddPlayer(bot, -1); } } else { sortedEntries = entries; for (int i = 0; i < entries.Count; i++) { UDPSocket socket = UDPGateway.CreateSocket(); socket.TCPConnection = sortedEntries[i].Connection; socket.Battle = battle; sortedEntries[i].Connection.UdpSessionId = socket.SessionId; int teamIndex = battle.GetGameModeVariation() == 9 ? i / 2 : i; BattlePlayer player = BattlePlayer.Create(sortedEntries[i].Connection.Home, sortedEntries[i].Connection.Avatar, i, teamIndex); player.TeamId = sortedEntries[i].PlayerTeamId; sortedEntries[i].Player = player; battle.AddPlayer(player, sortedEntries[i].Connection.UdpSessionId); } for (int i = entries.Count; i < battle.GetPlayersCountWithGameModeVariation(); i++) { int botCharacter = 16000000 + MatchmakingSlot.botBrawlers.OrderBy(f => Guid.NewGuid()).First(); int teamIndex = battle.GetGameModeVariation() == 9 ? i / 2 : i; CharacterData data = DataTables.Get(16).GetDataByGlobalId(botCharacter); BattlePlayer bot = BattlePlayer.CreateBotInfo(data.ItemName.ToUpper(), i, teamIndex, botCharacter); battle.AddPlayer(bot, -1); } } for (int i = 0; i < sortedEntries.Count; i++) { StartLoadingMessage startLoading = new StartLoadingMessage(); startLoading.LocationId = battle.Location.GetGlobalId(); startLoading.TeamIndex = sortedEntries[i].Player.TeamIndex; startLoading.OwnIndex = sortedEntries[i].Player.PlayerIndex; startLoading.GameMode = battle.GetGameModeVariation(); startLoading.SetPlayerMap(battle.BattlePlayerMap); if (sortedEntries.Count <= 1) { startLoading.isFriendlyMatch = true; } sortedEntries[i].Connection.Avatar.UdpSessionId = sortedEntries[i].Connection.UdpSessionId; startLoading.Players.AddRange(battle.GetPlayers()); sortedEntries[i].Connection.Send(startLoading); battle.BattleWithTrophies = false; } battle.AddGameObjects(); battle.Start(); } } catch (Exception e) { Logger.Error($"[Teams.StartGame] {e.GetType().Name}: {e.Message}\n{e.StackTrace}"); } } public static TeamEntry Get(long id) { Entries.TryGetValue(id, out var entry); return entry; // null если не найден } } }