diff --git a/logic/Server/PlaybackServer.cs b/logic/Server/PlaybackServer.cs index 1506b97..449c1ed 100644 --- a/logic/Server/PlaybackServer.cs +++ b/logic/Server/PlaybackServer.cs @@ -5,6 +5,7 @@ using System.Threading; using Timothy.FrameRateTask; using Gaming; using Grpc.Core; +using System.Collections.Concurrent; namespace Server { @@ -12,13 +13,31 @@ namespace Server { protected readonly ArgumentOptions options; private int[,] teamScore; - private Dictionary semaDict = new(); + private ConcurrentDictionary semaDict = new(); private object semaDictLock = new(); private MessageToClient? currentGameInfo = new(); + private MessageOfObj currentMapMsg = new(); private uint spectatorMinPlayerID = 2023; private List spectatorList = new List(); public int TeamCount => options.TeamCount; private MessageWriter? mwr = null; + private object spetatorJoinLock = new(); + protected object spectatorLock = new object(); + protected bool isSpectatorJoin = false; + protected bool IsSpectatorJoin + { + get + { + lock (spectatorLock) + return isSpectatorJoin; + } + + set + { + lock (spectatorLock) + isSpectatorJoin = value; + } + } private bool IsGaming { get; set; } private int[] finalScore; public int[] FinalScore @@ -38,18 +57,20 @@ namespace Server public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter responseStream, ServerCallContext context) { - if (request.PlayerId >= spectatorMinPlayerID) + if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) { // 观战模式 - uint tp = (uint)request.PlayerId; - if (!spectatorList.Contains(tp)) + lock (spetatorJoinLock) // 具体原因见另一个上锁的地方 { - spectatorList.Add(tp); - Console.WriteLine("A new spectator comes to watch this game."); - var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)); - lock (semaDictLock) + if (semaDict.TryAdd(request.PlayerId, (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)))) + { + Console.WriteLine("A new spectator comes to watch this game."); + IsSpectatorJoin = true; + } + else { - semaDict.Add(request.PlayerId, temp); + Console.WriteLine($"Duplicated Spectator ID {request.PlayerId}"); + return; } } do @@ -63,15 +84,32 @@ namespace Server //Console.WriteLine("Send!"); } } + catch (InvalidOperationException) + { + if (semaDict.TryRemove(request.PlayerId, out var semas)) + { + try + { + semas.Item1.Release(); + semas.Item2.Release(); + } + catch { } + Console.WriteLine($"The spectator {request.PlayerId} exited"); + } + } catch (Exception) { - //Console.WriteLine(ex); + // Console.WriteLine(ex); } finally { - semaDict[request.PlayerId].Item2.Release(); + try + { + semaDict[request.PlayerId].Item2.Release(); + } + catch { } } - } while (IsGaming == true); + } while (IsGaming); return; } } @@ -79,6 +117,16 @@ namespace Server public void ReportGame(MessageToClient? msg) { currentGameInfo = msg; + if (currentGameInfo != null && currentGameInfo.GameState == GameState.GameStart) + { + currentMapMsg = currentGameInfo.ObjMessage[0]; + } + + if (currentGameInfo != null && IsSpectatorJoin) + { + currentGameInfo.ObjMessage.Add(currentMapMsg); + IsSpectatorJoin = false; + } foreach (var kvp in semaDict) {