refactor(server): ♻️ make server base class to unify gameserver and playback server
tags/0.1.0
| @@ -1,22 +1,17 @@ | |||||
| using Grpc.Core; | |||||
| using Protobuf; | |||||
| using System.Threading; | |||||
| using Timothy.FrameRateTask; | |||||
| using System; | |||||
| using System.Net.Http.Headers; | |||||
| using GameClass.GameObj; | |||||
| using Gaming; | using Gaming; | ||||
| using GameClass.GameObj; | |||||
| using Preparation.Utility; | |||||
| using Playback; | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using Newtonsoft.Json.Linq; | using Newtonsoft.Json.Linq; | ||||
| using Preparation.Interface; | |||||
| using Playback; | |||||
| using Preparation.Utility; | |||||
| using Protobuf; | |||||
| using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
| using Timothy.FrameRateTask; | |||||
| namespace Server | namespace Server | ||||
| { | { | ||||
| public partial class GameServer : AvailableService.AvailableServiceBase | |||||
| partial class GameServer : ServerBase | |||||
| { | { | ||||
| private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); | private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); | ||||
| // private object semaDictLock = new(); | // private object semaDictLock = new(); | ||||
| @@ -86,7 +81,7 @@ namespace Server | |||||
| } | } | ||||
| } | } | ||||
| public void WaitForEnd() | |||||
| public override void WaitForEnd() | |||||
| { | { | ||||
| this.endGameSem.Wait(); | this.endGameSem.Wait(); | ||||
| mwr?.Dispose(); | mwr?.Dispose(); | ||||
| @@ -202,7 +197,7 @@ namespace Server | |||||
| return false; | return false; | ||||
| } | } | ||||
| public int[] GetScore() | |||||
| public override int[] GetScore() | |||||
| { | { | ||||
| int[] score = new int[2]; // 0代表Student,1代表Tricker | int[] score = new int[2]; // 0代表Student,1代表Tricker | ||||
| game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | ||||
| @@ -1,26 +1,23 @@ | |||||
| using Protobuf; | |||||
| using Playback; | |||||
| using System; | |||||
| using System.Threading; | |||||
| using Timothy.FrameRateTask; | |||||
| using Gaming; | |||||
| using Gaming; | |||||
| using Grpc.Core; | using Grpc.Core; | ||||
| using Playback; | |||||
| using Protobuf; | |||||
| using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
| using Timothy.FrameRateTask; | |||||
| namespace Server | namespace Server | ||||
| { | { | ||||
| class PlaybackServer : AvailableService.AvailableServiceBase | |||||
| class PlaybackServer : ServerBase | |||||
| { | { | ||||
| protected readonly ArgumentOptions options; | protected readonly ArgumentOptions options; | ||||
| private int[,] teamScore; | private int[,] teamScore; | ||||
| private ConcurrentDictionary<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 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 object spetatorJoinLock = new(); | private object spetatorJoinLock = new(); | ||||
| protected object spectatorLock = new object(); | protected object spectatorLock = new object(); | ||||
| protected bool isSpectatorJoin = false; | protected bool isSpectatorJoin = false; | ||||
| @@ -47,6 +44,7 @@ namespace Server | |||||
| return finalScore; | return finalScore; | ||||
| } | } | ||||
| } | } | ||||
| public override int[] GetScore() => FinalScore; | |||||
| public PlaybackServer(ArgumentOptions options) | public PlaybackServer(ArgumentOptions options) | ||||
| { | { | ||||
| this.options = options; | this.options = options; | ||||
| @@ -57,6 +55,7 @@ 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) | ||||
| { | { | ||||
| Console.WriteLine($"AddPlayer: {request.PlayerId}"); | |||||
| if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) | if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) | ||||
| { | { | ||||
| // 观战模式 | // 观战模式 | ||||
| @@ -95,6 +94,7 @@ namespace Server | |||||
| } | } | ||||
| catch { } | catch { } | ||||
| Console.WriteLine($"The spectator {request.PlayerId} exited"); | Console.WriteLine($"The spectator {request.PlayerId} exited"); | ||||
| return; | |||||
| } | } | ||||
| } | } | ||||
| catch (Exception) | catch (Exception) | ||||
| @@ -139,7 +139,7 @@ namespace Server | |||||
| } | } | ||||
| } | } | ||||
| public void WaitForGame() | |||||
| public override void WaitForEnd() | |||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| @@ -1,15 +1,16 @@ | |||||
| using Grpc.Core; | |||||
| using CommandLine; | |||||
| using Grpc.Core; | |||||
| using Protobuf; | using Protobuf; | ||||
| using System.Threading; | |||||
| using Timothy.FrameRateTask; | |||||
| using System; | |||||
| using System.Net.Http.Headers; | |||||
| using CommandLine; | |||||
| namespace Server | namespace Server | ||||
| { | { | ||||
| public class Program | public class Program | ||||
| { | { | ||||
| static ServerBase CreateServer(ArgumentOptions options) | |||||
| { | |||||
| return options.Playback ? new PlaybackServer(options) : new GameServer(options); | |||||
| } | |||||
| static int Main(string[] args) | static int Main(string[] args) | ||||
| { | { | ||||
| foreach (var arg in args) | foreach (var arg in args) | ||||
| @@ -28,61 +29,30 @@ namespace Server | |||||
| Console.WriteLine("Server begins to run: " + options.ServerPort.ToString()); | Console.WriteLine("Server begins to run: " + options.ServerPort.ToString()); | ||||
| if (options.Playback) | |||||
| try | |||||
| { | { | ||||
| try | |||||
| { | |||||
| PlaybackServer? playbackServer = new(options); | |||||
| Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) | |||||
| { | |||||
| Services = { AvailableService.BindService(playbackServer) }, | |||||
| Ports = { new ServerPort(options.ServerIP, options.ServerPort, ServerCredentials.Insecure) } | |||||
| }; | |||||
| server.Start(); | |||||
| Console.WriteLine("Server begins to listen!"); | |||||
| playbackServer.WaitForGame(); | |||||
| Console.WriteLine("Server end!"); | |||||
| server.ShutdownAsync().Wait(); | |||||
| Thread.Sleep(50); | |||||
| Console.WriteLine(""); | |||||
| Console.WriteLine("=================== Final Score ===================="); | |||||
| Console.WriteLine($"Studnet: {playbackServer.FinalScore[0]}"); | |||||
| Console.WriteLine($"Tricker: {playbackServer.FinalScore[1]}"); | |||||
| } | |||||
| catch (Exception ex) | |||||
| var server = CreateServer(options); | |||||
| Grpc.Core.Server rpcServer = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) | |||||
| { | { | ||||
| Console.WriteLine(ex.ToString()); | |||||
| } | |||||
| Services = { AvailableService.BindService(server) }, | |||||
| Ports = { new ServerPort(options.ServerIP, options.ServerPort, ServerCredentials.Insecure) } | |||||
| }; | |||||
| rpcServer.Start(); | |||||
| Console.WriteLine("Server begins to listen!"); | |||||
| server.WaitForEnd(); | |||||
| Console.WriteLine("Server end!"); | |||||
| rpcServer.ShutdownAsync().Wait(); | |||||
| Thread.Sleep(50); | |||||
| Console.WriteLine(""); | |||||
| Console.WriteLine("=================== Final Score ===================="); | |||||
| Console.WriteLine($"Studnet: {server.GetScore()[0]}"); | |||||
| Console.WriteLine($"Tricker: {server.GetScore()[1]}"); | |||||
| } | } | ||||
| else | |||||
| catch (Exception ex) | |||||
| { | { | ||||
| try | |||||
| { | |||||
| GameServer? gameServer = new(options); | |||||
| Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) | |||||
| { | |||||
| Services = { AvailableService.BindService(gameServer) }, | |||||
| Ports = { new ServerPort(options.ServerIP, options.ServerPort, ServerCredentials.Insecure) } | |||||
| }; | |||||
| server.Start(); | |||||
| Console.WriteLine("Server begins to listen!"); | |||||
| gameServer.WaitForEnd(); | |||||
| Console.WriteLine("Server end!"); | |||||
| server.ShutdownAsync().Wait(); | |||||
| Thread.Sleep(50); | |||||
| Console.WriteLine(""); | |||||
| Console.WriteLine("=================== Final Score ===================="); | |||||
| Console.WriteLine($"Studnet: {gameServer.GetScore()[0]}"); | |||||
| Console.WriteLine($"Tricker: {gameServer.GetScore()[1]}"); | |||||
| } | |||||
| catch (Exception ex) | |||||
| { | |||||
| Console.WriteLine(ex.ToString()); | |||||
| } | |||||
| Console.WriteLine(ex.ToString()); | |||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -1,19 +1,12 @@ | |||||
| using Grpc.Core; | |||||
| using Protobuf; | |||||
| using System.Threading; | |||||
| using System; | |||||
| using System.Net.Http.Headers; | |||||
| using GameClass.GameObj; | |||||
| using Gaming; | using Gaming; | ||||
| using GameClass.GameObj; | |||||
| using Grpc.Core; | |||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| using Playback; | |||||
| using Newtonsoft.Json; | |||||
| using Newtonsoft.Json.Linq; | |||||
| using Preparation.Interface; | |||||
| using Protobuf; | |||||
| namespace Server | namespace Server | ||||
| { | { | ||||
| public partial class GameServer : AvailableService.AvailableServiceBase | |||||
| partial class GameServer : ServerBase | |||||
| { | { | ||||
| private int playerCountNow = 0; | private int playerCountNow = 0; | ||||
| protected object spectatorLock = new object(); | protected object spectatorLock = new object(); | ||||
| @@ -0,0 +1,14 @@ | |||||
| using Grpc.Core; | |||||
| using Playback; | |||||
| using Protobuf; | |||||
| using System.Collections.Concurrent; | |||||
| using Timothy.FrameRateTask; | |||||
| namespace Server | |||||
| { | |||||
| abstract class ServerBase : AvailableService.AvailableServiceBase | |||||
| { | |||||
| public abstract void WaitForEnd(); | |||||
| public abstract int[] GetScore(); | |||||
| } | |||||
| } | |||||