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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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->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->gameMap[CellX][CellY];
  67. }
  68. bool Logic::Move(int64_t time, double angle)
  69. {
  70. logger->debug("Called Move");
  71. return pComm->Move(time, angle, playerID);
  72. }
  73. bool Logic::PickProp(THUAI6::PropType prop)
  74. {
  75. logger->debug("Called PickProp");
  76. return pComm->PickProp(prop, playerID);
  77. }
  78. bool Logic::UseProp(THUAI6::PropType prop)
  79. {
  80. logger->debug("Called UseProp");
  81. return pComm->UseProp(prop, playerID);
  82. }
  83. bool Logic::UseSkill(int32_t skill)
  84. {
  85. logger->debug("Called UseSkill");
  86. return pComm->UseSkill(skill, playerID);
  87. }
  88. bool Logic::SendMessage(int64_t toID, std::string message)
  89. {
  90. logger->debug("Called SendMessage");
  91. return pComm->SendMessage(toID, message, playerID);
  92. }
  93. bool Logic::HaveMessage()
  94. {
  95. logger->debug("Called HaveMessage");
  96. return pComm->HaveMessage();
  97. }
  98. std::optional<std::pair<int64_t, std::string>> Logic::GetMessage()
  99. {
  100. logger->debug("Called GetMessage");
  101. return pComm->GetMessage();
  102. }
  103. bool Logic::Graduate()
  104. {
  105. logger->debug("Called Graduate");
  106. return pComm->Graduate(playerID);
  107. }
  108. bool Logic::StartLearning()
  109. {
  110. logger->debug("Called StartLearning");
  111. return pComm->StartLearning(playerID);
  112. }
  113. bool Logic::StartTreatMate()
  114. {
  115. logger->debug("Called StartTreatMate");
  116. return pComm->StartTreatMate(playerID);
  117. }
  118. bool Logic::StartRescueMate()
  119. {
  120. logger->debug("Called StartRescueMate");
  121. return pComm->StartRescueMate(playerID);
  122. }
  123. bool Logic::Attack(double angle)
  124. {
  125. logger->debug("Called Attack");
  126. return pComm->Attack(angle, playerID);
  127. }
  128. bool Logic::WaitThread()
  129. {
  130. Update();
  131. return true;
  132. }
  133. void Logic::ProcessMessage()
  134. {
  135. auto messageThread = [&]()
  136. {
  137. logger->info("Message thread start!");
  138. pComm->AddPlayer(playerID, playerType, studentType, trickerType);
  139. logger->info("Join the player!");
  140. pComm->ReadMessage(playerID);
  141. while (gameState != THUAI6::GameState::GameEnd)
  142. {
  143. auto clientMsg = pComm->GetMessage2Client(); // 在获得新消息之前阻塞
  144. logger->debug("Get message from server!");
  145. gameState = Proto2THUAI6::gameStateDict[clientMsg.game_state()];
  146. switch (gameState)
  147. {
  148. case THUAI6::GameState::GameStart:
  149. logger->info("Game Start!");
  150. // 重新读取玩家的guid,保证人类在前屠夫在后
  151. playerGUIDs.clear();
  152. for (const auto& obj : clientMsg.obj_message())
  153. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  154. playerGUIDs.push_back(obj.student_message().guid());
  155. for (const auto& obj : clientMsg.obj_message())
  156. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  157. playerGUIDs.push_back(obj.tricker_message().guid());
  158. currentState->guids = playerGUIDs;
  159. bufferState->guids = playerGUIDs;
  160. LoadBuffer(clientMsg);
  161. AILoop = true;
  162. UnBlockAI();
  163. break;
  164. case THUAI6::GameState::GameRunning:
  165. // 重新读取玩家的guid,guid确保人类在前屠夫在后
  166. playerGUIDs.clear();
  167. for (const auto& obj : clientMsg.obj_message())
  168. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  169. playerGUIDs.push_back(obj.student_message().guid());
  170. for (const auto& obj : clientMsg.obj_message())
  171. if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  172. playerGUIDs.push_back(obj.tricker_message().guid());
  173. currentState->guids = playerGUIDs;
  174. bufferState->guids = playerGUIDs;
  175. LoadBuffer(clientMsg);
  176. break;
  177. default:
  178. logger->debug("Unknown GameState!");
  179. break;
  180. }
  181. }
  182. AILoop = false;
  183. {
  184. std::lock_guard<std::mutex> lock(mtxBuffer);
  185. bufferUpdated = true;
  186. counterBuffer = -1;
  187. }
  188. cvBuffer.notify_one();
  189. logger->info("Game End!");
  190. };
  191. std::thread(messageThread).detach();
  192. }
  193. void Logic::LoadBuffer(protobuf::MessageToClient& message)
  194. {
  195. // 将消息读入到buffer中
  196. {
  197. std::lock_guard<std::mutex> lock(mtxBuffer);
  198. // 清空原有信息
  199. bufferState->students.clear();
  200. bufferState->trickers.clear();
  201. bufferState->props.clear();
  202. logger->debug("Buffer cleared!");
  203. // 读取新的信息
  204. bufferState->gameMap = Proto2THUAI6::Protobuf2THUAI6Map(message.map_message());
  205. bufferState->gameInfo = Proto2THUAI6::Protobuf2THUAI6GameInfo(message.all_message());
  206. if (playerType == THUAI6::PlayerType::StudentPlayer)
  207. {
  208. for (const auto& item : message.obj_message())
  209. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  210. {
  211. if (item.student_message().player_id() == playerID)
  212. {
  213. bufferState->studentSelf = Proto2THUAI6::Protobuf2THUAI6Student(item.student_message());
  214. }
  215. bufferState->students.push_back(Proto2THUAI6::Protobuf2THUAI6Student(item.student_message()));
  216. logger->debug("Add Student!");
  217. }
  218. for (const auto& item : message.obj_message())
  219. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  220. 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->gameMap))
  221. {
  222. bufferState->trickers.push_back(Proto2THUAI6::Protobuf2THUAI6Tricker(item.tricker_message()));
  223. logger->debug("Add Tricker!");
  224. }
  225. }
  226. else
  227. {
  228. for (const auto& item : message.obj_message())
  229. {
  230. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage)
  231. {
  232. if (item.tricker_message().player_id() == playerID)
  233. {
  234. bufferState->trickerSelf = Proto2THUAI6::Protobuf2THUAI6Tricker(item.tricker_message());
  235. }
  236. bufferState->trickers.push_back(Proto2THUAI6::Protobuf2THUAI6Tricker(item.tricker_message()));
  237. logger->debug("Add Tricker!");
  238. }
  239. }
  240. for (const auto& item : message.obj_message())
  241. if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage)
  242. 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->gameMap))
  243. {
  244. bufferState->students.push_back(Proto2THUAI6::Protobuf2THUAI6Student(item.student_message()));
  245. logger->debug("Add Student!");
  246. }
  247. }
  248. for (const auto& item : message.obj_message())
  249. switch (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()])
  250. {
  251. case THUAI6::MessageOfObj::PropMessage:
  252. bufferState->props.push_back(Proto2THUAI6::Protobuf2THUAI6Prop(item.prop_message()));
  253. logger->debug("Add Prop!");
  254. break;
  255. case THUAI6::MessageOfObj::BulletMessage:
  256. bufferState->bullets.push_back(Proto2THUAI6::Protobuf2THUAI6Bullet(item.bullet_message()));
  257. logger->debug("Add Bullet!");
  258. break;
  259. case THUAI6::MessageOfObj::BombedBulletMessage:
  260. bufferState->bombedBullets.push_back(Proto2THUAI6::Protobuf2THUAI6BombedBullet(item.bombed_bullet_message()));
  261. logger->debug("Add BombedBullet!");
  262. break;
  263. }
  264. if (asynchronous)
  265. {
  266. {
  267. std::lock_guard<std::mutex> lock(mtxState);
  268. std::swap(currentState, bufferState);
  269. logger->info("Update State!");
  270. }
  271. freshed = true;
  272. }
  273. else
  274. bufferUpdated = true;
  275. counterBuffer++;
  276. }
  277. // 唤醒其他线程
  278. cvBuffer.notify_one();
  279. }
  280. void Logic::Update() noexcept
  281. {
  282. if (!asynchronous)
  283. {
  284. std::unique_lock<std::mutex> lock(mtxBuffer);
  285. // 缓冲区被更新之后才可以使用
  286. cvBuffer.wait(lock, [&]()
  287. { return bufferUpdated; });
  288. std::swap(currentState, bufferState);
  289. bufferUpdated = false;
  290. counterState = counterBuffer;
  291. logger->info("Update State!");
  292. }
  293. }
  294. void Logic::Wait() noexcept
  295. {
  296. freshed = false;
  297. {
  298. std::unique_lock<std::mutex> lock(mtxBuffer);
  299. cvBuffer.wait(lock, [&]()
  300. { return freshed.load(); });
  301. }
  302. }
  303. void Logic::UnBlockAI()
  304. {
  305. {
  306. std::lock_guard<std::mutex> lock(mtxAI);
  307. AIStart = true;
  308. }
  309. cvAI.notify_one();
  310. }
  311. int Logic::GetCounter() const
  312. {
  313. std::unique_lock<std::mutex> lock(mtxState);
  314. return counterState;
  315. }
  316. const std::vector<int64_t> Logic::GetPlayerGUIDs() const
  317. {
  318. std::unique_lock<std::mutex> lock(mtxState);
  319. return currentState->guids;
  320. }
  321. bool Logic::TryConnection()
  322. {
  323. logger->info("Try to connect to server...");
  324. return pComm->TryConnection(playerID);
  325. }
  326. void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool file, bool print, bool warnOnly)
  327. {
  328. // 建立日志组件
  329. auto fileLogger = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/logic-log.txt", true);
  330. auto printLogger = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
  331. std::string pattern = "[logic] [%H:%M:%S.%e] [%l] %v";
  332. fileLogger->set_pattern(pattern);
  333. printLogger->set_pattern(pattern);
  334. if (file)
  335. fileLogger->set_level(spdlog::level::trace);
  336. else
  337. fileLogger->set_level(spdlog::level::off);
  338. if (print)
  339. printLogger->set_level(spdlog::level::info);
  340. else
  341. printLogger->set_level(spdlog::level::off);
  342. if (warnOnly)
  343. printLogger->set_level(spdlog::level::warn);
  344. logger = std::make_unique<spdlog::logger>("logicLogger", spdlog::sinks_init_list{fileLogger, printLogger});
  345. // 打印当前的调试信息
  346. logger->info("*********Basic Info*********");
  347. logger->info("asynchronous: {}", asynchronous);
  348. logger->info("server: {}:{}", IP, port);
  349. logger->info("player ID: {}", playerID);
  350. logger->info("player type: {}", THUAI6::playerTypeDict[playerType]);
  351. logger->info("****************************");
  352. // 建立与服务器之间通信的组件
  353. pComm = std::make_unique<Communication>(IP, port);
  354. // 构造timer
  355. if (playerType == THUAI6::PlayerType::StudentPlayer)
  356. {
  357. if (!file && !print)
  358. timer = std::make_unique<StudentAPI>(*this);
  359. else
  360. timer = std::make_unique<StudentDebugAPI>(*this, file, print, warnOnly, playerID);
  361. }
  362. else if (playerType == THUAI6::PlayerType::TrickerPlayer)
  363. {
  364. if (!file && !print)
  365. timer = std::make_unique<TrickerAPI>(*this);
  366. else
  367. timer = std::make_unique<TrickerDebugAPI>(*this, file, print, warnOnly, playerID);
  368. }
  369. // 构造AI线程
  370. auto AIThread = [&]()
  371. {
  372. {
  373. std::unique_lock<std::mutex> lock(mtxAI);
  374. cvAI.wait(lock, [this]()
  375. { return AIStart; });
  376. }
  377. auto ai = createAI();
  378. while (AILoop)
  379. {
  380. if (asynchronous)
  381. {
  382. Wait();
  383. timer->StartTimer();
  384. timer->Play(*ai);
  385. timer->EndTimer();
  386. }
  387. else
  388. {
  389. Update();
  390. timer->StartTimer();
  391. timer->Play(*ai);
  392. timer->EndTimer();
  393. }
  394. }
  395. };
  396. // 连接服务器
  397. if (TryConnection())
  398. {
  399. logger->info("Connect to the server successfully, AI thread will be started.");
  400. tAI = std::thread(AIThread);
  401. if (tAI.joinable())
  402. {
  403. logger->info("Join the AI thread!");
  404. // 首先开启处理消息的线程
  405. ProcessMessage();
  406. tAI.join();
  407. }
  408. }
  409. else
  410. {
  411. AILoop = false;
  412. logger->error("Connect to the server failed, AI thread will not be started.");
  413. return;
  414. }
  415. }