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.

logic.cpp 36 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. #include "logic.h"
  2. #include "structures.h"
  3. #include <grpcpp/grpcpp.h>
  4. #include <spdlog/spdlog.h>
  5. #include <spdlog/sinks/basic_file_sink.h>
  6. #include <spdlog/sinks/stdout_color_sinks.h>
  7. #include <functional>
  8. #include "utils.hpp"
  9. #include "Communication.h"
  10. extern const bool asynchronous;
  11. Logic::Logic(THUAI6::PlayerType type, int64_t ID, THUAI6::TrickerType tricker, THUAI6::StudentType student) :
  12. playerType(type),
  13. playerID(ID),
  14. trickerType(tricker),
  15. studentType(student)
  16. {
  17. currentState = &state[0];
  18. bufferState = &state[1];
  19. }
  20. std::vector<std::shared_ptr<const THUAI6::Tricker>> Logic::GetTrickers() const
  21. {
  22. std::lock_guard<std::mutex> lock(mtxState);
  23. std::vector<std::shared_ptr<const THUAI6::Tricker>> temp;
  24. temp.assign(currentState->trickers.begin(), currentState->trickers.end());
  25. logger->debug("Called GetTrickers");
  26. return temp;
  27. }
  28. std::vector<std::shared_ptr<const THUAI6::Student>> Logic::GetStudents() const
  29. {
  30. std::unique_lock<std::mutex> lock(mtxState);
  31. std::vector<std::shared_ptr<const THUAI6::Student>> temp;
  32. temp.assign(currentState->students.begin(), currentState->students.end());
  33. logger->debug("Called GetStudents");
  34. return temp;
  35. }
  36. std::vector<std::shared_ptr<const THUAI6::Prop>> Logic::GetProps() const
  37. {
  38. std::unique_lock<std::mutex> lock(mtxState);
  39. std::vector<std::shared_ptr<const THUAI6::Prop>> temp;
  40. temp.assign(currentState->props.begin(), currentState->props.end());
  41. logger->debug("Called GetProps");
  42. return temp;
  43. }
  44. std::shared_ptr<const THUAI6::Student> Logic::StudentGetSelfInfo() const
  45. {
  46. std::unique_lock<std::mutex> lock(mtxState);
  47. logger->debug("Called StudentGetSelfInfo");
  48. return currentState->studentSelf;
  49. }
  50. std::shared_ptr<const THUAI6::Tricker> Logic::TrickerGetSelfInfo() const
  51. {
  52. std::unique_lock<std::mutex> lock(mtxState);
  53. logger->debug("Called TrickerGetSelfInfo");
  54. return currentState->trickerSelf;
  55. }
  56. std::vector<std::vector<THUAI6::PlaceType>> Logic::GetFullMap() const
  57. {
  58. std::unique_lock<std::mutex> lock(mtxState);
  59. logger->debug("Called GetFullMap");
  60. return currentState->gameMap;
  61. }
  62. THUAI6::PlaceType Logic::GetPlaceType(int32_t cellX, int32_t cellY) const
  63. {
  64. std::unique_lock<std::mutex> lock(mtxState);
  65. logger->debug("Called GetPlaceType");
  66. return currentState->gameMap[cellX][cellY];
  67. }
  68. bool Logic::IsDoorOpen(int32_t cellX, int32_t cellY) const
  69. {
  70. std::unique_lock<std::mutex> lock(mtxState);
  71. logger->debug("Called IsDoorOpen");
  72. auto pos = std::make_pair(cellX, cellY);
  73. if (currentState->mapInfo->doorState.count(pos) == 0)
  74. {
  75. logger->warn("Door not found");
  76. return false;
  77. }
  78. else
  79. return currentState->mapInfo->doorState[pos];
  80. }
  81. int32_t Logic::GetDoorProgress(int32_t cellX, int32_t cellY) const
  82. {
  83. std::unique_lock<std::mutex> lock(mtxState);
  84. logger->debug("Called GetDoorProgress");
  85. auto pos = std::make_pair(cellX, cellY);
  86. if (currentState->mapInfo->doorProgress.count(pos) == 0)
  87. {
  88. logger->warn("Door not found");
  89. return -1;
  90. }
  91. else
  92. return currentState->mapInfo->doorProgress[pos];
  93. }
  94. int32_t Logic::GetClassroomProgress(int32_t cellX, int32_t cellY) const
  95. {
  96. std::unique_lock<std::mutex> lock(mtxState);
  97. logger->debug("Called GetClassroomProgress");
  98. auto pos = std::make_pair(cellX, cellY);
  99. if (currentState->mapInfo->classRoomState.count(pos) == 0)
  100. {
  101. logger->warn("Classroom not found");
  102. return -1;
  103. }
  104. else
  105. return currentState->mapInfo->classRoomState[pos];
  106. }
  107. int32_t Logic::GetChestProgress(int32_t cellX, int32_t cellY) const
  108. {
  109. std::unique_lock<std::mutex> lock(mtxState);
  110. logger->debug("Called GetChestProgress");
  111. auto pos = std::make_pair(cellX, cellY);
  112. if (currentState->mapInfo->chestState.count(pos) == 0)
  113. {
  114. logger->warn("Chest not found");
  115. return -1;
  116. }
  117. else
  118. return currentState->mapInfo->chestState[pos];
  119. }
  120. int32_t Logic::GetGateProgress(int32_t cellX, int32_t cellY) const
  121. {
  122. std::unique_lock<std::mutex> lock(mtxState);
  123. logger->debug("Called GetGateProgress");
  124. auto pos = std::make_pair(cellX, cellY);
  125. if (currentState->mapInfo->gateState.count(pos) == 0)
  126. {
  127. logger->warn("Gate not found");
  128. return -1;
  129. }
  130. else
  131. return currentState->mapInfo->gateState[pos];
  132. }
  133. THUAI6::HiddenGateState Logic::GetHiddenGateState(int32_t cellX, int32_t cellY) const
  134. {
  135. std::unique_lock<std::mutex> lock(mtxState);
  136. logger->debug("Called GetHiddenGateState");
  137. auto pos = std::make_pair(cellX, cellY);
  138. if (currentState->mapInfo->hiddenGateState.count(pos) == 0)
  139. {
  140. logger->warn("HiddenGate not found");
  141. return THUAI6::HiddenGateState::Null;
  142. }
  143. else
  144. return currentState->mapInfo->hiddenGateState[pos];
  145. }
  146. std::shared_ptr<const THUAI6::GameInfo> Logic::GetGameInfo() const
  147. {
  148. std::unique_lock<std::mutex> lock(mtxState);
  149. logger->debug("Called GetGameInfo");
  150. return currentState->gameInfo;
  151. }
  152. bool Logic::Move(int64_t time, double angle)
  153. {
  154. logger->debug("Called Move");
  155. return pComm->Move(time, angle, playerID);
  156. }
  157. bool Logic::PickProp(THUAI6::PropType prop)
  158. {
  159. logger->debug("Called PickProp");
  160. return pComm->PickProp(prop, playerID);
  161. }
  162. bool Logic::UseProp(THUAI6::PropType prop)
  163. {
  164. logger->debug("Called UseProp");
  165. return pComm->UseProp(prop, playerID);
  166. }
  167. bool Logic::UseSkill(int32_t skill)
  168. {
  169. logger->debug("Called UseSkill");
  170. return pComm->UseSkill(skill, playerID);
  171. }
  172. bool Logic::SendMessage(int64_t toID, std::string message)
  173. {
  174. logger->debug("Called SendMessage");
  175. return pComm->SendMessage(toID, message, playerID);
  176. }
  177. bool Logic::HaveMessage()
  178. {
  179. logger->debug("Called HaveMessage");
  180. return !messageQueue.empty();
  181. }
  182. std::optional<std::pair<int64_t, std::string>> Logic::GetMessage()
  183. {
  184. logger->debug("Called GetMessage");
  185. return messageQueue.tryPop();
  186. }
  187. bool Logic::Graduate()
  188. {
  189. logger->debug("Called Graduate");
  190. return pComm->Graduate(playerID);
  191. }
  192. bool Logic::StartLearning()
  193. {
  194. logger->debug("Called StartLearning");
  195. return pComm->StartLearning(playerID);
  196. }
  197. bool Logic::StartTreatMate()
  198. {
  199. logger->debug("Called StartTreatMate");
  200. return pComm->StartTreatMate(playerID);
  201. }
  202. bool Logic::StartRescueMate()
  203. {
  204. logger->debug("Called StartRescueMate");
  205. return pComm->StartRescueMate(playerID);
  206. }
  207. bool Logic::Attack(double angle)
  208. {
  209. logger->debug("Called Attack");
  210. return pComm->Attack(angle, playerID);
  211. }
  212. bool Logic::OpenDoor()
  213. {
  214. logger->debug("Called OpenDoor");
  215. return pComm->OpenDoor(playerID);
  216. }
  217. bool Logic::CloseDoor()
  218. {
  219. logger->debug("Called CloseDoor");
  220. return pComm->CloseDoor(playerID);
  221. }
  222. bool Logic::SkipWindow()
  223. {
  224. logger->debug("Called SkipWindow");
  225. return pComm->SkipWindow(playerID);
  226. }
  227. bool Logic::StartOpenGate()
  228. {
  229. logger->debug("Called StartOpenGate");
  230. return pComm->StartOpenGate(playerID);
  231. }
  232. bool Logic::StartOpenChest()
  233. {
  234. logger->debug("Called StartOpenChest");
  235. return pComm->StartOpenChest(playerID);
  236. }
  237. bool Logic::EndAllAction()
  238. {
  239. logger->debug("Called EndAllAction");
  240. return pComm->EndAllAction(playerID);
  241. }
  242. bool Logic::WaitThread()
  243. {
  244. Update();
  245. return true;
  246. }
  247. void Logic::ProcessMessage()
  248. {
  249. auto messageThread = [&]()
  250. {
  251. logger->info("Message thread start!");
  252. pComm->AddPlayer(playerID, playerType, studentType, trickerType);
  253. while (gameState != THUAI6::GameState::GameEnd)
  254. {
  255. auto clientMsg = pComm->GetMessage2Client(); // 在获得新消息之前阻塞
  256. logger->debug("Get message from server!");
  257. gameState = Proto2THUAI6::gameStateDict[clientMsg.game_state()];
  258. switch (gameState)
  259. {
  260. case THUAI6::GameState::GameStart:
  261. logger->info("Game Start!");
  262. // 重新读取玩家的guid,保证人类在前屠夫在后
  263. playerGUIDs.clear();
  264. for (const auto& obj : clientMsg.obj_message())
  265. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  266. playerGUIDs.push_back(obj.student_message().guid());
  267. for (const auto& obj : clientMsg.obj_message())
  268. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  269. playerGUIDs.push_back(obj.tricker_message().guid());
  270. currentState->guids = playerGUIDs;
  271. bufferState->guids = playerGUIDs;
  272. // 读取地图
  273. for (const auto& item : clientMsg.obj_message())
  274. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::MapMessage)
  275. {
  276. auto map = std::vector<std::vector<THUAI6::PlaceType>>();
  277. auto mapResult = item.map_message();
  278. for (int i = 0; i < item.map_message().row_size(); i++)
  279. {
  280. std::vector<THUAI6::PlaceType> row;
  281. for (int j = 0; j < mapResult.row(i).col_size(); j++)
  282. {
  283. row.push_back(Proto2THUAI6::placeTypeDict[mapResult.row(i).col(j)]);
  284. }
  285. map.push_back(std::move(row));
  286. }
  287. bufferState->gameMap = std::move(map);
  288. currentState->gameMap = bufferState->gameMap;
  289. logger->info("Map loaded!");
  290. }
  291. if (currentState->gameMap.empty())
  292. {
  293. logger->error("Map not loaded!");
  294. throw std::runtime_error("Map not loaded!");
  295. }
  296. LoadBuffer(clientMsg);
  297. AILoop = true;
  298. UnBlockAI();
  299. break;
  300. case THUAI6::GameState::GameRunning:
  301. // 重新读取玩家的guid,guid确保人类在前屠夫在后
  302. playerGUIDs.clear();
  303. for (const auto& obj : clientMsg.obj_message())
  304. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  305. playerGUIDs.push_back(obj.student_message().guid());
  306. else if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::NewsMessage)
  307. {
  308. auto news = obj.news_message();
  309. if (news.to_id() == playerID)
  310. messageQueue.emplace(std::make_pair(news.from_id(), news.news()));
  311. }
  312. for (const auto& obj : clientMsg.obj_message())
  313. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  314. playerGUIDs.push_back(obj.tricker_message().guid());
  315. currentState->guids = playerGUIDs;
  316. bufferState->guids = playerGUIDs;
  317. LoadBuffer(clientMsg);
  318. break;
  319. default:
  320. logger->debug("Unknown GameState!");
  321. break;
  322. }
  323. }
  324. AILoop = false;
  325. {
  326. std::lock_guard<std::mutex> lock(mtxBuffer);
  327. bufferUpdated = true;
  328. counterBuffer = -1;
  329. }
  330. cvBuffer.notify_one();
  331. logger->info("Game End!");
  332. };
  333. std::thread(messageThread).detach();
  334. }
  335. void Logic::LoadBuffer(protobuf::MessageToClient& message)
  336. {
  337. // 将消息读入到buffer中
  338. {
  339. std::lock_guard<std::mutex> lock(mtxBuffer);
  340. // 清空原有信息
  341. bufferState->students.clear();
  342. bufferState->trickers.clear();
  343. bufferState->props.clear();
  344. logger->debug("Buffer cleared!");
  345. // 读取新的信息
  346. bufferState->gameInfo = Proto2THUAI6::Protobuf2THUAI6GameInfo(message.all_message());
  347. if (playerType == THUAI6::PlayerType::StudentPlayer)
  348. {
  349. for (const auto& item : message.obj_message())
  350. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  351. {
  352. if (item.student_message().player_id() == playerID)
  353. {
  354. bufferState->studentSelf = Proto2THUAI6::Protobuf2THUAI6Student(item.student_message());
  355. }
  356. bufferState->students.push_back(Proto2THUAI6::Protobuf2THUAI6Student(item.student_message()));
  357. logger->debug("Add Student!");
  358. }
  359. for (const auto& item : message.obj_message())
  360. switch (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()])
  361. {
  362. case THUAI6::MessageOfObj::PropMessage:
  363. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.prop_message().x(), item.prop_message().y(), bufferState->studentSelf->place, Proto2THUAI6::placeTypeDict[item.prop_message().place()], currentState->gameMap))
  364. {
  365. bufferState->props.push_back(Proto2THUAI6::Protobuf2THUAI6Prop(item.prop_message()));
  366. logger->debug("Add Prop!");
  367. }
  368. break;
  369. case THUAI6::MessageOfObj::BulletMessage:
  370. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.prop_message().x(), item.prop_message().y(), bufferState->studentSelf->place, Proto2THUAI6::placeTypeDict[item.prop_message().place()], currentState->gameMap))
  371. {
  372. bufferState->bullets.push_back(Proto2THUAI6::Protobuf2THUAI6Bullet(item.bullet_message()));
  373. logger->debug("Add Bullet!");
  374. }
  375. break;
  376. case THUAI6::MessageOfObj::ClassroomMessage:
  377. {
  378. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.classroom_message().x(), item.classroom_message().y(), bufferState->studentSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  379. {
  380. auto pos = std::make_pair(item.classroom_message().x(), item.classroom_message().y());
  381. if (bufferState->mapInfo->classRoomState.count(pos) == 0)
  382. {
  383. bufferState->mapInfo->classRoomState.emplace(pos, item.classroom_message().progress());
  384. logger->debug("Add Classroom!");
  385. }
  386. else
  387. {
  388. bufferState->mapInfo->classRoomState[pos] = item.classroom_message().progress();
  389. logger->debug("Update Classroom!");
  390. }
  391. }
  392. break;
  393. }
  394. case THUAI6::MessageOfObj::ChestMessage:
  395. {
  396. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.chest_message().x(), item.chest_message().y(), bufferState->studentSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  397. {
  398. auto pos = std::make_pair(item.chest_message().x(), item.chest_message().y());
  399. if (bufferState->mapInfo->chestState.count(pos) == 0)
  400. {
  401. bufferState->mapInfo->chestState.emplace(pos, item.chest_message().progress());
  402. logger->debug("Add Chest!");
  403. }
  404. else
  405. {
  406. bufferState->mapInfo->chestState[pos] = item.chest_message().progress();
  407. logger->debug("Update Chest!");
  408. }
  409. }
  410. break;
  411. }
  412. case THUAI6::MessageOfObj::DoorMessage:
  413. {
  414. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.door_message().x(), item.door_message().y(), bufferState->studentSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  415. {
  416. auto pos = std::make_pair(item.door_message().x(), item.door_message().y());
  417. if (bufferState->mapInfo->doorState.count(pos) == 0)
  418. {
  419. bufferState->mapInfo->doorState.emplace(pos, item.door_message().is_open());
  420. bufferState->mapInfo->doorProgress.emplace(pos, item.door_message().progress());
  421. logger->debug("Add Door!");
  422. }
  423. else
  424. {
  425. bufferState->mapInfo->doorState[pos] = item.door_message().is_open();
  426. bufferState->mapInfo->doorProgress[pos] = item.door_message().progress();
  427. logger->debug("Update Door!");
  428. }
  429. }
  430. break;
  431. }
  432. case THUAI6::MessageOfObj::HiddenGateMessage:
  433. {
  434. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.hidden_gate_message().x(), item.hidden_gate_message().y(), bufferState->studentSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  435. {
  436. auto pos = std::make_pair(item.hidden_gate_message().x(), item.hidden_gate_message().y());
  437. if (bufferState->mapInfo->hiddenGateState.count(pos) == 0)
  438. {
  439. bufferState->mapInfo->hiddenGateState.emplace(pos, Proto2THUAI6::Bool2HiddenGateState(item.hidden_gate_message().opened()));
  440. logger->debug("Add HiddenGate!");
  441. }
  442. else
  443. {
  444. bufferState->mapInfo->hiddenGateState[pos] = Proto2THUAI6::Bool2HiddenGateState(item.hidden_gate_message().opened());
  445. logger->debug("Update HiddenGate!");
  446. }
  447. }
  448. break;
  449. }
  450. case THUAI6::MessageOfObj::GateMessage:
  451. {
  452. if (!AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.gate_message().x(), item.gate_message().y(), bufferState->studentSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  453. {
  454. auto pos = std::make_pair(item.gate_message().x(), item.gate_message().y());
  455. if (bufferState->mapInfo->gateState.count(pos) == 0)
  456. {
  457. bufferState->mapInfo->gateState.emplace(pos, item.gate_message().progress());
  458. logger->debug("Add Gate!");
  459. }
  460. else
  461. {
  462. bufferState->mapInfo->gateState[pos] = item.gate_message().progress();
  463. logger->debug("Update Gate!");
  464. }
  465. }
  466. break;
  467. }
  468. case THUAI6::MessageOfObj::TrickerMessage:
  469. {
  470. if (AssistFunction::HaveView(bufferState->studentSelf->viewRange, bufferState->studentSelf->x, bufferState->studentSelf->y, item.tricker_message().x(), item.tricker_message().y(), bufferState->studentSelf->place, Proto2THUAI6::placeTypeDict[item.tricker_message().place()], bufferState->gameMap))
  471. {
  472. bufferState->trickers.push_back(Proto2THUAI6::Protobuf2THUAI6Tricker(item.tricker_message()));
  473. logger->debug("Add Tricker!");
  474. }
  475. }
  476. case THUAI6::MessageOfObj::NullMessageOfObj:
  477. default:
  478. break;
  479. }
  480. }
  481. else
  482. {
  483. for (const auto& item : message.obj_message())
  484. {
  485. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  486. {
  487. if (item.tricker_message().player_id() == playerID)
  488. {
  489. bufferState->trickerSelf = Proto2THUAI6::Protobuf2THUAI6Tricker(item.tricker_message());
  490. }
  491. bufferState->trickers.push_back(Proto2THUAI6::Protobuf2THUAI6Tricker(item.tricker_message()));
  492. logger->debug("Add Tricker!");
  493. }
  494. }
  495. for (const auto& item : message.obj_message())
  496. switch (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()])
  497. {
  498. case THUAI6::MessageOfObj::PropMessage:
  499. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.prop_message().x(), item.prop_message().y(), bufferState->trickerSelf->place, Proto2THUAI6::placeTypeDict[item.prop_message().place()], currentState->gameMap))
  500. {
  501. bufferState->props.push_back(Proto2THUAI6::Protobuf2THUAI6Prop(item.prop_message()));
  502. logger->debug("Add Prop!");
  503. }
  504. break;
  505. case THUAI6::MessageOfObj::BulletMessage:
  506. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.prop_message().x(), item.prop_message().y(), bufferState->trickerSelf->place, Proto2THUAI6::placeTypeDict[item.prop_message().place()], currentState->gameMap))
  507. {
  508. bufferState->bullets.push_back(Proto2THUAI6::Protobuf2THUAI6Bullet(item.bullet_message()));
  509. logger->debug("Add Bullet!");
  510. }
  511. break;
  512. case THUAI6::MessageOfObj::ClassroomMessage:
  513. {
  514. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.classroom_message().x(), item.classroom_message().y(), bufferState->trickerSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  515. {
  516. auto pos = std::make_pair(item.classroom_message().x(), item.classroom_message().y());
  517. if (bufferState->mapInfo->classRoomState.count(pos) == 0)
  518. {
  519. bufferState->mapInfo->classRoomState.emplace(pos, item.classroom_message().progress());
  520. logger->debug("Add Classroom!");
  521. }
  522. else
  523. {
  524. bufferState->mapInfo->classRoomState[pos] = item.classroom_message().progress();
  525. logger->debug("Update Classroom!");
  526. }
  527. }
  528. break;
  529. }
  530. case THUAI6::MessageOfObj::ChestMessage:
  531. {
  532. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.chest_message().x(), item.chest_message().y(), bufferState->trickerSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  533. {
  534. auto pos = std::make_pair(item.chest_message().x(), item.chest_message().y());
  535. if (bufferState->mapInfo->chestState.count(pos) == 0)
  536. {
  537. bufferState->mapInfo->chestState.emplace(pos, item.chest_message().progress());
  538. logger->debug("Add Chest!");
  539. }
  540. else
  541. {
  542. bufferState->mapInfo->chestState[pos] = item.chest_message().progress();
  543. logger->debug("Update Chest!");
  544. }
  545. }
  546. break;
  547. }
  548. case THUAI6::MessageOfObj::DoorMessage:
  549. {
  550. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.door_message().x(), item.door_message().y(), bufferState->trickerSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  551. {
  552. auto pos = std::make_pair(item.door_message().x(), item.door_message().y());
  553. if (bufferState->mapInfo->doorState.count(pos) == 0)
  554. {
  555. bufferState->mapInfo->doorState.emplace(pos, item.door_message().is_open());
  556. bufferState->mapInfo->doorProgress.emplace(pos, item.door_message().progress());
  557. logger->debug("Add Door!");
  558. }
  559. else
  560. {
  561. bufferState->mapInfo->doorState[pos] = item.door_message().is_open();
  562. bufferState->mapInfo->doorProgress[pos] = item.door_message().progress();
  563. logger->debug("Update Door!");
  564. }
  565. }
  566. break;
  567. }
  568. case THUAI6::MessageOfObj::HiddenGateMessage:
  569. {
  570. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.hidden_gate_message().x(), item.hidden_gate_message().y(), bufferState->trickerSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  571. {
  572. auto pos = std::make_pair(item.hidden_gate_message().x(), item.hidden_gate_message().y());
  573. if (bufferState->mapInfo->hiddenGateState.count(pos) == 0)
  574. {
  575. bufferState->mapInfo->hiddenGateState.emplace(pos, Proto2THUAI6::Bool2HiddenGateState(item.hidden_gate_message().opened()));
  576. logger->debug("Add HiddenGate!");
  577. }
  578. else
  579. {
  580. bufferState->mapInfo->hiddenGateState[pos] = Proto2THUAI6::Bool2HiddenGateState(item.hidden_gate_message().opened());
  581. logger->debug("Update HiddenGate!");
  582. }
  583. }
  584. break;
  585. }
  586. case THUAI6::MessageOfObj::GateMessage:
  587. {
  588. if (!AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.gate_message().x(), item.gate_message().y(), bufferState->trickerSelf->place, THUAI6::PlaceType::Land, currentState->gameMap))
  589. {
  590. auto pos = std::make_pair(item.gate_message().x(), item.gate_message().y());
  591. if (bufferState->mapInfo->gateState.count(pos) == 0)
  592. {
  593. bufferState->mapInfo->gateState.emplace(pos, item.gate_message().progress());
  594. logger->debug("Add Gate!");
  595. }
  596. else
  597. {
  598. bufferState->mapInfo->gateState[pos] = item.gate_message().progress();
  599. logger->debug("Update Gate!");
  600. }
  601. }
  602. break;
  603. }
  604. case THUAI6::MessageOfObj::StudentMessage:
  605. {
  606. if (AssistFunction::HaveView(bufferState->trickerSelf->viewRange, bufferState->trickerSelf->x, bufferState->trickerSelf->y, item.student_message().x(), item.student_message().y(), bufferState->trickerSelf->place, Proto2THUAI6::placeTypeDict[item.student_message().place()], bufferState->gameMap))
  607. {
  608. bufferState->students.push_back(Proto2THUAI6::Protobuf2THUAI6Student(item.student_message()));
  609. logger->debug("Add Student!");
  610. }
  611. }
  612. case THUAI6::MessageOfObj::NullMessageOfObj:
  613. default:
  614. break;
  615. }
  616. }
  617. if (asynchronous)
  618. {
  619. {
  620. std::lock_guard<std::mutex> lock(mtxState);
  621. std::swap(currentState, bufferState);
  622. logger->info("Update State!");
  623. }
  624. freshed = true;
  625. }
  626. else
  627. bufferUpdated = true;
  628. counterBuffer++;
  629. }
  630. // 唤醒其他线程
  631. cvBuffer.notify_one();
  632. }
  633. void Logic::Update() noexcept
  634. {
  635. if (!asynchronous)
  636. {
  637. std::unique_lock<std::mutex> lock(mtxBuffer);
  638. // 缓冲区被更新之后才可以使用
  639. cvBuffer.wait(lock, [&]()
  640. { return bufferUpdated; });
  641. std::swap(currentState, bufferState);
  642. bufferUpdated = false;
  643. counterState = counterBuffer;
  644. logger->info("Update State!");
  645. }
  646. }
  647. void Logic::Wait() noexcept
  648. {
  649. freshed = false;
  650. {
  651. std::unique_lock<std::mutex> lock(mtxBuffer);
  652. cvBuffer.wait(lock, [&]()
  653. { return freshed.load(); });
  654. }
  655. }
  656. void Logic::UnBlockAI()
  657. {
  658. {
  659. std::lock_guard<std::mutex> lock(mtxAI);
  660. AIStart = true;
  661. }
  662. cvAI.notify_one();
  663. }
  664. int Logic::GetCounter() const
  665. {
  666. std::unique_lock<std::mutex> lock(mtxState);
  667. return counterState;
  668. }
  669. std::vector<int64_t> Logic::GetPlayerGUIDs() const
  670. {
  671. std::unique_lock<std::mutex> lock(mtxState);
  672. return currentState->guids;
  673. }
  674. bool Logic::TryConnection()
  675. {
  676. logger->info("Try to connect to server...");
  677. return pComm->TryConnection(playerID);
  678. }
  679. void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool file, bool print, bool warnOnly)
  680. {
  681. // 建立日志组件
  682. auto fileLogger = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/logic-log.txt", true);
  683. auto printLogger = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
  684. std::string pattern = "[logic] [%H:%M:%S.%e] [%l] %v";
  685. fileLogger->set_pattern(pattern);
  686. printLogger->set_pattern(pattern);
  687. if (file)
  688. {
  689. fileLogger->set_level(spdlog::level::trace);
  690. }
  691. else
  692. fileLogger->set_level(spdlog::level::off);
  693. if (print)
  694. printLogger->set_level(spdlog::level::info);
  695. else
  696. printLogger->set_level(spdlog::level::off);
  697. if (warnOnly)
  698. printLogger->set_level(spdlog::level::warn);
  699. logger = std::make_unique<spdlog::logger>("logicLogger", spdlog::sinks_init_list{fileLogger, printLogger});
  700. logger->flush_on(spdlog::level::warn);
  701. // 打印当前的调试信息
  702. logger->info("*********Basic Info*********");
  703. logger->info("asynchronous: {}", asynchronous);
  704. logger->info("server: {}:{}", IP, port);
  705. logger->info("player ID: {}", playerID);
  706. logger->info("player type: {}", THUAI6::playerTypeDict[playerType]);
  707. logger->info("****************************");
  708. // 建立与服务器之间通信的组件
  709. pComm = std::make_unique<Communication>(IP, port);
  710. // 构造timer
  711. if (playerType == THUAI6::PlayerType::StudentPlayer)
  712. {
  713. if (!file && !print)
  714. timer = std::make_unique<StudentAPI>(*this);
  715. else
  716. timer = std::make_unique<StudentDebugAPI>(*this, file, print, warnOnly, playerID);
  717. }
  718. else if (playerType == THUAI6::PlayerType::TrickerPlayer)
  719. {
  720. if (!file && !print)
  721. timer = std::make_unique<TrickerAPI>(*this);
  722. else
  723. timer = std::make_unique<TrickerDebugAPI>(*this, file, print, warnOnly, playerID);
  724. }
  725. // 构造AI线程
  726. auto AIThread = [&]()
  727. {
  728. {
  729. std::unique_lock<std::mutex> lock(mtxAI);
  730. cvAI.wait(lock, [this]()
  731. { return AIStart; });
  732. }
  733. auto ai = createAI();
  734. while (AILoop)
  735. {
  736. if (asynchronous)
  737. {
  738. Wait();
  739. timer->StartTimer();
  740. timer->Play(*ai);
  741. timer->EndTimer();
  742. }
  743. else
  744. {
  745. Update();
  746. timer->StartTimer();
  747. timer->Play(*ai);
  748. timer->EndTimer();
  749. }
  750. }
  751. };
  752. // 连接服务器
  753. if (TryConnection())
  754. {
  755. logger->info("Connect to the server successfully, AI thread will be started.");
  756. tAI = std::thread(AIThread);
  757. if (tAI.joinable())
  758. {
  759. logger->info("Join the AI thread!");
  760. // 首先开启处理消息的线程
  761. ProcessMessage();
  762. tAI.join();
  763. }
  764. }
  765. else
  766. {
  767. AILoop = false;
  768. logger->error("Connect to the server failed, AI thread will not be started.");
  769. return;
  770. }
  771. }