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 29 kB

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