chore: add numpy in py requirementstags/0.1.0
| @@ -3,6 +3,7 @@ | |||
| #include "structures.h" | |||
| #include <tclap/CmdLine.h> | |||
| #include <array> | |||
| #include <string_view> | |||
| #undef GetMessage | |||
| #undef SendMessage | |||
| @@ -12,6 +13,26 @@ | |||
| #pragma warning(disable : 4996) | |||
| #endif | |||
| using namespace std::literals::string_view_literals; | |||
| // Generated by http://www.network-science.de/ascii/ with font "standard" | |||
| static constexpr std::string_view welcomeString = R"welcome( | |||
| _____ _ _ _ _ _ ___ __ | |||
| |_ _| | | | | | | / \ |_ _/ /_ | |||
| | | | |_| | | | |/ _ \ | | '_ \ | |||
| | | | _ | |_| / ___ \ | | (_) | | |||
| |_| |_| |_|\___/_/ \_\___\___/ | |||
| ____ _ _ ____ _ _ _ | |||
| / ___|_ __ __ _ __| |_ _ __ _| |_ ___ / ___(_)_ __| |___| | | |||
| | | _| '__/ _` |/ _` | | | |/ _` | __/ _ \ | | _| | '__| / __| | | |||
| | |_| | | | (_| | (_| | |_| | (_| | || __/_ | |_| | | | | \__ \_| | |||
| \____|_| \__,_|\__,_|\__,_|\__,_|\__\___( ) \____|_|_| |_|___(_) | |||
| )welcome"sv; | |||
| int THUAI6Main(int argc, char** argv, CreateAIFunc AIBuilder) | |||
| { | |||
| int pID = 0; | |||
| @@ -84,6 +105,11 @@ int THUAI6Main(int argc, char** argv, CreateAIFunc AIBuilder) | |||
| playerType = THUAI6::PlayerType::StudentPlayer; | |||
| stuType = studentType[pID]; | |||
| } | |||
| #ifdef _MSC_VER | |||
| std::cout << welcomeString << std::endl; | |||
| #endif | |||
| Logic logic(playerType, pID, trickerType, stuType); | |||
| logic.Main(AIBuilder, sIP, sPort, file, print, warnOnly); | |||
| } | |||
| @@ -512,10 +512,10 @@ class Logic(ILogic): | |||
| if platform.system().lower() == "windows": | |||
| os.system( | |||
| f"mkdir {os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/logs'}") | |||
| f"mkdir \"{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}\\logs\"") | |||
| else: | |||
| os.system( | |||
| f"mkdir -p {os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/logs'}") | |||
| f"mkdir -p \"{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}/logs\"") | |||
| fileHandler = logging.FileHandler(os.path.dirname( | |||
| os.path.dirname(os.path.realpath(__file__))) + "/logs/logic" + str(self.__playerID) + "-log.txt", "w+", encoding="utf-8") | |||
| @@ -9,8 +9,28 @@ from PyAPI.AI import AI | |||
| from PyAPI.logic import Logic | |||
| from typing import List, Callable | |||
| import argparse | |||
| import platform | |||
| import PyAPI.structures as THUAI6 | |||
| def PrintWelcomeString() -> None: | |||
| # Generated by http://www.network-science.de/ascii/ with font "standard" | |||
| welcomeString = """ | |||
| _____ _ _ _ _ _ ___ __ | |||
| |_ _| | | | | | | / \ |_ _/ /_ | |||
| | | | |_| | | | |/ _ \ | | '_ \ | |||
| | | | _ | |_| / ___ \ | | (_) | | |||
| |_| |_| |_|\___/_/ \_\___\___/ | |||
| ____ _ _ ____ _ _ _ | |||
| / ___|_ __ __ _ __| |_ _ __ _| |_ ___ / ___(_)_ __| |___| | | |||
| | | _| '__/ _` |/ _` | | | |/ _` | __/ _ \ | | _| | '__| / __| | | |||
| | |_| | | | (_| | (_| | |_| | (_| | || __/_ | |_| | | | | \__ \_| | |||
| \____|_| \__,_|\__,_|\__,_|\__,_|\__\___( ) \____|_|_| |_|___(_) | |||
| """ | |||
| print(welcomeString) | |||
| def THUAI6Main(argv: List[str], AIBuilder: Callable) -> None: | |||
| pID: int = 0 | |||
| @@ -45,6 +65,10 @@ def THUAI6Main(argv: List[str], AIBuilder: Callable) -> None: | |||
| playerType = THUAI6.PlayerType.TrickerPlayer | |||
| else: | |||
| playerType = THUAI6.PlayerType.StudentPlayer | |||
| if platform.system().lower() == "windows": | |||
| PrintWelcomeString() | |||
| logic = Logic(pID, playerType) | |||
| logic.Main(AIBuilder, sIP, sPort, file, screen, warnOnly) | |||
| @@ -1,2 +1,3 @@ | |||
| grpcio==1.52.0 | |||
| grpcio-tools==1.52.0 | |||
| numpy | |||
| @@ -6,8 +6,21 @@ | |||
| <Nullable>enable</Nullable> | |||
| <UseWPF>true</UseWPF> | |||
| <UseWindowsForms>true</UseWindowsForms> | |||
| <ApplicationIcon>eesast_software_trans_enlarged.ico</ApplicationIcon> | |||
| <PackageIcon>eesast_software_trans.png</PackageIcon> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <Content Include="eesast_software_trans_enlarged.ico" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <None Include="..\..\resource\eesast_software_trans.png"> | |||
| <Pack>True</Pack> | |||
| <PackagePath>\</PackagePath> | |||
| </None> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="ICSharpCode.SharpZipLib.dll" Version="0.85.4.369" /> | |||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" /> | |||
| @@ -392,7 +392,7 @@ namespace Downloader | |||
| public class Data | |||
| { | |||
| public static string path = ""; // 标记路径记录文件THUAI6.json的路径 | |||
| public static string FilePath = ""; // 最后一级为THUAI6文件夹所在目录 | |||
| public static string FilePath = ""; // 最后一级为THUAI6文件夹所在目录 | |||
| public static string dataPath = ""; // C盘的文档文件夹 | |||
| public Data(string path) | |||
| { | |||
| @@ -401,7 +401,7 @@ namespace Downloader | |||
| Data.path = System.IO.Path.Combine(dataPath, "THUAI6.json"); | |||
| if (File.Exists(Data.path)) | |||
| { | |||
| var dict = new Dictionary<string, string>(); | |||
| Dictionary<string, string>? dict; | |||
| using (StreamReader r = new StreamReader(Data.path)) | |||
| { | |||
| string json = r.ReadToEnd(); | |||
| @@ -409,7 +409,7 @@ namespace Downloader | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json); | |||
| if (dict != null && dict.ContainsKey("installpath")) | |||
| { | |||
| FilePath = dict["installpath"].Replace('\\', '/'); | |||
| @@ -424,7 +424,7 @@ namespace Downloader | |||
| else | |||
| { | |||
| FilePath = System.IO.Path.GetDirectoryName(@path) | |||
| ?? throw new Exception("Fail to find the path of the file"); | |||
| ?? throw new Exception("Failed to get the path of the file"); | |||
| //将dat文件写入程序运行路径 | |||
| string json; | |||
| @@ -437,7 +437,7 @@ namespace Downloader | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json); | |||
| dict?.Add("installpath", path); | |||
| } | |||
| using FileStream fs2 = new FileStream(Data.path, FileMode.Create, FileAccess.ReadWrite); | |||
| @@ -461,7 +461,7 @@ namespace Downloader | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json); | |||
| if (dict != null && dict.ContainsKey("installpath")) | |||
| { | |||
| dict["installpath"] = newPath; | |||
| @@ -634,7 +634,7 @@ namespace Downloader | |||
| using (StreamReader r = new StreamReader(System.IO.Path.Combine(Data.FilePath, jsonName))) | |||
| json = r.ReadToEnd(); | |||
| json = json.Replace("\r", string.Empty).Replace("\n", string.Empty); | |||
| Dictionary<string, string> jsonDict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| var jsonDict = Utils.DeserializeJson1<Dictionary<string, string>>(json); | |||
| string updatingFolder = ""; | |||
| switch (OS) | |||
| { | |||
| @@ -815,7 +815,7 @@ namespace Downloader | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| var dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| var dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json); | |||
| if (dict == null || !dict.ContainsKey("download") || "false" == dict["download"]) | |||
| { | |||
| return false; | |||
| @@ -865,7 +865,7 @@ namespace Downloader | |||
| using (StreamReader r = new StreamReader(System.IO.Path.Combine(Data.FilePath, jsonName))) | |||
| json = r.ReadToEnd(); | |||
| json = json.Replace("\r", string.Empty).Replace("\n", string.Empty); | |||
| Dictionary<string, string> jsonDict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| // var jsonDict = Utils.DeserializeJson<Dictionary1<string, string>>(json); | |||
| newFileName.Clear(); | |||
| updateFileName.Clear(); | |||
| @@ -899,7 +899,7 @@ namespace Downloader | |||
| FileInfo fileInfo = new FileInfo(System.IO.Path.Combine(Data.FilePath, "THUAI6.tar.gz")); | |||
| fileInfo.Delete(); | |||
| string json2; | |||
| Dictionary<string, string> dict = new Dictionary<string, string>(); | |||
| Dictionary<string, string>? dict; | |||
| string existpath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json"); | |||
| using FileStream fs = new FileStream(existpath, FileMode.Open, FileAccess.ReadWrite); | |||
| using (StreamReader r = new StreamReader(fs)) | |||
| @@ -909,7 +909,7 @@ namespace Downloader | |||
| { | |||
| json2 += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json2); | |||
| dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json2); | |||
| if (dict == null || !dict.ContainsKey("download")) | |||
| { | |||
| dict?.Add("download", "true"); | |||
| @@ -1000,7 +1000,7 @@ namespace Downloader | |||
| using (StreamReader r = new StreamReader(System.IO.Path.Combine(Data.FilePath, "hash.json"))) | |||
| json = r.ReadToEnd(); | |||
| json = json.Replace("\r", string.Empty).Replace("\n", string.Empty).Replace("/", @"\\"); | |||
| Dictionary<string, string> jsonDict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| Dictionary<string, string> jsonDict = Utils.DeserializeJson1<Dictionary<string, string>>(json); | |||
| Change_all_hash(Data.FilePath, jsonDict); | |||
| OverwriteHash(jsonDict); | |||
| break; | |||
| @@ -1058,7 +1058,7 @@ namespace Downloader | |||
| } | |||
| string json2; | |||
| Dictionary<string, string> dict = new Dictionary<string, string>(); | |||
| Dictionary<string, string>? dict; | |||
| string existpath = System.IO.Path.Combine(Data.dataPath, "THUAI6.json"); | |||
| using FileStream fs = new FileStream(existpath, FileMode.Open, FileAccess.ReadWrite); | |||
| using (StreamReader r = new StreamReader(fs)) | |||
| @@ -1068,7 +1068,7 @@ namespace Downloader | |||
| { | |||
| json2 += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json2); | |||
| dict = Utils.TryDeserializeJson<Dictionary<string, string>>(json2); | |||
| if (dict == null || !dict.ContainsKey("download")) | |||
| { | |||
| dict?.Add("download", "false"); | |||
| @@ -1302,7 +1302,7 @@ namespace Downloader | |||
| using (StreamReader r = new StreamReader(System.IO.Path.Combine(dir, hashName))) | |||
| json = r.ReadToEnd(); | |||
| json = json.Replace("\r", string.Empty).Replace("\n", string.Empty); | |||
| Dictionary<string, string> jsonDict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| var jsonDict = Utils.TryDeserializeJson<Dictionary<string, string>>(json); | |||
| string md5 = ""; | |||
| List<string> awaitUpdate = new List<string>(); | |||
| if (jsonDict != null) | |||
| @@ -1351,9 +1351,9 @@ namespace Downloader | |||
| using (StreamReader r = new StreamReader(System.IO.Path.Combine(dir, "updateList.json"))) | |||
| json = r.ReadToEnd(); | |||
| json = json.Replace("\r", string.Empty).Replace("\n", string.Empty); | |||
| List<string> jsonList; | |||
| List<string>? jsonList; | |||
| if (json != null) | |||
| jsonList = Utils.DeserializeJson<List<string>>(json); | |||
| jsonList = Utils.TryDeserializeJson<List<string>>(json); | |||
| else | |||
| return false; | |||
| if (jsonList != null && jsonList.Contains("Dismiss")) | |||
| @@ -1405,7 +1405,7 @@ namespace WebConnect | |||
| throw new Exception("no token!"); | |||
| logintoken = token; | |||
| SaveToken(); | |||
| var info = Utils.DeserializeJson<Dictionary<string, string>>(await response.Content.ReadAsStringAsync()); | |||
| var info = Utils.DeserializeJson1<Dictionary<string, string>>(await response.Content.ReadAsStringAsync()); | |||
| Downloader.UserInfo._id = info["_id"]; | |||
| Downloader.UserInfo.email = info["email"]; | |||
| break; | |||
| @@ -1461,19 +1461,19 @@ namespace WebConnect | |||
| { | |||
| case System.Net.HttpStatusCode.OK: | |||
| var res = Utils.DeserializeJson<Dictionary<string, string>>(await response.Content.ReadAsStringAsync()); | |||
| string appid = "1255334966"; // 设置腾讯云账户的账户标识(APPID) | |||
| string region = "ap-beijing"; // 设置一个默认的存储桶地域 | |||
| var res = Utils.DeserializeJson1<Dictionary<string, string>>(await response.Content.ReadAsStringAsync()); | |||
| string appid = "1255334966"; // 设置腾讯云账户的账户标识(APPID) | |||
| string region = "ap-beijing"; // 设置一个默认的存储桶地域 | |||
| CosXmlConfig config = new CosXmlConfig.Builder() | |||
| .IsHttps(true) // 设置默认 HTTPS 请求 | |||
| .SetAppid(appid) // 设置腾讯云账户的账户标识 APPID | |||
| .SetRegion(region) // 设置一个默认的存储桶地域 | |||
| .SetDebugLog(true) // 显示日志 | |||
| .Build(); // 创建 CosXmlConfig 对象 | |||
| string tmpSecretId = res["TmpSecretId"]; //"临时密钥 SecretId"; | |||
| string tmpSecretKey = res["TmpSecretKey"]; //"临时密钥 SecretKey"; | |||
| string tmpToken = res["SecurityToken"]; //"临时密钥 token"; | |||
| long tmpExpiredTime = Convert.ToInt64(res["ExpiredTime"]);//临时密钥有效截止时间,精确到秒 | |||
| .IsHttps(true) // 设置默认 HTTPS 请求 | |||
| .SetAppid(appid) // 设置腾讯云账户的账户标识 APPID | |||
| .SetRegion(region) // 设置一个默认的存储桶地域 | |||
| .SetDebugLog(true) // 显示日志 | |||
| .Build(); // 创建 CosXmlConfig 对象 | |||
| string tmpSecretId = res["TmpSecretId"]; //"临时密钥 SecretId"; | |||
| string tmpSecretKey = res["TmpSecretKey"]; //"临时密钥 SecretKey"; | |||
| string tmpToken = res["SecurityToken"]; //"临时密钥 token"; | |||
| long tmpExpiredTime = Convert.ToInt64(res["ExpiredTime"]); //临时密钥有效截止时间,精确到秒 | |||
| QCloudCredentialProvider cosCredentialProvider = new DefaultSessionQCloudCredentialProvider( | |||
| tmpSecretId, tmpSecretKey, tmpExpiredTime, tmpToken | |||
| ); | |||
| @@ -1586,7 +1586,7 @@ namespace WebConnect | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.DeserializeJson1<Dictionary<string, string>>(json); | |||
| if (dict.ContainsKey("token")) | |||
| { | |||
| dict.Remove("token"); | |||
| @@ -1629,7 +1629,7 @@ namespace WebConnect | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| Dictionary<string, string> dict = new Dictionary<string, string>(); | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.DeserializeJson1<Dictionary<string, string>>(json); | |||
| if (!dict.ContainsKey(key)) | |||
| { | |||
| dict.Add(key, data); | |||
| @@ -1666,7 +1666,7 @@ namespace WebConnect | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.DeserializeJson1<Dictionary<string, string>>(json); | |||
| fs.Close(); | |||
| sr.Close(); | |||
| return dict[key]; | |||
| @@ -1693,7 +1693,7 @@ namespace WebConnect | |||
| { | |||
| json += @"{""THUAI6""" + ":" + @"""2023""}"; | |||
| } | |||
| dict = Utils.DeserializeJson<Dictionary<string, string>>(json); | |||
| dict = Utils.DeserializeJson1<Dictionary<string, string>>(json); | |||
| if (!dict.ContainsKey("token")) | |||
| { | |||
| return false; | |||
| @@ -1747,9 +1747,9 @@ namespace WebConnect | |||
| var response = await client.SendAsync(request); | |||
| response.EnsureSuccessStatusCode(); | |||
| var info = await response.Content.ReadAsStringAsync(); | |||
| var s1 = Utils.DeserializeJson<Dictionary<string, object>>(info)["data"]; | |||
| var s2 = Utils.DeserializeJson<Dictionary<string, List<object>>>(s1.ToString() ?? "")["contest_team_member"]; | |||
| var sres = Utils.DeserializeJson<Dictionary<string, string>>(s2[0].ToString() ?? "")["team_id"]; | |||
| var s1 = Utils.DeserializeJson1<Dictionary<string, object>>(info)["data"]; | |||
| var s2 = Utils.DeserializeJson1<Dictionary<string, List<object>>>(s1.ToString() ?? "")["contest_team_member"]; | |||
| var sres = Utils.DeserializeJson1<Dictionary<string, string>>(s2[0].ToString() ?? "")["team_id"]; | |||
| return sres; | |||
| } | |||
| async public Task<string> GetUserId(string learnNumber) | |||
| @@ -1777,11 +1777,18 @@ namespace WebConnect | |||
| internal static class Utils | |||
| { | |||
| public static T DeserializeJson<T>(string json) | |||
| public static T DeserializeJson1<T>(string json) | |||
| where T : notnull | |||
| { | |||
| return JsonConvert.DeserializeObject<T>(json) | |||
| ?? throw new Exception("Failed to deserialize json."); | |||
| } | |||
| public static T? TryDeserializeJson<T>(string json) | |||
| where T : notnull | |||
| { | |||
| return JsonConvert.DeserializeObject<T>(json); | |||
| } | |||
| } | |||
| } | |||
| @@ -5,8 +5,16 @@ | |||
| <TargetFramework>net6.0-windows</TargetFramework> | |||
| <Nullable>enable</Nullable> | |||
| <UseWPF>true</UseWPF> | |||
| <PackageIcon>eesast_software_trans.png</PackageIcon> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <None Include="..\..\resource\eesast_software_trans.png"> | |||
| <Pack>True</Pack> | |||
| <PackagePath>\</PackagePath> | |||
| </None> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> | |||
| <PackageReference Include="Tencent.QCloud.Cos.Sdk" Version="5.4.34"> | |||
| @@ -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 GameClass.GameObj; | |||
| using Preparation.Utility; | |||
| using Playback; | |||
| using Newtonsoft.Json; | |||
| using Newtonsoft.Json.Linq; | |||
| using Preparation.Interface; | |||
| using Playback; | |||
| using Preparation.Utility; | |||
| using Protobuf; | |||
| using System.Collections.Concurrent; | |||
| using Timothy.FrameRateTask; | |||
| namespace Server | |||
| { | |||
| public partial class GameServer : AvailableService.AvailableServiceBase | |||
| partial class GameServer : ServerBase | |||
| { | |||
| private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); | |||
| // private object semaDictLock = new(); | |||
| @@ -86,7 +81,7 @@ namespace Server | |||
| } | |||
| } | |||
| public void WaitForEnd() | |||
| public override void WaitForEnd() | |||
| { | |||
| this.endGameSem.Wait(); | |||
| mwr?.Dispose(); | |||
| @@ -202,7 +197,7 @@ namespace Server | |||
| return false; | |||
| } | |||
| public int[] GetScore() | |||
| public override int[] GetScore() | |||
| { | |||
| int[] score = new int[2]; // 0代表Student,1代表Tricker | |||
| 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 Playback; | |||
| using Protobuf; | |||
| using System.Collections.Concurrent; | |||
| using Timothy.FrameRateTask; | |||
| namespace Server | |||
| { | |||
| class PlaybackServer : AvailableService.AvailableServiceBase | |||
| class PlaybackServer : ServerBase | |||
| { | |||
| protected readonly ArgumentOptions options; | |||
| private int[,] teamScore; | |||
| private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); | |||
| private object semaDictLock = new(); | |||
| // private object semaDictLock = new(); | |||
| private MessageToClient? currentGameInfo = new(); | |||
| private MessageOfObj currentMapMsg = new(); | |||
| private uint spectatorMinPlayerID = 2023; | |||
| private List<uint> spectatorList = new List<uint>(); | |||
| // private List<uint> spectatorList = new List<uint>(); | |||
| public int TeamCount => options.TeamCount; | |||
| private MessageWriter? mwr = null; | |||
| private object spetatorJoinLock = new(); | |||
| protected object spectatorLock = new object(); | |||
| protected bool isSpectatorJoin = false; | |||
| @@ -47,6 +44,7 @@ namespace Server | |||
| return finalScore; | |||
| } | |||
| } | |||
| public override int[] GetScore() => FinalScore; | |||
| public PlaybackServer(ArgumentOptions options) | |||
| { | |||
| this.options = options; | |||
| @@ -57,6 +55,7 @@ namespace Server | |||
| public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter<MessageToClient> responseStream, ServerCallContext context) | |||
| { | |||
| Console.WriteLine($"AddPlayer: {request.PlayerId}"); | |||
| if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) | |||
| { | |||
| // 观战模式 | |||
| @@ -95,6 +94,7 @@ namespace Server | |||
| } | |||
| catch { } | |||
| Console.WriteLine($"The spectator {request.PlayerId} exited"); | |||
| return; | |||
| } | |||
| } | |||
| catch (Exception) | |||
| @@ -139,7 +139,7 @@ namespace Server | |||
| } | |||
| } | |||
| public void WaitForGame() | |||
| public override void WaitForEnd() | |||
| { | |||
| try | |||
| { | |||
| @@ -1,15 +1,55 @@ | |||
| using Grpc.Core; | |||
| using CommandLine; | |||
| using Grpc.Core; | |||
| using Protobuf; | |||
| using System.Threading; | |||
| using Timothy.FrameRateTask; | |||
| using System; | |||
| using System.Net.Http.Headers; | |||
| using CommandLine; | |||
| namespace Server | |||
| { | |||
| public class Program | |||
| { | |||
| /// <summary> | |||
| /// Generated by http://www.network-science.de/ascii/ with font "standard" | |||
| /// </summary> | |||
| const string welcome = | |||
| @" | |||
| _____ _ _ _ _ _ ___ __ | |||
| |_ _| | | | | | | / \ |_ _/ /_ | |||
| | | | |_| | | | |/ _ \ | | '_ \ | |||
| | | | _ | |_| / ___ \ | | (_) | | |||
| |_| |_| |_|\___/_/ \_\___\___/ | |||
| ____ _ _ ____ _ _ _ | |||
| / ___|_ __ __ _ __| |_ _ __ _| |_ ___ / ___(_)_ __| |___| | | |||
| | | _| '__/ _` |/ _` | | | |/ _` | __/ _ \ | | _| | '__| / __| | | |||
| | |_| | | | (_| | (_| | |_| | (_| | || __/_ | |_| | | | | \__ \_| | |||
| \____|_| \__,_|\__,_|\__,_|\__,_|\__\___( ) \____|_|_| |_|___(_) | |||
| "; | |||
| // 特别说明:在 .NET 7 及以上,C# 支持新的多行字符串,允许多行前面缩进,因此可以不必再定格写字符串, | |||
| // 即升级 .NET 版本后可以改为如下的: | |||
| // const string welcome = """ | |||
| // | |||
| // _____ _ _ _ _ _ ___ __ | |||
| // |_ _| | | | | | | / \ |_ _/ /_ | |||
| // | | | |_| | | | |/ _ \ | | '_ \ | |||
| // | | | _ | |_| / ___ \ | | (_) | | |||
| // |_| |_| |_|\___/_/ \_\___\___/ | |||
| // | |||
| // ____ _ _ ____ _ _ _ | |||
| // / ___|_ __ __ _ __| |_ _ __ _| |_ ___ / ___(_)_ __| |___| | | |||
| // | | _| '__/ _` |/ _` | | | |/ _` | __/ _ \ | | _| | '__| / __| | | |||
| // | |_| | | | (_| | (_| | |_| | (_| | || __/_ | |_| | | | | \__ \_| | |||
| // \____|_| \__,_|\__,_|\__,_|\__,_|\__\___( ) \____|_|_| |_|___(_) | |||
| // | |||
| // | |||
| // """; // 将以此结束符为基准开始缩进(但 Python 没有这个 feature,差评 x) | |||
| static ServerBase CreateServer(ArgumentOptions options) | |||
| { | |||
| return options.Playback ? new PlaybackServer(options) : new GameServer(options); | |||
| } | |||
| static int Main(string[] args) | |||
| { | |||
| foreach (var arg in args) | |||
| @@ -26,63 +66,36 @@ namespace Server | |||
| return 1; | |||
| } | |||
| if (options.StartLockFile == DefaultArgumentOptions.FileName) | |||
| { | |||
| Console.WriteLine(welcome); | |||
| } | |||
| Console.WriteLine("Server begins to run: " + options.ServerPort.ToString()); | |||
| if (options.Playback) | |||
| try | |||
| { | |||
| try | |||
| var server = CreateServer(options); | |||
| Grpc.Core.Server rpcServer = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) | |||
| { | |||
| 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(); | |||
| Services = { AvailableService.BindService(server) }, | |||
| Ports = { new ServerPort(options.ServerIP, options.ServerPort, ServerCredentials.Insecure) } | |||
| }; | |||
| rpcServer.Start(); | |||
| Console.WriteLine("Server begins to listen!"); | |||
| playbackServer.WaitForGame(); | |||
| Console.WriteLine("Server end!"); | |||
| server.ShutdownAsync().Wait(); | |||
| 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: {playbackServer.FinalScore[0]}"); | |||
| Console.WriteLine($"Tricker: {playbackServer.FinalScore[1]}"); | |||
| } | |||
| catch (Exception ex) | |||
| { | |||
| Console.WriteLine(ex.ToString()); | |||
| } | |||
| 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; | |||
| } | |||
| @@ -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 GameClass.GameObj; | |||
| using Grpc.Core; | |||
| using Preparation.Utility; | |||
| using Playback; | |||
| using Newtonsoft.Json; | |||
| using Newtonsoft.Json.Linq; | |||
| using Preparation.Interface; | |||
| using Protobuf; | |||
| namespace Server | |||
| { | |||
| public partial class GameServer : AvailableService.AvailableServiceBase | |||
| partial class GameServer : ServerBase | |||
| { | |||
| private int playerCountNow = 0; | |||
| 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(); | |||
| } | |||
| } | |||