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

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