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.py 30 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. import os
  2. from typing import List, Union, Callable, Tuple
  3. import threading
  4. import logging
  5. import copy
  6. import platform
  7. import proto.MessageType_pb2 as MessageType
  8. import proto.Message2Server_pb2 as Message2Server
  9. import proto.Message2Clients_pb2 as Message2Clients
  10. from queue import Queue
  11. import PyAPI.structures as THUAI6
  12. from PyAPI.utils import Proto2THUAI6, AssistFunction
  13. from PyAPI.DebugAPI import StudentDebugAPI, TrickerDebugAPI
  14. from PyAPI.API import StudentAPI, TrickerAPI
  15. from PyAPI.AI import Setting
  16. from PyAPI.Communication import Communication
  17. from PyAPI.State import State
  18. from PyAPI.Interface import ILogic, IGameTimer
  19. class Logic(ILogic):
  20. def __init__(self, playerID: int, playerType: THUAI6.PlayerType) -> None:
  21. # ID
  22. self.__playerID: int = playerID
  23. self.__playerType: THUAI6.PlayerType = playerType
  24. # 通信
  25. self.__comm: Communication
  26. # 存储状态
  27. self.__currentState: State = State()
  28. self.__bufferState: State = State()
  29. # timer,用于实际运行AI
  30. self.__timer: IGameTimer
  31. # AI线程
  32. self.__threadAI: threading.Thread
  33. # 互斥锁
  34. self.__mtxState: threading.Lock = threading.Lock()
  35. # 条件变量
  36. self.__cvBuffer: threading.Condition = threading.Condition()
  37. self.__cvAI: threading.Condition = threading.Condition()
  38. # 保存缓冲区数
  39. self.__counterState: int = 0
  40. self.__counterBuffer: int = 0
  41. # 记录游戏状态
  42. self.__gameState: THUAI6.GameState = THUAI6.GameState.NullGameState
  43. # 是否应该执行player()
  44. self.__AILoop: bool = True
  45. # buffer是否更新完毕
  46. self.__bufferUpdated: bool = False
  47. # 是否应当启动AI
  48. self.__AIStart: bool = False
  49. # asynchronous为True时控制内容更新的变量
  50. self.__freshed: bool = False
  51. self.__logger: logging.Logger = logging.getLogger("logic")
  52. self.__messageQueue: Queue = Queue()
  53. # IAPI统一可用的接口
  54. def GetTrickers(self) -> List[THUAI6.Tricker]:
  55. with self.__mtxState:
  56. self.__logger.debug("Called GetTrickers")
  57. return copy.deepcopy(self.__currentState.trickers)
  58. def GetStudents(self) -> List[THUAI6.Student]:
  59. with self.__mtxState:
  60. self.__logger.debug("Called GetStudents")
  61. return copy.deepcopy(self.__currentState.students)
  62. def GetProps(self) -> List[THUAI6.Prop]:
  63. with self.__mtxState:
  64. self.__logger.debug("Called GetProps")
  65. return copy.deepcopy(self.__currentState.props)
  66. def GetBullets(self) -> List[THUAI6.Bullet]:
  67. with self.__mtxState:
  68. self.__logger.debug("Called GetBullets")
  69. return copy.deepcopy(self.__currentState.bullets)
  70. def GetSelfInfo(self) -> Union[THUAI6.Student, THUAI6.Tricker]:
  71. with self.__mtxState:
  72. self.__logger.debug("Called GetSelfInfo")
  73. return copy.deepcopy(self.__currentState.self)
  74. def GetFullMap(self) -> List[List[THUAI6.PlaceType]]:
  75. with self.__mtxState:
  76. self.__logger.debug("Called GetFullMap")
  77. return copy.deepcopy(self.__currentState.gameMap)
  78. def GetPlaceType(self, x: int, y: int) -> THUAI6.PlaceType:
  79. with self.__mtxState:
  80. if (
  81. x < 0
  82. or x >= len(self.__currentState.gameMap)
  83. or y < 0
  84. or y >= len(self.__currentState.gameMap[0])
  85. ):
  86. self.__logger.warning("Invalid position")
  87. return THUAI6.PlaceType.NullPlaceType
  88. self.__logger.debug("Called GetPlaceType")
  89. return copy.deepcopy(self.__currentState.gameMap[x][y])
  90. def IsDoorOpen(self, x: int, y: int) -> bool:
  91. with self.__mtxState:
  92. self.__logger.debug("Called IsDoorOpen")
  93. if (x, y) in self.__currentState.mapInfo.doorState:
  94. return copy.deepcopy(self.__currentState.mapInfo.doorState[(x, y)])
  95. else:
  96. self.__logger.warning("Door not found")
  97. return False
  98. def GetClassroomProgress(self, x: int, y: int) -> int:
  99. with self.__mtxState:
  100. self.__logger.debug("Called GetClassroomProgress")
  101. if (x, y) in self.__currentState.mapInfo.classroomState:
  102. return copy.deepcopy(self.__currentState.mapInfo.classroomState[(x, y)])
  103. else:
  104. self.__logger.warning("Classroom not found")
  105. return -1
  106. def GetChestProgress(self, x: int, y: int) -> int:
  107. with self.__mtxState:
  108. self.__logger.debug("Called GetChestProgress")
  109. if (x, y) in self.__currentState.mapInfo.chestState:
  110. return copy.deepcopy(self.__currentState.mapInfo.chestState[(x, y)])
  111. else:
  112. self.__logger.warning("Chest not found")
  113. return -1
  114. def GetGateProgress(self, x: int, y: int) -> int:
  115. with self.__mtxState:
  116. self.__logger.debug("Called GetGateProgress")
  117. if (x, y) in self.__currentState.mapInfo.gateState:
  118. return copy.deepcopy(self.__currentState.mapInfo.gateState[(x, y)])
  119. else:
  120. self.__logger.warning("Gate not found")
  121. return -1
  122. def GetHiddenGateState(self, x: int, y: int) -> THUAI6.HiddenGateState:
  123. with self.__mtxState:
  124. self.__logger.debug("Called GetHiddenGateState")
  125. if (x, y) in self.__currentState.mapInfo.hiddenGateState:
  126. return copy.deepcopy(
  127. self.__currentState.mapInfo.hiddenGateState[(x, y)]
  128. )
  129. else:
  130. self.__logger.warning("HiddenGate not found")
  131. return THUAI6.HiddenGateState.Null
  132. def GetDoorProgress(self, x: int, y: int) -> int:
  133. with self.__mtxState:
  134. self.__logger.debug("Called GetDoorProgress")
  135. if (x, y) in self.__currentState.mapInfo.doorProgress:
  136. return copy.deepcopy(self.__currentState.mapInfo.doorProgress[(x, y)])
  137. else:
  138. self.__logger.warning("Door not found")
  139. return -1
  140. def GetGameInfo(self) -> THUAI6.GameInfo:
  141. with self.__mtxState:
  142. self.__logger.debug("Called GetGameInfo")
  143. return copy.deepcopy(self.__currentState.gameInfo)
  144. def Move(self, time: int, angle: float) -> bool:
  145. self.__logger.debug("Called Move")
  146. return self.__comm.Move(time, angle, self.__playerID)
  147. def PickProp(self, propType: THUAI6.PropType) -> bool:
  148. self.__logger.debug("Called PickProp")
  149. return self.__comm.PickProp(propType, self.__playerID)
  150. def UseProp(self, propType: THUAI6.PropType) -> bool:
  151. self.__logger.debug("Called UseProp")
  152. return self.__comm.UseProp(propType, self.__playerID)
  153. def ThrowProp(self, propType: THUAI6.PropType) -> bool:
  154. self.__logger.debug("Called ThrowProp")
  155. return self.__comm.ThrowProp(propType, self.__playerID)
  156. def UseSkill(self, skillID: int, skillParam: int) -> bool:
  157. self.__logger.debug("Called UseSkill")
  158. return self.__comm.UseSkill(skillID, skillParam, self.__playerID)
  159. def SendMessage(self, toID: int, message: Union[str, bytes]) -> bool:
  160. self.__logger.debug("Called SendMessage")
  161. return self.__comm.SendMessage(toID, message, self.__playerID)
  162. def HaveMessage(self) -> bool:
  163. self.__logger.debug("Called HaveMessage")
  164. return not self.__messageQueue.empty()
  165. def GetMessage(self) -> Tuple[int, Union[str, bytes]]:
  166. self.__logger.debug("Called GetMessage")
  167. if self.__messageQueue.empty():
  168. self.__logger.warning("Message queue is empty!")
  169. return -1, ""
  170. else:
  171. return self.__messageQueue.get()
  172. def WaitThread(self) -> bool:
  173. self.__Update()
  174. return True
  175. def GetCounter(self) -> int:
  176. with self.__mtxState:
  177. return copy.deepcopy(self.__counterState)
  178. def GetPlayerGUIDs(self) -> List[int]:
  179. with self.__mtxState:
  180. return copy.deepcopy(self.__currentState.guids)
  181. # IStudentAPI使用的接口
  182. def Graduate(self) -> bool:
  183. self.__logger.debug("Called Graduate")
  184. return self.__comm.Graduate(self.__playerID)
  185. def StartLearning(self) -> bool:
  186. self.__logger.debug("Called StartLearning")
  187. return self.__comm.StartLearning(self.__playerID)
  188. def StartEncourageMate(self, mateID: int) -> bool:
  189. self.__logger.debug("Called StartEncourageMate")
  190. return self.__comm.StartEncourageMate(self.__playerID, mateID)
  191. def StartRouseMate(self, mateID: int) -> bool:
  192. self.__logger.debug("Called StartRouseMate")
  193. return self.__comm.StartRouseMate(self.__playerID, mateID)
  194. def Attack(self, angle: float) -> bool:
  195. self.__logger.debug("Called Trick")
  196. return self.__comm.Attack(angle, self.__playerID)
  197. def CloseDoor(self) -> bool:
  198. self.__logger.debug("Called CloseDoor")
  199. return self.__comm.CloseDoor(self.__playerID)
  200. def OpenDoor(self) -> bool:
  201. self.__logger.debug("Called OpenDoor")
  202. return self.__comm.OpenDoor(self.__playerID)
  203. def SkipWindow(self) -> bool:
  204. self.__logger.debug("Called SkipWindow")
  205. return self.__comm.SkipWindow(self.__playerID)
  206. def StartOpenGate(self) -> bool:
  207. self.__logger.debug("Called StartOpenGate")
  208. return self.__comm.StartOpenGate(self.__playerID)
  209. def StartOpenChest(self) -> bool:
  210. self.__logger.debug("Called StartOpenChest")
  211. return self.__comm.StartOpenChest(self.__playerID)
  212. def EndAllAction(self) -> bool:
  213. self.__logger.debug("Called EndAllAction")
  214. return self.__comm.EndAllAction(self.__playerID)
  215. def HaveView(
  216. self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int
  217. ) -> bool:
  218. with self.__mtxState:
  219. return AssistFunction.HaveView(
  220. viewRange, selfX, selfY, gridX, gridY, self.__currentState.gameMap
  221. )
  222. # Logic内部逻辑
  223. def __TryConnection(self) -> bool:
  224. self.__logger.info("Try to connect to server...")
  225. return self.__comm.TryConnection(self.__playerID)
  226. def __ProcessMessage(self) -> None:
  227. def messageThread():
  228. self.__logger.info("Message thread start!")
  229. self.__comm.AddPlayer(self.__playerID, self.__playerType)
  230. self.__logger.info("Join the player!")
  231. while self.__gameState != THUAI6.GameState.GameEnd:
  232. # 读取消息,无消息时此处阻塞
  233. clientMsg = self.__comm.GetMessage2Client()
  234. self.__logger.debug("Get message from server!")
  235. self.__gameState = Proto2THUAI6.gameStateDict[clientMsg.game_state]
  236. if self.__gameState == THUAI6.GameState.GameStart:
  237. # 读取玩家的GUID
  238. self.__logger.info("Game start!")
  239. for obj in clientMsg.obj_message:
  240. if obj.WhichOneof("message_of_obj") == "map_message":
  241. gameMap: List[List[THUAI6.PlaceType]] = []
  242. for row in obj.map_message.row:
  243. col: List[THUAI6.PlaceType] = []
  244. for place in row.col:
  245. col.append(Proto2THUAI6.placeTypeDict[place])
  246. gameMap.append(col)
  247. self.__currentState.gameMap = gameMap
  248. self.__bufferState.gameMap = gameMap
  249. self.__logger.info("Game map loaded!")
  250. break
  251. else:
  252. self.__logger.error("Map not found!")
  253. self.__LoadBuffer(clientMsg)
  254. self.__AILoop = True
  255. self.__UnBlockAI()
  256. elif self.__gameState == THUAI6.GameState.GameRunning:
  257. # 读取玩家的GUID
  258. self.__LoadBuffer(clientMsg)
  259. else:
  260. self.__logger.error("Unknown GameState!")
  261. continue
  262. with self.__cvBuffer:
  263. self.__bufferUpdated = True
  264. self.__counterBuffer = -1
  265. self.__cvBuffer.notify()
  266. self.__logger.info("Game End!")
  267. self.__logger.info("Message thread end!")
  268. self.__AILoop = False
  269. threading.Thread(target=messageThread).start()
  270. def __LoadBufferSelf(self, message: Message2Clients.MessageToClient) -> None:
  271. if self.__playerType == THUAI6.PlayerType.StudentPlayer:
  272. for item in message.obj_message:
  273. if item.WhichOneof("message_of_obj") == "student_message":
  274. if item.student_message.player_id == self.__playerID:
  275. self.__bufferState.self = Proto2THUAI6.Protobuf2THUAI6Student(
  276. item.student_message
  277. )
  278. self.__bufferState.students.append(self.__bufferState.self)
  279. else:
  280. self.__bufferState.students.append(
  281. Proto2THUAI6.Protobuf2THUAI6Student(item.student_message)
  282. )
  283. self.__logger.debug("Add Student!")
  284. else:
  285. for item in message.obj_message:
  286. if item.WhichOneof("message_of_obj") == "tricker_message":
  287. if item.tricker_message.player_id == self.__playerID:
  288. self.__bufferState.self = Proto2THUAI6.Protobuf2THUAI6Tricker(
  289. item.tricker_message
  290. )
  291. self.__bufferState.trickers.append(self.__bufferState.self)
  292. else:
  293. self.__bufferState.trickers.append(
  294. Proto2THUAI6.Protobuf2THUAI6Tricker(item.tricker_message)
  295. )
  296. self.__logger.debug("Add Tricker!")
  297. def __LoadBufferCase(self, item: Message2Clients.MessageOfObj) -> None:
  298. if (
  299. self.__playerType == THUAI6.PlayerType.StudentPlayer
  300. and item.WhichOneof("message_of_obj") == "tricker_message"
  301. ):
  302. if MessageType.TRICKER_INVISIBLE in item.tricker_message.buff:
  303. return
  304. if AssistFunction.HaveView(
  305. self.__bufferState.self.viewRange,
  306. self.__bufferState.self.x,
  307. self.__bufferState.self.y,
  308. item.tricker_message.x,
  309. item.tricker_message.y,
  310. self.__bufferState.gameMap,
  311. ):
  312. self.__bufferState.trickers.append(
  313. Proto2THUAI6.Protobuf2THUAI6Tricker(item.tricker_message)
  314. )
  315. self.__logger.debug("Add Tricker!")
  316. elif (
  317. self.__playerType == THUAI6.PlayerType.TrickerPlayer
  318. and item.WhichOneof("message_of_obj") == "student_message"
  319. ):
  320. if THUAI6.TrickerBuffType.Clairaudience in self.__bufferState.self.buff:
  321. self.__bufferState.students.append(
  322. Proto2THUAI6.Protobuf2THUAI6Student(item.student_message)
  323. )
  324. self.__logger.debug("Add Student!")
  325. return
  326. if MessageType.STUDENT_INVISIBLE in item.student_message.buff:
  327. return
  328. if AssistFunction.HaveView(
  329. self.__bufferState.self.viewRange,
  330. self.__bufferState.self.x,
  331. self.__bufferState.self.y,
  332. item.student_message.x,
  333. item.student_message.y,
  334. self.__bufferState.gameMap,
  335. ):
  336. self.__bufferState.students.append(
  337. Proto2THUAI6.Protobuf2THUAI6Student(item.student_message)
  338. )
  339. self.__logger.debug("Add Student!")
  340. elif item.WhichOneof("message_of_obj") == "prop_message":
  341. if AssistFunction.HaveView(
  342. self.__bufferState.self.viewRange,
  343. self.__bufferState.self.x,
  344. self.__bufferState.self.y,
  345. item.prop_message.x,
  346. item.prop_message.y,
  347. self.__bufferState.gameMap,
  348. ):
  349. self.__bufferState.props.append(
  350. Proto2THUAI6.Protobuf2THUAI6Prop(item.prop_message)
  351. )
  352. self.__logger.debug("Add Prop!")
  353. elif item.WhichOneof("message_of_obj") == "bullet_message":
  354. if AssistFunction.HaveView(
  355. self.__bufferState.self.viewRange,
  356. self.__bufferState.self.x,
  357. self.__bufferState.self.y,
  358. item.bullet_message.x,
  359. item.bullet_message.y,
  360. self.__bufferState.gameMap,
  361. ):
  362. self.__bufferState.bullets.append(
  363. Proto2THUAI6.Protobuf2THUAI6Bullet(item.bullet_message)
  364. )
  365. self.__logger.debug("Add Bullet!")
  366. elif item.WhichOneof("message_of_obj") == "classroom_message":
  367. if AssistFunction.HaveView(
  368. self.__bufferState.self.viewRange,
  369. self.__bufferState.self.x,
  370. self.__bufferState.self.y,
  371. item.classroom_message.x,
  372. item.classroom_message.y,
  373. self.__bufferState.gameMap,
  374. ):
  375. pos = (
  376. AssistFunction.GridToCell(item.classroom_message.x),
  377. AssistFunction.GridToCell(item.classroom_message.y),
  378. )
  379. if pos not in self.__bufferState.mapInfo.classroomState:
  380. self.__bufferState.mapInfo.classroomState[
  381. pos
  382. ] = item.classroom_message.progress
  383. self.__logger.debug("Add Classroom!")
  384. else:
  385. self.__bufferState.mapInfo.classroomState[
  386. pos
  387. ] = item.classroom_message.progress
  388. self.__logger.debug("Update Classroom!")
  389. elif item.WhichOneof("message_of_obj") == "chest_message":
  390. if AssistFunction.HaveView(
  391. self.__bufferState.self.viewRange,
  392. self.__bufferState.self.x,
  393. self.__bufferState.self.y,
  394. item.chest_message.x,
  395. item.chest_message.y,
  396. self.__bufferState.gameMap,
  397. ):
  398. pos = (
  399. AssistFunction.GridToCell(item.chest_message.x),
  400. AssistFunction.GridToCell(item.chest_message.y),
  401. )
  402. if pos not in self.__bufferState.mapInfo.chestState:
  403. self.__bufferState.mapInfo.chestState[
  404. pos
  405. ] = item.chest_message.progress
  406. self.__logger.debug(f"Add Chest at {pos[0]}, {pos[1]}")
  407. else:
  408. self.__bufferState.mapInfo.chestState[
  409. pos
  410. ] = item.chest_message.progress
  411. self.__logger.debug(f"Update Chest at {pos[0]}, {pos[1]}")
  412. elif item.WhichOneof("message_of_obj") == "door_message":
  413. if AssistFunction.HaveView(
  414. self.__bufferState.self.viewRange,
  415. self.__bufferState.self.x,
  416. self.__bufferState.self.y,
  417. item.door_message.x,
  418. item.door_message.y,
  419. self.__bufferState.gameMap,
  420. ):
  421. pos = (
  422. AssistFunction.GridToCell(item.door_message.x),
  423. AssistFunction.GridToCell(item.door_message.y),
  424. )
  425. if pos not in self.__bufferState.mapInfo.doorState:
  426. self.__bufferState.mapInfo.doorState[
  427. pos
  428. ] = item.door_message.is_open
  429. self.__bufferState.mapInfo.doorProgress[
  430. pos
  431. ] = item.door_message.progress
  432. self.__logger.debug("Add Door!")
  433. else:
  434. self.__bufferState.mapInfo.doorState[
  435. pos
  436. ] = item.door_message.is_open
  437. self.__bufferState.mapInfo.doorProgress[
  438. pos
  439. ] = item.door_message.progress
  440. self.__logger.debug("Update Door!")
  441. elif item.WhichOneof("message_of_obj") == "hidden_gate_message":
  442. if AssistFunction.HaveView(
  443. self.__bufferState.self.viewRange,
  444. self.__bufferState.self.x,
  445. self.__bufferState.self.y,
  446. item.hidden_gate_message.x,
  447. item.hidden_gate_message.y,
  448. self.__bufferState.gameMap,
  449. ):
  450. pos = (
  451. AssistFunction.GridToCell(item.hidden_gate_message.x),
  452. AssistFunction.GridToCell(item.hidden_gate_message.y),
  453. )
  454. if pos not in self.__bufferState.mapInfo.hiddenGateState:
  455. self.__bufferState.mapInfo.hiddenGateState[
  456. pos
  457. ] = Proto2THUAI6.Bool2HiddenGateState(
  458. item.hidden_gate_message.opened
  459. )
  460. self.__logger.debug("Add HiddenGate!")
  461. else:
  462. self.__bufferState.mapInfo.hiddenGateState[
  463. pos
  464. ] = Proto2THUAI6.Bool2HiddenGateState(
  465. item.hidden_gate_message.opened
  466. )
  467. self.__logger.debug("Update HiddenGate!")
  468. elif item.WhichOneof("message_of_obj") == "gate_message":
  469. if AssistFunction.HaveView(
  470. self.__bufferState.self.viewRange,
  471. self.__bufferState.self.x,
  472. self.__bufferState.self.y,
  473. item.gate_message.x,
  474. item.gate_message.y,
  475. self.__bufferState.gameMap,
  476. ):
  477. pos = (
  478. AssistFunction.GridToCell(item.gate_message.x),
  479. AssistFunction.GridToCell(item.gate_message.y),
  480. )
  481. if pos not in self.__bufferState.mapInfo.gateState:
  482. self.__bufferState.mapInfo.gateState[
  483. pos
  484. ] = item.gate_message.progress
  485. self.__logger.debug("Add Gate!")
  486. else:
  487. self.__bufferState.mapInfo.gateState[
  488. pos
  489. ] = item.gate_message.progress
  490. self.__logger.debug("Update Gate!")
  491. elif item.WhichOneof("message_of_obj") == "news_message":
  492. if item.news_message.to_id == self.__playerID:
  493. if item.news_message.WhichOneof("news") == "text_message":
  494. self.__messageQueue.put(
  495. (item.news_message.from_id, item.news_message.text_message)
  496. )
  497. self.__logger.debug("Add News!")
  498. elif item.news_message.WhichOneof("news") == "binary_message":
  499. self.__messageQueue.put(
  500. (item.news_message.from_id, item.news_message.binary_message)
  501. )
  502. self.__logger.debug("Add News!")
  503. else:
  504. self.__logger.error("Unknown News!")
  505. else:
  506. self.__logger.debug("Unknown Message!")
  507. def __LoadBuffer(self, message: Message2Clients.MessageToClient) -> None:
  508. with self.__cvBuffer:
  509. self.__bufferState.students.clear()
  510. self.__bufferState.trickers.clear()
  511. self.__bufferState.props.clear()
  512. self.__bufferState.bullets.clear()
  513. self.__bufferState.bombedBullets.clear()
  514. self.__bufferState.guids.clear()
  515. self.__logger.debug("Buffer cleared!")
  516. for obj in message.obj_message:
  517. if obj.WhichOneof("message_of_obj") == "student_message":
  518. self.__bufferState.guids.append(obj.student_message.guid)
  519. for obj in message.obj_message:
  520. if obj.WhichOneof("message_of_obj") == "tricker_message":
  521. self.__bufferState.guids.append(obj.tricker_message.guid)
  522. self.__bufferState.gameInfo = Proto2THUAI6.Protobuf2THUAI6GameInfo(
  523. message.all_message
  524. )
  525. self.__LoadBufferSelf(message)
  526. for item in message.obj_message:
  527. self.__LoadBufferCase(item)
  528. if Setting.asynchronous():
  529. with self.__mtxState:
  530. self.__currentState, self.__bufferState = (
  531. self.__bufferState,
  532. self.__currentState,
  533. )
  534. self.__counterState = self.__counterBuffer
  535. self.__logger.info("Update state!")
  536. self.__freshed = True
  537. else:
  538. self.__bufferUpdated = True
  539. self.__counterBuffer += 1
  540. self.__cvBuffer.notify()
  541. def __UnBlockAI(self) -> None:
  542. with self.__cvAI:
  543. self.__AIStart = True
  544. self.__cvAI.notify()
  545. def __Update(self) -> None:
  546. if not Setting.asynchronous():
  547. with self.__cvBuffer:
  548. self.__cvBuffer.wait_for(lambda: self.__bufferUpdated)
  549. with self.__mtxState:
  550. self.__bufferState, self.__currentState = (
  551. self.__currentState,
  552. self.__bufferState,
  553. )
  554. self.__counterState = self.__counterBuffer
  555. self.__bufferUpdated = False
  556. self.__logger.info("Update state!")
  557. def __Wait(self) -> None:
  558. self.__freshed = False
  559. with self.__cvBuffer:
  560. self.__cvBuffer.wait_for(lambda: self.__freshed)
  561. def Main(
  562. self,
  563. createAI: Callable,
  564. IP: str,
  565. port: str,
  566. file: bool,
  567. screen: bool,
  568. warnOnly: bool,
  569. ) -> None:
  570. # 建立日志组件
  571. self.__logger.setLevel(logging.DEBUG)
  572. formatter = logging.Formatter(
  573. "[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s",
  574. "%H:%M:%S",
  575. )
  576. # 确保文件存在
  577. # if not os.path.exists(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"):
  578. # os.makedirs(os.path.dirname(os.path.dirname(
  579. # os.path.realpath(__file__))) + "/logs")
  580. if platform.system().lower() == "windows":
  581. os.system(
  582. f'mkdir "{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}\\logs"'
  583. )
  584. else:
  585. os.system(
  586. f'mkdir -p "{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}/logs"'
  587. )
  588. fileHandler = logging.FileHandler(
  589. os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
  590. + "/logs/logic"
  591. + str(self.__playerID)
  592. + "-log.txt",
  593. "w+",
  594. encoding="utf-8",
  595. )
  596. screenHandler = logging.StreamHandler()
  597. if file:
  598. fileHandler.setLevel(logging.DEBUG)
  599. fileHandler.setFormatter(formatter)
  600. self.__logger.addHandler(fileHandler)
  601. if screen:
  602. if warnOnly:
  603. screenHandler.setLevel(logging.WARNING)
  604. else:
  605. screenHandler.setLevel(logging.INFO)
  606. screenHandler.setFormatter(formatter)
  607. self.__logger.addHandler(screenHandler)
  608. self.__logger.info("*********Basic Info*********")
  609. self.__logger.info("asynchronous: %s", Setting.asynchronous())
  610. self.__logger.info("server: %s:%s", IP, port)
  611. self.__logger.info("playerID: %s", self.__playerID)
  612. self.__logger.info("player type: %s", self.__playerType.name)
  613. self.__logger.info("****************************")
  614. # 建立通信组件
  615. self.__comm = Communication(IP, port)
  616. # 构造timer
  617. if self.__playerType == THUAI6.PlayerType.StudentPlayer:
  618. if not file and not screen:
  619. self.__timer = StudentAPI(self)
  620. else:
  621. self.__timer = StudentDebugAPI(
  622. self, file, screen, warnOnly, self.__playerID
  623. )
  624. elif self.__playerType == THUAI6.PlayerType.TrickerPlayer:
  625. if not file and not screen:
  626. self.__timer = TrickerAPI(self)
  627. else:
  628. self.__timer = TrickerDebugAPI(
  629. self, file, screen, warnOnly, self.__playerID
  630. )
  631. # 构建AI线程
  632. def AIThread():
  633. with self.__cvAI:
  634. self.__cvAI.wait_for(lambda: self.__AIStart)
  635. ai = createAI(self.__playerID)
  636. while self.__AILoop:
  637. if Setting.asynchronous():
  638. self.__Wait()
  639. self.__timer.StartTimer()
  640. self.__timer.Play(ai)
  641. self.__timer.EndTimer()
  642. else:
  643. self.__Update()
  644. self.__timer.StartTimer()
  645. self.__timer.Play(ai)
  646. self.__timer.EndTimer()
  647. if self.__TryConnection():
  648. self.__logger.info(
  649. "Connect to the server successfully, AI thread will be started."
  650. )
  651. self.__threadAI = threading.Thread(target=AIThread)
  652. self.__threadAI.start()
  653. self.__ProcessMessage()
  654. self.__logger.info("Join the AI thread.")
  655. self.__threadAI.join()
  656. else:
  657. self.__AILoop = False
  658. self.__logger.error("Failed to connect to the server.")
  659. return