|
|
@@ -5,6 +5,7 @@ using System.Threading; |
|
|
using Timothy.FrameRateTask; |
|
|
using Timothy.FrameRateTask; |
|
|
using Gaming; |
|
|
using Gaming; |
|
|
using Grpc.Core; |
|
|
using Grpc.Core; |
|
|
|
|
|
using System.Collections.Concurrent; |
|
|
|
|
|
|
|
|
namespace Server |
|
|
namespace Server |
|
|
{ |
|
|
{ |
|
|
@@ -12,13 +13,31 @@ namespace Server |
|
|
{ |
|
|
{ |
|
|
protected readonly ArgumentOptions options; |
|
|
protected readonly ArgumentOptions options; |
|
|
private int[,] teamScore; |
|
|
private int[,] teamScore; |
|
|
private Dictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); |
|
|
|
|
|
|
|
|
private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); |
|
|
private object semaDictLock = new(); |
|
|
private object semaDictLock = new(); |
|
|
private MessageToClient? currentGameInfo = new(); |
|
|
private MessageToClient? currentGameInfo = new(); |
|
|
|
|
|
private MessageOfObj currentMapMsg = new(); |
|
|
private uint spectatorMinPlayerID = 2023; |
|
|
private uint spectatorMinPlayerID = 2023; |
|
|
private List<uint> spectatorList = new List<uint>(); |
|
|
private List<uint> spectatorList = new List<uint>(); |
|
|
public int TeamCount => options.TeamCount; |
|
|
public int TeamCount => options.TeamCount; |
|
|
private MessageWriter? mwr = null; |
|
|
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 bool IsGaming { get; set; } |
|
|
private int[] finalScore; |
|
|
private int[] finalScore; |
|
|
public int[] FinalScore |
|
|
public int[] FinalScore |
|
|
@@ -38,18 +57,20 @@ namespace Server |
|
|
|
|
|
|
|
|
public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter<MessageToClient> responseStream, ServerCallContext context) |
|
|
public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter<MessageToClient> 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 |
|
|
do |
|
|
@@ -63,15 +84,32 @@ namespace Server |
|
|
//Console.WriteLine("Send!"); |
|
|
//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) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
|
//Console.WriteLine(ex); |
|
|
|
|
|
|
|
|
// Console.WriteLine(ex); |
|
|
} |
|
|
} |
|
|
finally |
|
|
finally |
|
|
{ |
|
|
{ |
|
|
semaDict[request.PlayerId].Item2.Release(); |
|
|
|
|
|
|
|
|
try |
|
|
|
|
|
{ |
|
|
|
|
|
semaDict[request.PlayerId].Item2.Release(); |
|
|
|
|
|
} |
|
|
|
|
|
catch { } |
|
|
} |
|
|
} |
|
|
} while (IsGaming == true); |
|
|
|
|
|
|
|
|
} while (IsGaming); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@@ -79,6 +117,16 @@ namespace Server |
|
|
public void ReportGame(MessageToClient? msg) |
|
|
public void ReportGame(MessageToClient? msg) |
|
|
{ |
|
|
{ |
|
|
currentGameInfo = 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) |
|
|
foreach (var kvp in semaDict) |
|
|
{ |
|
|
{ |
|
|
|