You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

GameServer.cs 25 kB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. using Grpc.Core;
  2. using Protobuf;
  3. using System.Threading;
  4. using Timothy.FrameRateTask;
  5. using System;
  6. using System.Net.Http.Headers;
  7. using Gaming;
  8. using GameClass.GameObj;
  9. using Preparation.Utility;
  10. using Playback;
  11. using Newtonsoft.Json;
  12. using Newtonsoft.Json.Linq;
  13. using Preparation.Interface;
  14. namespace Server
  15. {
  16. public class GameServer : AvailableService.AvailableServiceBase
  17. {
  18. private Dictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new();
  19. protected readonly ArgumentOptions options;
  20. private HttpSender? httpSender;
  21. private object gameLock = new();
  22. private MessageToClient currentGameInfo = new();
  23. private MessageOfObj currentMapMsg = new();
  24. private object newsLock = new();
  25. private List<MessageOfNews> currentNews = new();
  26. private SemaphoreSlim endGameSem = new(0);
  27. protected readonly Game game;
  28. private uint spectatorMinPlayerID = 2023;
  29. private List<uint> spectatorList = new List<uint>();
  30. public int playerNum;
  31. public int TeamCount => options.TeamCount;
  32. protected long[] communicationToGameID; // 通信用的ID映射到游戏内的ID,通信中0-3为Student,4为Tricker
  33. private readonly object messageToAllClientsLock = new();
  34. public static readonly long SendMessageToClientIntervalInMilliseconds = 50;
  35. private MessageWriter? mwr = null;
  36. public void StartGame()
  37. {
  38. if (game.GameMap.Timer.IsGaming) return;
  39. /*foreach (var id in communicationToGameID)
  40. {
  41. if (id == GameObj.invalidID) return; //如果有未初始化的玩家,不开始游戏
  42. }*/ //测试时人数不够
  43. Console.WriteLine("Game starts!");
  44. game.StartGame((int)options.GameTimeInSecond * 1000);
  45. Thread.Sleep(1);
  46. new Thread(() =>
  47. {
  48. bool flag = true;
  49. new FrameRateTaskExecutor<int>
  50. (
  51. () => game.GameMap.Timer.IsGaming,
  52. () =>
  53. {
  54. if (flag == true)
  55. {
  56. game.AllPlayerUsePassiveSkill();
  57. ReportGame(GameState.GameStart);
  58. game.AllActiveSkillDisabledTemporarily();
  59. flag = false;
  60. }
  61. else ReportGame(GameState.GameRunning);
  62. },
  63. SendMessageToClientIntervalInMilliseconds,
  64. () =>
  65. {
  66. ReportGame(GameState.GameEnd); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住
  67. OnGameEnd();
  68. return 0;
  69. }
  70. ).Start();
  71. })
  72. { IsBackground = true }.Start();
  73. }
  74. public void WaitForEnd()
  75. {
  76. this.endGameSem.Wait();
  77. mwr?.Dispose();
  78. }
  79. private void SaveGameResult(string path)
  80. {
  81. Dictionary<string, int> result = new Dictionary<string, int>();
  82. for (int i = 0; i < TeamCount; i++)
  83. {
  84. result.Add("Team" + i.ToString(), GetTeamScore(i)); //Team待修改
  85. }
  86. JsonSerializer serializer = new JsonSerializer();
  87. using (StreamWriter sw = new StreamWriter(path))
  88. {
  89. using (JsonWriter writer = new JsonTextWriter(sw))
  90. {
  91. serializer.Serialize(writer, result);
  92. }
  93. }
  94. }
  95. protected virtual void SendGameResult() // 天梯的 Server 给网站发消息记录比赛结果
  96. {
  97. var scores = new JObject[options.TeamCount];
  98. for (ushort i = 0; i < options.TeamCount; ++i)
  99. {
  100. scores[i] = new JObject { ["team_id"] = i.ToString(), ["score"] = GetTeamScore(i) };
  101. } // Team待修改
  102. httpSender?.SendHttpRequest
  103. (
  104. new JObject
  105. {
  106. ["result"] = new JArray(scores)
  107. }
  108. );
  109. }
  110. private void OnGameEnd()
  111. {
  112. game.ClearAllLists();
  113. mwr?.Flush();
  114. if (options.ResultFileName != DefaultArgumentOptions.FileName)
  115. SaveGameResult(options.ResultFileName + ".json");
  116. SendGameResult();
  117. this.endGameSem.Release();
  118. }
  119. public void ReportGame(GameState gameState, bool requiredGaming = true)
  120. {
  121. var gameObjList = game.GetGameObj();
  122. currentGameInfo = new();
  123. lock (messageToAllClientsLock)
  124. {
  125. switch (gameState)
  126. {
  127. case GameState.GameRunning:
  128. case GameState.GameEnd:
  129. case GameState.GameStart:
  130. currentGameInfo.ObjMessage.Add(currentMapMsg);
  131. foreach (GameObj gameObj in gameObjList)
  132. {
  133. MessageOfObj? msg = CopyInfo.Auto(gameObj);
  134. if (msg != null) currentGameInfo.ObjMessage.Add(CopyInfo.Auto(gameObj));
  135. }
  136. lock (newsLock)
  137. {
  138. foreach (var news in currentNews)
  139. {
  140. MessageOfObj? msg = CopyInfo.Auto(news);
  141. if (msg != null) currentGameInfo.ObjMessage.Add(CopyInfo.Auto(news));
  142. }
  143. currentNews.Clear();
  144. }
  145. currentGameInfo.GameState = gameState;
  146. currentGameInfo.AllMessage = GetMessageOfAll();
  147. mwr?.WriteOne(currentGameInfo);
  148. break;
  149. default:
  150. break;
  151. }
  152. }
  153. foreach (var kvp in semaDict)
  154. {
  155. kvp.Value.Item1.Release();
  156. }
  157. foreach (var kvp in semaDict)
  158. {
  159. kvp.Value.Item2.Wait();
  160. }
  161. }
  162. public int GetTeamScore(long teamID)
  163. {
  164. return game.GetTeamScore(teamID);
  165. }
  166. private int PlayerIDToTeamID(long playerID)
  167. {
  168. if (0 <= playerID && playerID < options.StudentCount) return 0;
  169. if (options.MaxStudentCount <= playerID && playerID < options.MaxStudentCount + options.TrickerCount) return 1;
  170. return -1;
  171. }
  172. private int PlayerTypeToTeamID(Protobuf.PlayerType playerType)
  173. {
  174. if (playerType == PlayerType.StudentPlayer) return 0;
  175. if (playerType == PlayerType.TrickerPlayer) return 1;
  176. return -1;
  177. }
  178. private uint GetBirthPointIdx(long playerID) // 获取出生点位置
  179. {
  180. return (uint)playerID + 1; // ID从0-4,出生点从1-5
  181. }
  182. private bool ValidPlayerID(long playerID)
  183. {
  184. if ((0 <= playerID && playerID < options.StudentCount) || (options.MaxStudentCount <= playerID && playerID < options.MaxStudentCount + options.TrickerCount))
  185. return true;
  186. return false;
  187. }
  188. private MessageOfAll GetMessageOfAll()
  189. {
  190. MessageOfAll msg = new MessageOfAll();
  191. //msg.GameTime
  192. msg.SubjectFinished = (int)game.GameMap.NumOfRepairedGenerators;
  193. //msg.StudentGraduated
  194. //msg.StudentQuited
  195. msg.StudentScore = 0;
  196. msg.TrickerScore = 0;
  197. game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock();
  198. try
  199. {
  200. foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character])
  201. {
  202. if (!character.IsGhost()) msg.StudentScore += character.Score;
  203. else msg.TrickerScore += character.Score;
  204. }
  205. }
  206. finally
  207. {
  208. game.GameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
  209. }
  210. //msg.GateOpened
  211. //msg.HiddenGateRefreshed
  212. //msg.HiddenGateOpened
  213. return msg;
  214. }
  215. private Protobuf.PlaceType IntToPlaceType(uint n)
  216. {
  217. switch (n)
  218. {
  219. case 0:
  220. case 1:
  221. case 2:
  222. case 3:
  223. case 4:
  224. case 5:
  225. return Protobuf.PlaceType.Land;
  226. case 6: return Protobuf.PlaceType.Wall;
  227. case 7: return Protobuf.PlaceType.Grass;
  228. case 8: return Protobuf.PlaceType.Classroom;
  229. case 9: return Protobuf.PlaceType.Gate;
  230. case 10: return Protobuf.PlaceType.HiddenGate;
  231. case 11: return Protobuf.PlaceType.Window;
  232. case 12: return Protobuf.PlaceType.Door3;
  233. case 13: return Protobuf.PlaceType.Door5;
  234. case 14: return Protobuf.PlaceType.Door6;
  235. case 15: return Protobuf.PlaceType.Chest;
  236. default: return Protobuf.PlaceType.NullPlaceType;
  237. }
  238. }
  239. private MessageOfObj MapMsg(uint[,] map)
  240. {
  241. MessageOfObj msgOfMap = new();
  242. msgOfMap.MapMessage = new();
  243. for (int i = 0; i < GameData.rows; i++)
  244. {
  245. msgOfMap.MapMessage.Row.Add(new MessageOfMap.Types.Row());
  246. for (int j = 0; j < GameData.cols; j++)
  247. {
  248. msgOfMap.MapMessage.Row[i].Col.Add(IntToPlaceType(map[i, j]));
  249. }
  250. }
  251. return msgOfMap;
  252. }
  253. public override Task<BoolRes> TryConnection(IDMsg request, ServerCallContext context)
  254. {
  255. #if DEBUG
  256. Console.WriteLine($"TryConnection ID: {request.PlayerId}");
  257. #endif
  258. var onConnection = new BoolRes();
  259. lock (gameLock)
  260. {
  261. if (0 <= request.PlayerId && request.PlayerId < playerNum) // 注意修改
  262. {
  263. onConnection.ActSuccess = true;
  264. Console.WriteLine(onConnection.ActSuccess);
  265. return Task.FromResult(onConnection);
  266. }
  267. }
  268. onConnection.ActSuccess = false;
  269. return Task.FromResult(onConnection);
  270. }
  271. protected readonly object addPlayerLock = new();
  272. public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter<MessageToClient> responseStream, ServerCallContext context)
  273. {
  274. Console.WriteLine($"AddPlayer: {request.PlayerId}");
  275. if (request.PlayerId >= spectatorMinPlayerID)
  276. {
  277. // 观战模式
  278. uint tp = (uint)request.PlayerId;
  279. if (!spectatorList.Contains(tp))
  280. {
  281. spectatorList.Add(tp);
  282. Console.WriteLine("A new spectator comes to watch this game.");
  283. }
  284. return;
  285. }
  286. if (game.GameMap.Timer.IsGaming)
  287. return;
  288. if (!ValidPlayerID(request.PlayerId)) //玩家id是否正确
  289. return;
  290. if (communicationToGameID[request.PlayerId] != GameObj.invalidID) //是否已经添加了该玩家
  291. return;
  292. Preparation.Utility.CharacterType characterType = Preparation.Utility.CharacterType.Null;
  293. if (request.PlayerType == PlayerType.StudentPlayer)
  294. characterType = CopyInfo.ToStudentType(request.StudentType);
  295. else if (request.PlayerType == PlayerType.TrickerPlayer)
  296. characterType = CopyInfo.ToTrickerType(request.TrickerType);
  297. lock (addPlayerLock)
  298. {
  299. Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), (int)request.PlayerId, characterType);
  300. long newPlayerID = game.AddPlayer(playerInitInfo);
  301. if (newPlayerID == GameObj.invalidID)
  302. return;
  303. communicationToGameID[request.PlayerId] = newPlayerID;
  304. // 内容待修改
  305. var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1));
  306. bool start = false;
  307. Console.WriteLine($"Id: {request.PlayerId} joins.");
  308. lock (semaDict)
  309. {
  310. semaDict.Add(request.PlayerId, temp);
  311. start = semaDict.Count == playerNum;
  312. }
  313. if (start) StartGame();
  314. }
  315. do
  316. {
  317. semaDict[request.PlayerId].Item1.Wait();
  318. if (currentGameInfo != null)
  319. {
  320. await responseStream.WriteAsync(currentGameInfo);
  321. //Console.WriteLine("Send!");
  322. }
  323. semaDict[request.PlayerId].Item2.Release();
  324. } while (game.GameMap.Timer.IsGaming);
  325. }
  326. public override Task<BoolRes> Attack(AttackMsg request, ServerCallContext context)
  327. {
  328. #if DEBUG
  329. Console.WriteLine($"Attack ID: {request.PlayerId}");
  330. #endif
  331. var gameID = communicationToGameID[request.PlayerId];
  332. game.Attack(gameID, request.Angle);
  333. BoolRes boolRes = new();
  334. boolRes.ActSuccess = true;
  335. return Task.FromResult(boolRes);
  336. }
  337. public override Task<MoveRes> Move(MoveMsg request, ServerCallContext context)
  338. {
  339. #if DEBUG
  340. Console.WriteLine($"Move ID: {request.PlayerId}, TimeInMilliseconds: {request.TimeInMilliseconds}");
  341. #endif
  342. var gameID = communicationToGameID[request.PlayerId];
  343. MoveRes moveRes = new();
  344. game.MovePlayer(gameID, (int)request.TimeInMilliseconds, request.Angle);
  345. // 之后game.MovePlayer可能改为bool类
  346. moveRes.ActSuccess = true;
  347. if (!game.GameMap.Timer.IsGaming) moveRes.ActSuccess = false;
  348. return Task.FromResult(moveRes);
  349. }
  350. public override Task<BoolRes> SendMessage(SendMsg request, ServerCallContext context)
  351. {
  352. var boolRes = new BoolRes();
  353. if (!ValidPlayerID(request.PlayerId) || !ValidPlayerID(request.ToPlayerId)
  354. || PlayerIDToTeamID(request.PlayerId) != PlayerIDToTeamID(request.ToPlayerId) || request.PlayerId == request.ToPlayerId)
  355. {
  356. boolRes.ActSuccess = false;
  357. return Task.FromResult(boolRes);
  358. }
  359. if (request.Message.Length > 256)
  360. {
  361. #if DEBUG
  362. Console.WriteLine("Message string is too long!");
  363. #endif
  364. boolRes.ActSuccess = false;
  365. return Task.FromResult(boolRes);
  366. }
  367. else
  368. {
  369. MessageOfNews news = new();
  370. news.News = request.Message;
  371. news.FromId = request.PlayerId;
  372. news.ToId = request.ToPlayerId;
  373. lock (newsLock)
  374. {
  375. currentNews.Add(news);
  376. }
  377. #if DEBUG
  378. Console.WriteLine(news.News);
  379. #endif
  380. }
  381. boolRes.ActSuccess = true;
  382. return Task.FromResult(boolRes);
  383. }
  384. public override Task<BoolRes> PickProp(PropMsg request, ServerCallContext context)
  385. {
  386. #if DEBUG
  387. Console.WriteLine($"PickProp ID: {request.PlayerId}");
  388. #endif
  389. BoolRes boolRes = new();
  390. var gameID = communicationToGameID[request.PlayerId];
  391. boolRes.ActSuccess = game.PickProp(gameID, CopyInfo.ToPropType(request.PropType));
  392. return Task.FromResult(boolRes);
  393. }
  394. public override Task<BoolRes> UseProp(PropMsg request, ServerCallContext context)
  395. {
  396. #if DEBUG
  397. Console.WriteLine($"UseProp ID: {request.PlayerId}");
  398. #endif
  399. BoolRes boolRes = new();
  400. var gameID = communicationToGameID[request.PlayerId];
  401. game.UseProp(gameID, CopyInfo.ToPropType(request.PropType));
  402. boolRes.ActSuccess = true;
  403. return Task.FromResult(boolRes);
  404. }
  405. public override Task<BoolRes> ThrowProp(PropMsg request, ServerCallContext context)
  406. {
  407. #if DEBUG
  408. Console.WriteLine($"ThrowProp ID: {request.PlayerId}");
  409. #endif
  410. BoolRes boolRes = new();
  411. var gameID = communicationToGameID[request.PlayerId];
  412. game.ThrowProp(gameID, CopyInfo.ToPropType(request.PropType));
  413. boolRes.ActSuccess = true;
  414. return Task.FromResult(boolRes);
  415. }
  416. public override Task<BoolRes> UseSkill(SkillMsg request, ServerCallContext context)
  417. {
  418. #if DEBUG
  419. Console.WriteLine($"UseSkill ID: {request.PlayerId}");
  420. #endif
  421. BoolRes boolRes = new();
  422. var gameID = communicationToGameID[request.PlayerId];
  423. boolRes.ActSuccess = game.UseActiveSkill(gameID, request.SkillId);
  424. return Task.FromResult(boolRes);
  425. }
  426. public override Task<BoolRes> Graduate(IDMsg request, ServerCallContext context)
  427. {
  428. #if DEBUG
  429. Console.WriteLine($"Graduate ID: {request.PlayerId}");
  430. #endif
  431. BoolRes boolRes = new();
  432. var gameID = communicationToGameID[request.PlayerId];
  433. boolRes.ActSuccess = game.Escape(gameID);
  434. return Task.FromResult(boolRes);
  435. }
  436. public override Task<BoolRes> StartRescueMate(TreatAndRescueMsg request, ServerCallContext context)
  437. {
  438. #if DEBUG
  439. Console.WriteLine($"StartRescueMate ID: {request.PlayerId}");
  440. #endif
  441. BoolRes boolRes = new();
  442. var gameID = communicationToGameID[request.PlayerId];
  443. var toGameID = communicationToGameID[request.ToPlayerId];
  444. boolRes.ActSuccess = game.Rescue(gameID, toGameID);
  445. return Task.FromResult(boolRes);
  446. }
  447. public override Task<BoolRes> StartTreatMate(TreatAndRescueMsg request, ServerCallContext context)
  448. {
  449. #if DEBUG
  450. Console.WriteLine($"StartTreatMate ID: {request.PlayerId}");
  451. #endif
  452. BoolRes boolRes = new();
  453. var gameID = communicationToGameID[request.PlayerId];
  454. var toGameID = communicationToGameID[request.ToPlayerId];
  455. boolRes.ActSuccess = game.Treat(gameID, toGameID);
  456. return Task.FromResult(boolRes);
  457. }
  458. public override Task<BoolRes> StartLearning(IDMsg request, ServerCallContext context)
  459. {
  460. #if DEBUG
  461. Console.WriteLine($"StartLearning ID: {request.PlayerId}");
  462. #endif
  463. BoolRes boolRes = new();
  464. var gameID = communicationToGameID[request.PlayerId];
  465. boolRes.ActSuccess = game.Fix(gameID);
  466. return Task.FromResult(boolRes);
  467. }
  468. public override Task<BoolRes> StartOpenChest(IDMsg request, ServerCallContext context)
  469. {
  470. #if DEBUG
  471. Console.WriteLine($"StartOpenChest ID: {request.PlayerId}");
  472. #endif
  473. BoolRes boolRes = new();
  474. var gameID = communicationToGameID[request.PlayerId];
  475. boolRes.ActSuccess = game.OpenChest(gameID);
  476. return Task.FromResult(boolRes);
  477. }
  478. public override Task<BoolRes> StartOpenGate(IDMsg request, ServerCallContext context)
  479. {
  480. #if DEBUG
  481. Console.WriteLine($"StartOpenGate ID: {request.PlayerId}");
  482. #endif
  483. BoolRes boolRes = new();
  484. var gameID = communicationToGameID[request.PlayerId];
  485. boolRes.ActSuccess = game.OpenDoorway(gameID);
  486. return Task.FromResult(boolRes);
  487. }
  488. public override Task<BoolRes> OpenDoor(IDMsg request, ServerCallContext context)
  489. {
  490. #if DEBUG
  491. Console.WriteLine($"OpenDoor ID: {request.PlayerId}");
  492. #endif
  493. BoolRes boolRes = new();
  494. var gameID = communicationToGameID[request.PlayerId];
  495. boolRes.ActSuccess = game.LockOrOpenDoor(gameID);
  496. return Task.FromResult(boolRes);
  497. }
  498. public override Task<BoolRes> CloseDoor(IDMsg request, ServerCallContext context)
  499. {
  500. #if DEBUG
  501. Console.WriteLine($"CloseDoor ID: {request.PlayerId}");
  502. #endif
  503. BoolRes boolRes = new();
  504. var gameID = communicationToGameID[request.PlayerId];
  505. boolRes.ActSuccess = game.LockOrOpenDoor(gameID);
  506. return Task.FromResult(boolRes);
  507. }
  508. public override Task<BoolRes> EndAllAction(IDMsg request, ServerCallContext context)
  509. {
  510. #if DEBUG
  511. Console.WriteLine($"EndAllAction ID: {request.PlayerId}");
  512. #endif
  513. BoolRes boolRes = new();
  514. var gameID = communicationToGameID[request.PlayerId];
  515. boolRes.ActSuccess = game.Stop(gameID);
  516. return Task.FromResult(boolRes);
  517. }
  518. public override Task<BoolRes> SkipWindow(IDMsg request, ServerCallContext context)
  519. {
  520. #if DEBUG
  521. Console.WriteLine($"SkipWindow ID: {request.PlayerId}");
  522. #endif
  523. BoolRes boolRes = new();
  524. var gameID = communicationToGameID[request.PlayerId];
  525. boolRes.ActSuccess = game.ClimbingThroughWindow(gameID);
  526. return Task.FromResult(boolRes);
  527. }
  528. public GameServer(ArgumentOptions options)
  529. {
  530. this.options = options;
  531. if (options.mapResource == DefaultArgumentOptions.MapResource)
  532. this.game = new Game(MapInfo.defaultMap, options.TeamCount);
  533. else
  534. {
  535. uint[,] map = new uint[GameData.rows, GameData.cols];
  536. try
  537. {
  538. string? line;
  539. int i = 0, j = 0;
  540. using (StreamReader sr = new StreamReader(options.mapResource))
  541. {
  542. while (!sr.EndOfStream && i < GameData.rows)
  543. {
  544. if ((line = sr.ReadLine()) != null)
  545. {
  546. string[] nums = line.Split(' ');
  547. foreach (string item in nums)
  548. {
  549. if (item.Length > 1)//以兼容原方案
  550. {
  551. map[i, j] = (uint)int.Parse(item);
  552. }
  553. else
  554. {
  555. //2022-04-22 by LHR 十六进制编码地图方案(防止地图编辑员瞎眼x
  556. map[i, j] = (uint)Preparation.Utility.MapEncoder.Hex2Dec(char.Parse(item));
  557. }
  558. j++;
  559. if (j >= GameData.cols)
  560. {
  561. j = 0;
  562. break;
  563. }
  564. }
  565. i++;
  566. }
  567. }
  568. }
  569. }
  570. catch
  571. {
  572. map = MapInfo.defaultMap;
  573. }
  574. finally { this.game = new Game(map, options.TeamCount); }
  575. }
  576. playerNum = options.StudentCount + options.TrickerCount;
  577. currentMapMsg = MapMsg(game.GameMap.ProtoGameMap);
  578. communicationToGameID = new long[options.MaxStudentCount + options.TrickerCount];
  579. //创建server时先设定待加入人物都是invalid
  580. for (int i = 0; i < communicationToGameID.GetLength(0); i++)
  581. {
  582. communicationToGameID[i] = GameObj.invalidID;
  583. }
  584. if (options.FileName != DefaultArgumentOptions.FileName)
  585. {
  586. try
  587. {
  588. mwr = new MessageWriter(options.FileName, options.TeamCount, options.StudentCount);
  589. }
  590. catch
  591. {
  592. Console.WriteLine($"Error: Cannot create the playback file: {options.FileName}!");
  593. }
  594. }
  595. if (options.Url != DefaultArgumentOptions.Url && options.Token != DefaultArgumentOptions.Token)
  596. {
  597. this.httpSender = new HttpSender(options.Url, options.Token, "PUT");
  598. }
  599. }
  600. }
  601. }