From 534e8fb36195cb066e32e035769a3228d6010e22 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Mon, 24 Apr 2023 10:09:15 +0800 Subject: [PATCH 001/105] docs: :memo: edit docs --- docs/CAPI接口(cpp).md | 3 +++ docs/CAPI接口(python).md | 3 +++ docs/GameRules.md | 5 +---- docs/QandA.md | 10 ++-------- docs/Tool_tutorial.md | 3 ++- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/CAPI接口(cpp).md b/docs/CAPI接口(cpp).md index 01fc608..e92367a 100644 --- a/docs/CAPI接口(cpp).md +++ b/docs/CAPI接口(cpp).md @@ -13,6 +13,9 @@ #### 人物 - `std::future EndAllAction()`:可以使不处在不可行动状态中的玩家终止当前行动 +- 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出Stop指令终止进行的指令 + - 实际上唤醒或勉励不同的人是有效的 +- EndAllAction()及Move指令调用数总和一帧内不超过10次 #### 攻击 - `std::future Attack(double angleInRadian)`:`angleInRadian`为攻击方向 diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index c821959..84d2c82 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -18,6 +18,9 @@ #### 人物 - `def EndAllAction(self) -> Future[bool]`:可以使不处在不可行动状态中的玩家终止当前行动 +- 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出Stop指令终止进行的指令 + - 实际上唤醒或勉励不同的人是有效的 +- EndAllAction()及Move指令调用数总和一帧内不超过10次 #### 攻击 diff --git a/docs/GameRules.md b/docs/GameRules.md index ffc4fd4..39ad815 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -147,7 +147,7 @@ $$ ### 可视范围 - 小于视野半径 - - 对于在从草地中的物体,物体中心与玩家中心连线上均为草地方可见 + - 对于中心在草地中的物体,物体中心与玩家中心连线上均为草地方可见 - 不在草地的物体,物体中心与玩家中心连线上无墙即可见 ### 道具 @@ -308,7 +308,6 @@ $$ - 不鼓励选手面向地图编程,因为移动过程中你可以受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 ### 人物 -- EndAllAction()及Move指令调用数总和一帧内不超过10次 - 眩晕状态中的玩家不能再次被眩晕 ### 初始状态 @@ -318,8 +317,6 @@ $$ - 使用钥匙相当于销毁 ### 交互 -- 在指令仍在进行时,重复发出同一类型的交互指令是无效的,你需要先发出Stop指令终止进行的指令 - - 实际上唤醒或勉励不同的人是有效的 - 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 ### 学习与毕业 diff --git a/docs/QandA.md b/docs/QandA.md index 6e32bd1..90096d9 100644 --- a/docs/QandA.md +++ b/docs/QandA.md @@ -24,12 +24,6 @@ Q: 怎么开始游戏? A: 需要确保学生阵营和捣蛋鬼阵营的人数都达到Server.cmd中设定的值。人数不足也可以打开WPF,参考使用文档,修改RunGUIClient.cmd的参数,然后运行RunGUIClient.cmd,这样可以通过WPF运行部分客户端,来达到人数限制。 - -Q: Mac怎么用? - -A: -安装Windows虚拟机 -try ## C++ Q:显示API项目已卸载 @@ -37,7 +31,7 @@ Q:显示API项目已卸载 A:可能是没有安装C++ -Q:CAPI.sln编译不通过 +Q:CAPI.sln编译不通过(第一种) 情况1: ![std_find_trivial](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/std_find_trivial.jpg) 情况2: @@ -52,7 +46,7 @@ A: ![项目属性](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/项目属性.png) 确保上图项目属性中平台工具集在 v143,C++17 标准 -Q:CAPI编译不通过 +Q:CAPI编译不通过(第二种) ![lib](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/lib.png) A:查看`.\win\CAPI\cpp\`文件夹下是否有`lib`文件夹,没有则https://cloud.tsinghua.edu.cn/d/6972138f641d4e81a446/ 下载并复制粘贴 diff --git a/docs/Tool_tutorial.md b/docs/Tool_tutorial.md index 65b71b2..b90e7d6 100644 --- a/docs/Tool_tutorial.md +++ b/docs/Tool_tutorial.md @@ -65,9 +65,10 @@ int main() ### 线程睡眠 - 由于移动过程中会阻塞人物角色,因此玩家可能要在移动后让线程休眠一段时间,直到移动结束。C++ 标准库中使线程休眠需要包含头文件:`#include `。示例用法: +我们推荐小步移动,不太建议玩家使用线程睡眠超过一帧 + ```cpp std::this_thread::sleep_for(std::chrono::milliseconds(20)); // 休眠 20 毫秒 std::this_thread::sleep_for(std::chrono::seconds(2)); // 休眠 2 秒 From 483624ea80772706f98c9e2156caa04a24b435ba Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Mon, 24 Apr 2023 15:44:58 +0800 Subject: [PATCH 002/105] fix: :bug: fix the bug about classVolume --- docs/GameRules.md | 2 +- docs/使用文档.md | 5 +++++ logic/Gaming/ActionManager.cs | 2 +- logic/Gaming/CharacterManager .cs | 4 ---- logic/README.md | 4 +++- resource/AIcpp.png | Bin 0 -> 56705 bytes resource/AIpy.png | Bin 0 -> 56955 bytes 7 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 resource/AIcpp.png create mode 100644 resource/AIpy.png diff --git a/docs/GameRules.md b/docs/GameRules.md index 39ad815..8586e40 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -1,5 +1,5 @@ # 规则 -V5.1 +V5.2 - [规则](#规则) - [简则](#简则) - [地图](#地图) diff --git a/docs/使用文档.md b/docs/使用文档.md index 3782837..2f1205e 100644 --- a/docs/使用文档.md +++ b/docs/使用文档.md @@ -6,6 +6,11 @@ ## 不应当使用Windows特性的库,不建议使用.h结尾的库,建议使用标准库 - 不要使用conio.h,Windows.h +## 请注意下载器不更新AI.py,AI.cpp和脚本 +- 最新版AI.cpp和AI.py +![AIcpp](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/AIcpp.png) +![AIpy](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/AIpy.png) + ## C++接口使用说明 - Windows:先查看`.\win\CAPI\cpp\`文件夹下是否有`lib`文件夹,没有则https://cloud.tsinghua.edu.cn/d/6972138f641d4e81a446/ 下载并复制粘贴 diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 7ad0e10..8c459ef 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -88,11 +88,11 @@ namespace Gaming finallyReturn: () => 0 ) .Start(); + --generatorForFix.NumOfFixing; } ) { IsBackground = true }.Start(); - --generatorForFix.NumOfFixing; return true; } diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs index f3cbd19..969d016 100644 --- a/logic/Gaming/CharacterManager .cs +++ b/logic/Gaming/CharacterManager .cs @@ -1,13 +1,9 @@ using System; using System.Threading; -using System.Collections.Generic; using GameClass.GameObj; using Preparation.Utility; -using GameEngine; using Preparation.Interface; using Timothy.FrameRateTask; -using System.Numerics; -using System.Timers; namespace Gaming { diff --git a/logic/README.md b/logic/README.md index 16d928e..ae46d6a 100644 --- a/logic/README.md +++ b/logic/README.md @@ -47,4 +47,6 @@ ## 开发人员 -- ......(自己加) \ No newline at end of file +- 黄淞:底层逻辑 +- 游笑权:Client +- 高思研:Server \ No newline at end of file diff --git a/resource/AIcpp.png b/resource/AIcpp.png new file mode 100644 index 0000000000000000000000000000000000000000..93f6b5d30e2b9f8de637ee41451a53774b56906c GIT binary patch literal 56705 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

v={TGuH|a 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 WeUFmcoXhJSJAcOXbdllJyZ;B`H!isV literal 0 HcmV?d00001 diff --git a/resource/AIpy.png b/resource/AIpy.png new file mode 100644 index 0000000000000000000000000000000000000000..1b0eb58667d51ec4e422cf8fe5afddb4f2d42bf7 GIT binary patch literal 56955 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≤+eZS1sU%adK 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 literal 0 HcmV?d00001 From f19be0308631652ac8829ae9da758a0f51a29503 Mon Sep 17 00:00:00 2001 From: xiangmy21 <90919434+xiangmy21@users.noreply.github.com> Date: Mon, 24 Apr 2023 16:25:58 +0800 Subject: [PATCH 003/105] Update compile.sh add file num to 5. check file existence. if cpp not exist, then check py, if py not exist either, compile failed. --- dependency/shell/compile.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dependency/shell/compile.sh b/dependency/shell/compile.sh index db2cac2..4e7b6f3 100644 --- a/dependency/shell/compile.sh +++ b/dependency/shell/compile.sh @@ -3,15 +3,19 @@ i=1 flag=1 bind=/usr/local/mnt -while (( $i <= 4 )) +while (( $i <= 5 )) do - mv -f $bind/player$i.cpp ./API/src/AI.cpp - cmake ./CMakeLists.txt && make >compile_log$i.txt 2>&1 - mv ./capi $bind/capi$i # executable file - if [ $? -ne 0 ]; then + if [ -f "${bind}/player${i}.cpp" ]; then + cp -f $bind/player$i.cpp ./API/src/AI.cpp + cmake ./CMakeLists.txt && make >compile_log$i.txt 2>&1 + mv ./capi $bind/capi$i # executable file + if [ $? -ne 0 ]; then + flag=0 + fi + mv ./compile_log$i.txt $bind/compile_log$i.txt + elif [ ! -f "${bind}/player${i}.py" ]; then flag=0 fi - mv ./compile_log$i.txt $bind/compile_log$i.txt let "i++" done # HTML request to update status. From 39b76ea847b57bc3bf65ed345b0949737f29dd27 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Mon, 24 Apr 2023 18:02:28 +0800 Subject: [PATCH 004/105] fix(CAPI): :bug: fix wrong gate view --- CAPI/cpp/API/src/logic.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 8baaee1..9431289 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -564,8 +564,9 @@ void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) } case THUAI6::MessageOfObj::GateMessage: { - if (!AssistFunction::HaveView(viewRange, x, y, item.gate_message().x(), item.gate_message().y(), bufferState->gameMap)) + if (AssistFunction::HaveView(viewRange, x, y, item.gate_message().x(), item.gate_message().y(), bufferState->gameMap)) { + std::cout << "x:" << item.gate_message().x() << "y:" << item.gate_message().y() << std::endl; auto pos = std::make_pair(AssistFunction::GridToCell(item.gate_message().x()), AssistFunction::GridToCell(item.gate_message().y())); if (bufferState->mapInfo->gateState.count(pos) == 0) { @@ -574,6 +575,11 @@ void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) } else { + if (playerID == 1) + { + std::cout << pos.first << pos.second << std::endl; + std::cout << "Update Gate!" << std::endl; + } bufferState->mapInfo->gateState[pos] = item.gate_message().progress(); logger->debug("Update Gate!"); } @@ -695,9 +701,7 @@ void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool f fileLogger->set_pattern(pattern); printLogger->set_pattern(pattern); if (file) - { - fileLogger->set_level(spdlog::level::trace); - } + fileLogger->set_level(spdlog::level::debug); else fileLogger->set_level(spdlog::level::off); if (print) From f995cdd800487c7ea90f50018c98e808b0ec655b Mon Sep 17 00:00:00 2001 From: DragonAura Date: Mon, 24 Apr 2023 18:03:30 +0800 Subject: [PATCH 005/105] fix(CAPI): :fire: fix wrong debug code --- CAPI/cpp/API/src/logic.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 9431289..82dab90 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -566,7 +566,6 @@ void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) { if (AssistFunction::HaveView(viewRange, x, y, item.gate_message().x(), item.gate_message().y(), bufferState->gameMap)) { - std::cout << "x:" << item.gate_message().x() << "y:" << item.gate_message().y() << std::endl; auto pos = std::make_pair(AssistFunction::GridToCell(item.gate_message().x()), AssistFunction::GridToCell(item.gate_message().y())); if (bufferState->mapInfo->gateState.count(pos) == 0) { @@ -575,11 +574,6 @@ void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) } else { - if (playerID == 1) - { - std::cout << pos.first << pos.second << std::endl; - std::cout << "Update Gate!" << std::endl; - } bufferState->mapInfo->gateState[pos] = item.gate_message().progress(); logger->debug("Update Gate!"); } From 0f46fb20a0da5ebf9bb49d29f541fede13406a35 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Mon, 24 Apr 2023 20:08:12 +0800 Subject: [PATCH 006/105] fix(CAPI): :bug: fix wrong __init__ --- CAPI/python/PyAPI/AI.py | 2 +- CAPI/python/PyAPI/State.py | 30 +++++++---- CAPI/python/PyAPI/structures.py | 91 +++++++++++++++++++++++++++++---- CAPI/python/PyAPI/utils.py | 6 --- CAPI/python/run.sh | 10 ++-- 5 files changed, 108 insertions(+), 31 deletions(-) diff --git a/CAPI/python/PyAPI/AI.py b/CAPI/python/PyAPI/AI.py index 010a3dc..efa1a1a 100644 --- a/CAPI/python/PyAPI/AI.py +++ b/CAPI/python/PyAPI/AI.py @@ -11,7 +11,7 @@ class Setting: # 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新 @staticmethod def asynchronous() -> bool: - return True + return False # 选手需要依次将player0到player4的职业都定义 @staticmethod diff --git a/CAPI/python/PyAPI/State.py b/CAPI/python/PyAPI/State.py index f2eb339..d493617 100644 --- a/CAPI/python/PyAPI/State.py +++ b/CAPI/python/PyAPI/State.py @@ -3,21 +3,33 @@ import PyAPI.structures as THUAI6 class State: + def __init__(self, **kwargs) -> None: + self.teamScore = 0 + self.self = THUAI6.Student() + self.students = [] + self.trickers = [] + self.props = [] + self.gameMap = [] + self.bullets = [] + self.bombedBullets = [] + self.mapInfo = THUAI6.GameMap() + self.gameInfo = THUAI6.GameInfo() + self.guids = [] teamScore: int self: Union[THUAI6.Student, THUAI6.Tricker] - students: List[THUAI6.Student] = [] - trickers: List[THUAI6.Tricker] = [] + students: List[THUAI6.Student] + trickers: List[THUAI6.Tricker] - props: List[THUAI6.Prop] = [] + props: List[THUAI6.Prop] - gameMap: List[List[THUAI6.PlaceType]] = [] + gameMap: List[List[THUAI6.PlaceType]] - bullets: List[THUAI6.Bullet] = [] - bombedBullets: List[THUAI6.BombedBullet] = [] + bullets: List[THUAI6.Bullet] + bombedBullets: List[THUAI6.BombedBullet] - mapInfo: THUAI6.GameMap = THUAI6.GameMap() + mapInfo: THUAI6.GameMap - gameInfo: THUAI6.GameInfo = THUAI6.GameInfo() + gameInfo: THUAI6.GameInfo - guids: List[int] = [] + guids: List[int] diff --git a/CAPI/python/PyAPI/structures.py b/CAPI/python/PyAPI/structures.py index 939f452..d37e607 100644 --- a/CAPI/python/PyAPI/structures.py +++ b/CAPI/python/PyAPI/structures.py @@ -143,6 +143,22 @@ class HiddenGateState(Enum): class Player: + def __init__(self, **kwargs) -> None: + self.x = 0 + self.y = 0 + self.speed = 0 + self.viewRange = 0 + self.playerID = 0 + self.guid = 0 + self.radius = 0 + self.score = 0 + self.facingDirection = 0.0 + self.timeUntilSkillAvailable = [] + self.playerType = PlayerType.NullPlayerType + self.prop = [] + self.place = PlaceType.NullPlaceType + self.bulletType = BulletType.NullBulletType + self.playerState = PlayerState.NullState x: int y: int speed: int @@ -152,15 +168,26 @@ class Player: radius: int score: int facingDirection: float - timeUntilSkillAvailable: List[float] = [] + timeUntilSkillAvailable: List[float] playerType: PlayerType - prop: List[PropType] = [] + prop: List[PropType] place: PlaceType bulletType: BulletType playerState: PlayerState class Student(Player): + def __init__(self, **kwargs) -> None: + super().__init__() + self.studentType = StudentType.NullStudentType + self.determination = 0 + self.addiction = 0 + self.encourageProgress = 0 + self.rouseProgress = 0 + self.learningSpeed = 0 + self.encourageSpeed = 0 + self.dangerAlert = 0.0 + self.buff = [] studentType: StudentType determination: int addiction: int @@ -169,17 +196,30 @@ class Student(Player): learningSpeed: int encourageSpeed: int dangerAlert: float - buff: List[StudentBuffType] = [] + buff: List[StudentBuffType] class Tricker(Player): + def __init__(self, **kwargs) -> None: + super().__init__() + self.trickerType = TrickerType.NullTrickerType + self.trickDesire = 0.0 + self.classVolume = 0.0 + self.buff = [] trickerType: TrickerType trickDesire: float classVolume: float - buff: List[TrickerBuffType] = [] + buff: List[TrickerBuffType] class Prop: + def __init__(self, **kwargs) -> None: + self.x = 0 + self.y = 0 + self.guid = 0 + self.type = PropType.NullPropType + self.place = PlaceType.NullPlaceType + self.facingDirection = 0.0 x: int y: int guid: int @@ -189,6 +229,16 @@ class Prop: class Bullet: + def __init__(self, **kwargs) -> None: + self.bulletType = BulletType.NullBulletType + self.x = 0 + self.y = 0 + self.facingDirection = 0.0 + self.guid = 0 + self.team = PlayerType.NullPlayerType + self.place = PlaceType.NullPlaceType + self.bombRange = 0.0 + self.speed = 0 bulletType: BulletType x: int y: int @@ -201,6 +251,13 @@ class Bullet: class BombedBullet: + def __init__(self, **kwargs) -> None: + self.bulletType = BulletType.NullBulletType + self.x = 0 + self.y = 0 + self.facingDirection = 0.0 + self.mappingID = 0 + self.bombRange = 0.0 bulletType: BulletType x: int y: int @@ -210,15 +267,29 @@ class BombedBullet: class GameMap: - classroomState: Dict[Tuple[int, int], int] = {} - gateState: Dict[Tuple[int, int], int] = {} - chestState: Dict[Tuple[int, int], int] = {} - doorState: Dict[Tuple[int, int], bool] = {} - doorProgress: Dict[Tuple[int, int], int] = {} - hiddenGateState: Dict[Tuple[int, int], HiddenGateState] = {} + def __init__(self, **kwargs) -> None: + self.classroomState = {} + self.gateState = {} + self.chestState = {} + self.doorState = {} + self.doorProgress = {} + self.hiddenGateState = {} + classroomState: Dict[Tuple[int, int], int] + gateState: Dict[Tuple[int, int], int] + chestState: Dict[Tuple[int, int], int] + doorState: Dict[Tuple[int, int], bool] + doorProgress: Dict[Tuple[int, int], int] + hiddenGateState: Dict[Tuple[int, int], HiddenGateState] class GameInfo: + def __init__(self, **kwargs) -> None: + self.gameTime = 0 + self.subjectFinished = 0 + self.studentGraduated = 0 + self.studentQuited = 0 + self.studentScore = 0 + self.trickerScore = 0 gameTime: int subjectFinished: int studentGraduated: int diff --git a/CAPI/python/PyAPI/utils.py b/CAPI/python/PyAPI/utils.py index e286212..f713229 100644 --- a/CAPI/python/PyAPI/utils.py +++ b/CAPI/python/PyAPI/utils.py @@ -177,12 +177,10 @@ class Proto2THUAI6(NoInstance): tricker.trickDesire = trickerMsg.trick_desire tricker.classVolume = trickerMsg.class_volume tricker.bulletType = Proto2THUAI6.bulletTypeDict[trickerMsg.bullet_type] - tricker.timeUntilSkillAvailable.clear() for time in trickerMsg.time_until_skill_available: tricker.timeUntilSkillAvailable.append(time) tricker.place = Proto2THUAI6.placeTypeDict[trickerMsg.place] tricker.playerState = Proto2THUAI6.playerStateDict[trickerMsg.player_state] - tricker.prop.clear() for item in trickerMsg.prop: tricker.prop.append(Proto2THUAI6.propTypeDict[item]) tricker.trickerType = Proto2THUAI6.trickerTypeDict[trickerMsg.tricker_type] @@ -190,7 +188,6 @@ class Proto2THUAI6(NoInstance): tricker.playerID = trickerMsg.player_id tricker.viewRange = trickerMsg.view_range tricker.radius = trickerMsg.radius - tricker.buff.clear() for buff in trickerMsg.buff: tricker.buff.append(Proto2THUAI6.trickerBuffTypeDict[buff]) tricker.playerType = THUAI6.PlayerType.TrickerPlayer @@ -212,11 +209,9 @@ class Proto2THUAI6(NoInstance): student.encourageProgress = studentMsg.treat_progress student.rouseProgress = studentMsg.rescue_progress student.dangerAlert = studentMsg.danger_alert - student.timeUntilSkillAvailable.clear() for time in studentMsg.time_until_skill_available: student.timeUntilSkillAvailable.append(time) student.place = Proto2THUAI6.placeTypeDict[studentMsg.place] - student.prop.clear() for item in studentMsg.prop: student.prop.append(Proto2THUAI6.propTypeDict[item]) student.studentType = Proto2THUAI6.studentTypeDict[studentMsg.student_type] @@ -225,7 +220,6 @@ class Proto2THUAI6(NoInstance): student.playerID = studentMsg.player_id student.viewRange = studentMsg.view_range student.radius = studentMsg.radius - student.buff.clear() for buff in studentMsg.buff: student.buff.append(Proto2THUAI6.studentBuffTypeDict[buff]) student.playerType = THUAI6.PlayerType.StudentPlayer diff --git a/CAPI/python/run.sh b/CAPI/python/run.sh index f41c458..5efb5a6 100755 --- a/CAPI/python/run.sh +++ b/CAPI/python/run.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 0 -d -o & -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 1 -d & -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 2 -d & -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 3 -d & -# python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 4 -d & \ No newline at end of file +python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 0 -d -o& +python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 1& +# python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 2& +# python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 3& +# python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 4& \ No newline at end of file From 905416f0a414f379691493f34a0dcc3f39934a14 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Mon, 24 Apr 2023 20:25:38 +0800 Subject: [PATCH 007/105] fix(CAPI): :bug: fix wrong static variable --- CAPI/python/PyAPI/Communication.py | 8 +- CAPI/python/PyAPI/structures.py | 183 ++++++++++------------------- 2 files changed, 62 insertions(+), 129 deletions(-) diff --git a/CAPI/python/PyAPI/Communication.py b/CAPI/python/PyAPI/Communication.py index e3b5960..336ee60 100644 --- a/CAPI/python/PyAPI/Communication.py +++ b/CAPI/python/PyAPI/Communication.py @@ -16,19 +16,13 @@ class BoolErrorHandler(IErrorHandler): class Communication: - - __THUAI6Stub: Services.AvailableServiceStub - __haveNewMessage: bool - __message2Client: Message2Clients.MessageToClient - __mtxMessage: threading.Lock - __cvMessage: threading.Condition - def __init__(self, sIP: str, sPort: str): aim = sIP + ':' + sPort channel = grpc.insecure_channel(aim) self.__THUAI6Stub = Services.AvailableServiceStub(channel) self.__haveNewMessage = False self.__cvMessage = threading.Condition() + self.__message2Client: Message2Clients.MessageToClient def Move(self, time: int, angle: float, playerID: int) -> bool: try: diff --git a/CAPI/python/PyAPI/structures.py b/CAPI/python/PyAPI/structures.py index d37e607..72e61b4 100644 --- a/CAPI/python/PyAPI/structures.py +++ b/CAPI/python/PyAPI/structures.py @@ -144,155 +144,94 @@ class HiddenGateState(Enum): class Player: def __init__(self, **kwargs) -> None: - self.x = 0 - self.y = 0 - self.speed = 0 - self.viewRange = 0 - self.playerID = 0 - self.guid = 0 - self.radius = 0 - self.score = 0 - self.facingDirection = 0.0 - self.timeUntilSkillAvailable = [] - self.playerType = PlayerType.NullPlayerType - self.prop = [] - self.place = PlaceType.NullPlaceType - self.bulletType = BulletType.NullBulletType - self.playerState = PlayerState.NullState - x: int - y: int - speed: int - viewRange: int - playerID: int - guid: int - radius: int - score: int - facingDirection: float - timeUntilSkillAvailable: List[float] - playerType: PlayerType - prop: List[PropType] - place: PlaceType - bulletType: BulletType - playerState: PlayerState + self.x: int = 0 + self.y: int = 0 + self.speed: int = 0 + self.viewRange: int = 0 + self.playerID: int = 0 + self.guid: int = 0 + self.radius: int = 0 + self.score: int = 0 + self.facingDirection: float = 0.0 + self.timeUntilSkillAvailable: List[float] = [] + self.playerType: PlayerType = PlayerType.NullPlayerType + self.prop: List[PropType] = [] + self.place: PlaceType = PlaceType.NullPlaceType + self.bulletType: BulletType = BulletType.NullBulletType + self.playerState: PlayerState = PlayerState.NullState class Student(Player): def __init__(self, **kwargs) -> None: super().__init__() - self.studentType = StudentType.NullStudentType - self.determination = 0 - self.addiction = 0 - self.encourageProgress = 0 - self.rouseProgress = 0 - self.learningSpeed = 0 - self.encourageSpeed = 0 - self.dangerAlert = 0.0 - self.buff = [] - studentType: StudentType - determination: int - addiction: int - encourageProgress: int - rouseProgress: int - learningSpeed: int - encourageSpeed: int - dangerAlert: float - buff: List[StudentBuffType] + self.studentType: StudentType = StudentType.NullStudentType + self.determination: int = 0 + self.addiction: int = 0 + self.encourageProgress: int = 0 + self.rouseProgress: int = 0 + self.learningSpeed: int = 0 + self.encourageSpeed: int = 0 + self.dangerAlert: float = 0.0 + self.buff: List[StudentBuffType] = [] class Tricker(Player): def __init__(self, **kwargs) -> None: super().__init__() - self.trickerType = TrickerType.NullTrickerType - self.trickDesire = 0.0 - self.classVolume = 0.0 - self.buff = [] - trickerType: TrickerType - trickDesire: float - classVolume: float - buff: List[TrickerBuffType] + self.trickerType: TrickerType = TrickerType.NullTrickerType + self.trickDesire: float = 0.0 + self.classVolume: float = 0.0 + self.buff: List[TrickerBuffType] = [] class Prop: def __init__(self, **kwargs) -> None: - self.x = 0 - self.y = 0 - self.guid = 0 - self.type = PropType.NullPropType - self.place = PlaceType.NullPlaceType - self.facingDirection = 0.0 - x: int - y: int - guid: int - type: PropType - place: PlaceType - facingDirection: float + self.x: int = 0 + self.y: int = 0 + self.guid: int = 0 + self.type: PropType = PropType.NullPropType + self.place: PlaceType = PlaceType.NullPlaceType + self.facingDirection: float = 0.0 class Bullet: def __init__(self, **kwargs) -> None: - self.bulletType = BulletType.NullBulletType - self.x = 0 - self.y = 0 - self.facingDirection = 0.0 - self.guid = 0 - self.team = PlayerType.NullPlayerType - self.place = PlaceType.NullPlaceType - self.bombRange = 0.0 - self.speed = 0 - bulletType: BulletType - x: int - y: int - facingDirection: float - guid: int - team: PlayerType - place: PlaceType - bombRange: float - speed: int + self.bulletType: BulletType = BulletType.NullBulletType + self.x: int = 0 + self.y: int = 0 + self.facingDirection: float = 0.0 + self.guid: int = 0 + self.team: PlayerType = PlayerType.NullPlayerType + self.place: PlaceType = PlaceType.NullPlaceType + self.bombRange: float = 0.0 + self.speed: int = 0 class BombedBullet: def __init__(self, **kwargs) -> None: - self.bulletType = BulletType.NullBulletType - self.x = 0 - self.y = 0 - self.facingDirection = 0.0 - self.mappingID = 0 - self.bombRange = 0.0 - bulletType: BulletType - x: int - y: int - facingDirection: float - mappingID: int - bombRange: float + self.bulletType: BulletType = BulletType.NullBulletType + self.x: int = 0 + self.y: int = 0 + self.facingDirection: float = 0.0 + self.mappingID: int = 0 + self.bombRange: float = 0.0 class GameMap: def __init__(self, **kwargs) -> None: - self.classroomState = {} - self.gateState = {} - self.chestState = {} - self.doorState = {} - self.doorProgress = {} - self.hiddenGateState = {} - classroomState: Dict[Tuple[int, int], int] - gateState: Dict[Tuple[int, int], int] - chestState: Dict[Tuple[int, int], int] - doorState: Dict[Tuple[int, int], bool] - doorProgress: Dict[Tuple[int, int], int] - hiddenGateState: Dict[Tuple[int, int], HiddenGateState] + self.classroomState: Dict[Tuple[int, int], int] = {} + self.gateState: Dict[Tuple[int, int], int] = {} + self.chestState: Dict[Tuple[int, int], int] = {} + self.doorState: Dict[Tuple[int, int], bool] = {} + self.doorProgress: Dict[Tuple[int, int], int] = {} + self.hiddenGateState: Dict[Tuple[int, int], HiddenGateState] = {} class GameInfo: def __init__(self, **kwargs) -> None: - self.gameTime = 0 - self.subjectFinished = 0 - self.studentGraduated = 0 - self.studentQuited = 0 - self.studentScore = 0 - self.trickerScore = 0 - gameTime: int - subjectFinished: int - studentGraduated: int - studentQuited: int - studentScore: int - trickerScore: int + self.gameTime: int = 0 + self.subjectFinished: int = 0 + self.studentGraduated: int = 0 + self.studentQuited: int = 0 + self.studentScore: int = 0 + self.trickerScore: int = 0 From 578f00b2833289a1152c50ab65b9313ec1dca336 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Mon, 24 Apr 2023 20:53:45 +0800 Subject: [PATCH 008/105] docs: :memo: update capi docs --- docs/CAPI接口(cpp).md | 12 ++++++------ docs/CAPI接口(python).md | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/CAPI接口(cpp).md b/docs/CAPI接口(cpp).md index e92367a..b7f4087 100644 --- a/docs/CAPI接口(cpp).md +++ b/docs/CAPI接口(cpp).md @@ -13,9 +13,9 @@ #### 人物 - `std::future EndAllAction()`:可以使不处在不可行动状态中的玩家终止当前行动 -- 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出Stop指令终止进行的指令 +- 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出 Stop 指令终止进行的指令 - 实际上唤醒或勉励不同的人是有效的 -- EndAllAction()及Move指令调用数总和一帧内不超过10次 +- EndAllAction() 及 Move 指令调用数总和一帧内不超过 10 次 #### 攻击 - `std::future Attack(double angleInRadian)`:`angleInRadian`为攻击方向 @@ -59,7 +59,7 @@ - `THUAI6::PlaceType GetPlaceType(int32_t cellX, int32_t cellY)` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - `bool IsDoorOpen(int32_t cellX, int32_t cellY) const`:查询特定位置门是否开启,没有门也返回false - - 以下指令特定位置没有对应物品返回-1 + - 以下指令,若查询物品当前在视野内,则返回最新进度;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 - `int32_t GetChestProgress(int32_t cellX, int32_t cellY) const`:查询特定位置箱子开启进度 - `int32_t GetGateProgress(int32_t cellX, int32_t cellY) const`:查询特定位置校门开启进度 - `int32_t GetClassroomProgress(int32_t cellX, int32_t cellY) const`:查询特定位置教室作业完成进度 @@ -74,9 +74,9 @@ - `std::vector> GetFullMap() const`:返回整张地图的地形信息。可以写成类似`api.GetFullMap()[x][y]`,其中x为地图自上到下第几行,y为自左向右第几列,注意从0开始 ### 辅助函数 -`static inline int CellToGrid(int cell) noexcept`:将地图格数 cell 转换为绝对坐标grid。 +`static inline int CellToGrid(int cell) noexcept`:将地图格数 cell 转换为绝对坐标 grid。 -`static inline int GridToCell(int grid) noexcept`:将绝对坐标 grid 转换为地图格数cell。 +`static inline int GridToCell(int grid) noexcept`:将绝对坐标 grid 转换为地图格数 cell。 下面为用于DEBUG的输出函数,选手仅在开启Debug模式的情况下可以使用 ~~~c++ @@ -126,7 +126,7 @@ // 获取视野内可见的道具信息 [[nodiscard]] virtual std::vector> GetProps() const = 0; - // 获取地图信息,视野外的地图统一为Land + // 获取地图信息 [[nodiscard]] virtual std::vector> GetFullMap() const = 0; [[nodiscard]] virtual THUAI6::PlaceType GetPlaceType(int32_t cellX, int32_t cellY) const = 0; diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index 84d2c82..e470ac2 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -8,7 +8,7 @@ #### 移动 -- `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为x轴,水平向右方向为y轴**因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 +- `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为 x 轴,水平向右方向为 y 轴**因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 - `def MoveRight(self, timeInMilliseconds: int) -> Future[bool]`即向右移动,`MoveLeft`、`MoveDown`、`MoveUp`同理 #### 使用技能 @@ -18,9 +18,9 @@ #### 人物 - `def EndAllAction(self) -> Future[bool]`:可以使不处在不可行动状态中的玩家终止当前行动 -- 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出Stop指令终止进行的指令 +- 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出 Stop 指令终止进行的指令 - 实际上唤醒或勉励不同的人是有效的 -- EndAllAction()及Move指令调用数总和一帧内不超过10次 +- EndAllAction() 及 Move 指令调用数总和一帧内不超过 10 次 #### 攻击 @@ -34,8 +34,8 @@ #### 勉励与唤醒 -- `def StartEncourageMate(self, mateID: int) -> Future[bool]`:勉励对应玩家ID的学生。 -- `def StartRouseMate(self, mateID: int) -> Future[bool]`:唤醒对应玩家ID的沉迷的学生。 +- `def StartEncourageMate(self, mateID: int) -> Future[bool]`:勉励对应玩家 ID 的学生。 +- `def StartRouseMate(self, mateID: int) -> Future[bool]`:唤醒对应玩家 ID 的沉迷的学生。 #### 地图互动 @@ -71,13 +71,13 @@ - `def GetPlaceType(self, cellX: int, cellY: int) -> THUAI6.PlaceType` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - `def IsDoorOpen(self, cellX: int, cellY: int) -> bool`:查询特定位置门是否开启,没有门也返回false - - 以下指令特定位置没有对应物品返回-1 + - 以下指令,若查询物品当前在视野内,则返回最新进度;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 - `def GetChestProgress(self, cellX: int, cellY: int) -> int`:查询特定位置箱子开启进度 - `def GetGateProgress(self, cellX: int, cellY: int) -> int`:查询特定位置校门开启进度 - `def GetClassroomProgress(self, cellX: int, cellY: int) -> int`:查询特定位置教室作业完成进度 - `def GetDoorProgress(self, cellX: int, cellY: int) -> int`:查询特定位置门开启状态 - `def GetHiddenGateState(self, cellX: int, cellY: int) -> THUAI6.HiddenGateState`::查询特定位置隐藏校门状态,没有隐藏校门返回THUAI6::HiddenGateState::Null - + #### 其他 @@ -89,11 +89,11 @@ ### 辅助函数 -`def CellToGrid(cell: int) -> int`:将地图格数 cell 转换为绝对坐标grid。 +`def CellToGrid(cell: int) -> int`:将地图格数 cell 转换为绝对坐标 grid。 -`def GridToCell(grid: int) -> int`:将绝对坐标 grid 转换为地图格数cell。 +`def GridToCell(grid: int) -> int`:将绝对坐标 grid 转换为地图格数 cell。 -下面为用于DEBUG的输出函数,选手仅在开启Debug模式的情况下可以使用 +下面为用于DEBUG的输出函数,选手仅在开启 Debug 模式的情况下可以使用 ~~~python def Print(self, cont: str) -> None: From 05a251d881a790bd6dd8c56a282b17899c387d30 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Mon, 24 Apr 2023 21:23:46 +0800 Subject: [PATCH 009/105] fix: :bug: fix the bug about NumOfRepairedGenerators --- logic/GameClass/GameObj/Map/Generator.cs | 2 +- logic/Gaming/ActionManager.cs | 5 ++--- logic/Gaming/CharacterManager .cs | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/logic/GameClass/GameObj/Map/Generator.cs b/logic/GameClass/GameObj/Map/Generator.cs index 4718f65..d982161 100644 --- a/logic/GameClass/GameObj/Map/Generator.cs +++ b/logic/GameClass/GameObj/Map/Generator.cs @@ -46,7 +46,7 @@ namespace GameClass.GameObj public bool Repair(int addDegree, Character character) { - if (DegreeOfRepair == GameData.degreeOfFixedGenerator) return true; + if (DegreeOfRepair == GameData.degreeOfFixedGenerator) return false; int orgDegreeOfRepair = degreeOfRepair; DegreeOfRepair += addDegree; if (DegreeOfRepair > orgDegreeOfRepair) diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 8c459ef..b4f88fb 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -79,10 +79,9 @@ namespace Gaming loopToDo: () => { if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) - { - characterManager.SetPlayerState(player); gameMap.NumOfRepairedGenerators++; - } + if (generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator) + characterManager.SetPlayerState(player); }, timeInterval: GameData.frameDuration, finallyReturn: () => 0 diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs index 969d016..6d61367 100644 --- a/logic/Gaming/CharacterManager .cs +++ b/logic/Gaming/CharacterManager .cs @@ -397,8 +397,10 @@ namespace Gaming ((SummonGolem)(((Golem)player).Parent.FindIActiveSkill(ActiveSkillType.SummonGolem))).GolemSummoned = null; player.FindIActiveSkill(ActiveSkillType.UseRobot).IsBeingUsed = false; } + gameMap.Remove(player); return; } + gameMap.Remove(player); ++gameMap.NumOfDeceasedStudent; } From 155434661326f35cc65bad40884a70b60001fe6f Mon Sep 17 00:00:00 2001 From: DragonAura Date: Mon, 24 Apr 2023 21:30:24 +0800 Subject: [PATCH 010/105] feat(CAPI): :sparkles: add have view in capi --- CAPI/cpp/API/include/API.h | 12 ++++++++++++ CAPI/cpp/API/include/logic.h | 2 ++ CAPI/cpp/API/src/API.cpp | 12 ++++++++++++ CAPI/cpp/API/src/DebugAPI.cpp | 12 ++++++++++++ CAPI/cpp/API/src/logic.cpp | 5 +++++ CAPI/python/PyAPI/API.py | 6 ++++++ CAPI/python/PyAPI/DebugAPI.py | 6 ++++++ CAPI/python/PyAPI/Interface.py | 8 ++++++++ CAPI/python/PyAPI/logic.py | 3 +++ CAPI/python/run.sh | 2 +- 10 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CAPI/cpp/API/include/API.h b/CAPI/cpp/API/include/API.h index 75824ae..1b89718 100644 --- a/CAPI/cpp/API/include/API.h +++ b/CAPI/cpp/API/include/API.h @@ -83,6 +83,8 @@ public: virtual bool Attack(double angle) = 0; virtual std::vector GetPlayerGUIDs() const = 0; + + [[nodiscard]] virtual bool HaveView(int gridX, int gridY, int selfX, int selfY, int viewRange) const = 0; }; class IAPI @@ -162,6 +164,8 @@ public: return grid / numOfGridPerCell; } + [[nodiscard]] virtual bool HaveView(int gridX, int gridY) const = 0; + // 用于DEBUG的输出函数,选手仅在开启Debug模式的情况下可以使用 virtual void Print(std::string str) const = 0; @@ -271,6 +275,8 @@ public: std::future Graduate() override; [[nodiscard]] std::shared_ptr GetSelfInfo() const override; + [[nodiscard]] bool HaveView(int gridX, int gridY) const override; + void Print(std::string str) const override { } @@ -356,6 +362,8 @@ public: std::future Attack(double angleInRadian) override; [[nodiscard]] std::shared_ptr GetSelfInfo() const override; + [[nodiscard]] bool HaveView(int gridX, int gridY) const override; + void Print(std::string str) const override { } @@ -439,6 +447,8 @@ public: std::future Graduate() override; [[nodiscard]] virtual std::shared_ptr GetSelfInfo() const override; + [[nodiscard]] bool HaveView(int gridX, int gridY) const override; + void Print(std::string str) const override; void PrintStudent() const override; void PrintTricker() const override; @@ -509,6 +519,8 @@ public: std::future Attack(double angleInRadian) override; [[nodiscard]] std::shared_ptr GetSelfInfo() const override; + [[nodiscard]] bool HaveView(int gridX, int gridY) const override; + void Print(std::string str) const override; void PrintStudent() const override; void PrintTricker() const override; diff --git a/CAPI/cpp/API/include/logic.h b/CAPI/cpp/API/include/logic.h index 7bd8d1a..5ca41ea 100644 --- a/CAPI/cpp/API/include/logic.h +++ b/CAPI/cpp/API/include/logic.h @@ -161,6 +161,8 @@ private: // 等待 void Wait() noexcept; + [[nodiscard]] bool HaveView(int gridX, int gridY, int selfX, int selfY, int viewRange) const override; + public: // 构造函数还需要传更多参数,有待补充 Logic(THUAI6::PlayerType type, int64_t ID, THUAI6::TrickerType tricker, THUAI6::StudentType student); diff --git a/CAPI/cpp/API/src/API.cpp b/CAPI/cpp/API/src/API.cpp index 9b4693a..895abcd 100644 --- a/CAPI/cpp/API/src/API.cpp +++ b/CAPI/cpp/API/src/API.cpp @@ -419,6 +419,18 @@ std::shared_ptr TrickerAPI::GetSelfInfo() const return logic.TrickerGetSelfInfo(); } +bool StudentAPI::HaveView(int gridX, int gridY) const +{ + auto selfInfo = GetSelfInfo(); + return logic.HaveView(gridX, gridY, selfInfo->x, selfInfo->y, selfInfo->viewRange); +} + +bool TrickerAPI::HaveView(int gridX, int gridY) const +{ + auto selfInfo = GetSelfInfo(); + return logic.HaveView(gridX, gridY, selfInfo->x, selfInfo->y, selfInfo->viewRange); +} + void StudentAPI::Play(IAI& ai) { ai.play(*this); diff --git a/CAPI/cpp/API/src/DebugAPI.cpp b/CAPI/cpp/API/src/DebugAPI.cpp index 8aa3165..fdeb857 100644 --- a/CAPI/cpp/API/src/DebugAPI.cpp +++ b/CAPI/cpp/API/src/DebugAPI.cpp @@ -631,6 +631,18 @@ std::shared_ptr TrickerDebugAPI::GetSelfInfo() const return logic.TrickerGetSelfInfo(); } +bool StudentDebugAPI::HaveView(int gridX, int gridY) const +{ + auto selfInfo = GetSelfInfo(); + return logic.HaveView(gridX, gridY, selfInfo->x, selfInfo->y, selfInfo->viewRange); +} + +bool TrickerDebugAPI::HaveView(int gridX, int gridY) const +{ + auto selfInfo = GetSelfInfo(); + return logic.HaveView(gridX, gridY, selfInfo->x, selfInfo->y, selfInfo->viewRange); +} + void StudentDebugAPI::Print(std::string str) const { logger->info(str); diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 82dab90..13c174b 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -686,6 +686,11 @@ bool Logic::TryConnection() return pComm->TryConnection(playerID); } +bool Logic::HaveView(int gridX, int gridY, int selfX, int selfY, int viewRange) const +{ + return AssistFunction::HaveView(viewRange, selfX, selfY, gridX, gridY, currentState->gameMap); +} + void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool file, bool print, bool warnOnly) { // 建立日志组件 diff --git a/CAPI/python/PyAPI/API.py b/CAPI/python/PyAPI/API.py index 2ce4506..7a67a76 100644 --- a/CAPI/python/PyAPI/API.py +++ b/CAPI/python/PyAPI/API.py @@ -132,6 +132,9 @@ class StudentAPI(IStudentAPI, IGameTimer): def GetGameInfo(self) -> THUAI6.GameInfo: return self.__logic.GetGameInfo() + def HaveView(self, gridX: int, gridY: int) -> bool: + return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange) + # 用于DEBUG的输出函数,仅在DEBUG模式下有效 def Print(self, cont: str) -> None: @@ -305,6 +308,9 @@ class TrickerAPI(ITrickerAPI, IGameTimer): def GetGameInfo(self) -> THUAI6.GameInfo: return self.__logic.GetGameInfo() + def HaveView(self, gridX: int, gridY: int) -> bool: + return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange) + # 用于DEBUG的输出函数,仅在DEBUG模式下有效 def Print(self, cont: str) -> None: diff --git a/CAPI/python/PyAPI/DebugAPI.py b/CAPI/python/PyAPI/DebugAPI.py index a784026..f175553 100644 --- a/CAPI/python/PyAPI/DebugAPI.py +++ b/CAPI/python/PyAPI/DebugAPI.py @@ -304,6 +304,9 @@ class StudentDebugAPI(IStudentAPI, IGameTimer): def GetGameInfo(self) -> THUAI6.GameInfo: return self.__logic.GetGameInfo() + def HaveView(self, gridX: int, gridY: int) -> bool: + return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange) + # 用于DEBUG的输出函数,仅在DEBUG模式下有效 def Print(self, cont: str) -> None: @@ -756,6 +759,9 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer): def GetGameInfo(self) -> THUAI6.GameInfo: return self.__logic.GetGameInfo() + def HaveView(self, gridX: int, gridY: int) -> bool: + return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange) + # 用于DEBUG的输出函数,仅在DEBUG模式下有效 def Print(self, cont: str) -> None: diff --git a/CAPI/python/PyAPI/Interface.py b/CAPI/python/PyAPI/Interface.py index 4d38060..3045877 100644 --- a/CAPI/python/PyAPI/Interface.py +++ b/CAPI/python/PyAPI/Interface.py @@ -154,6 +154,10 @@ class ILogic(metaclass=ABCMeta): def StartRouseMate(self, mateID: int) -> bool: pass + @abstractmethod + def HaveView(self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int) -> bool: + pass + class IAPI(metaclass=ABCMeta): @@ -314,6 +318,10 @@ class IAPI(metaclass=ABCMeta): def GetGameInfo(self) -> THUAI6.GameInfo: pass + @abstractmethod + def HaveView(self, gridX: int, gridY: int) -> bool: + pass + # 用于DEBUG的输出函数,仅在DEBUG模式下有效 @abstractmethod diff --git a/CAPI/python/PyAPI/logic.py b/CAPI/python/PyAPI/logic.py index 1907451..65af3bb 100644 --- a/CAPI/python/PyAPI/logic.py +++ b/CAPI/python/PyAPI/logic.py @@ -262,6 +262,9 @@ class Logic(ILogic): self.__logger.debug("Called EndAllAction") return self.__comm.EndAllAction(self.__playerID) + def HaveView(self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int) -> bool: + return AssistFunction.HaveView(viewRange, selfX, selfY, gridX, gridY, self.__currentState.gameMap) + # Logic内部逻辑 def __TryConnection(self) -> bool: self.__logger.info("Try to connect to server...") diff --git a/CAPI/python/run.sh b/CAPI/python/run.sh index 5efb5a6..f0ff428 100755 --- a/CAPI/python/run.sh +++ b/CAPI/python/run.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 0 -d -o& -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 1& +python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 1 -o& # python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 2& # python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 3& # python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 4& \ No newline at end of file From d06602c127f4110cbc313ef547bddeaa9071b096 Mon Sep 17 00:00:00 2001 From: Tian Guoyun <88619302+BlitherBoom812@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:46:23 +0800 Subject: [PATCH 011/105] Update run.sh --- dependency/shell/run.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index b84bfbc..3a38a95 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -9,7 +9,7 @@ do for i in {1..4} do j=$((i - 1)) - if [-f "./python/player$i.py"]; then + if [ -f "./python/player$i.py" ]; then nice -0 python3 ./python/player$i.py -I 127.0.0.1 -P 8888 -p $j elif [-f "./capi$i"]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j @@ -21,9 +21,9 @@ do for i in {5..5} do j=$((i - 1)) - if [-f "./python/player$i.py"]; then + if [ -f "./python/player$i.py" ]; then nice -0 python3 ./python/player$i.py -I 127.0.0.1 -P 8888 -p $j - elif [-f "./capi$i"]; then + elif [ -f "./capi$i" ]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j else echo "ERROR. $i is not found." From ce89152021e9f4a5e2afb4221c2e3d4292535ff4 Mon Sep 17 00:00:00 2001 From: Tian Guoyun <88619302+BlitherBoom812@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:51:18 +0800 Subject: [PATCH 012/105] Update run.sh --- dependency/shell/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 3a38a95..86a88bb 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -11,7 +11,7 @@ do j=$((i - 1)) if [ -f "./python/player$i.py" ]; then nice -0 python3 ./python/player$i.py -I 127.0.0.1 -P 8888 -p $j - elif [-f "./capi$i"]; then + elif [ -f "./capi$i" ]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j else echo "ERROR. $i is not found." From 38de6c480bc5c6775cc01cf40b2a3dc9a9022d28 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Mon, 24 Apr 2023 22:06:49 +0800 Subject: [PATCH 013/105] fix: :bug: fix the bug about Removing --- logic/GameClass/GameObj/Map/Map.cs | 9 +++++---- logic/Gaming/CharacterManager .cs | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 1ca3ec9..1a5eafa 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -203,7 +203,7 @@ namespace GameClass.GameObj } public bool Remove(GameObj gameObj) { - bool flag = false; + GameObj? ToDel = null; GameObjLockDict[gameObj.Type].EnterWriteLock(); try { @@ -211,8 +211,7 @@ namespace GameClass.GameObj { if (gameObj.ID == obj.ID) { - GameObjDict[gameObj.Type].Remove(obj); - flag = true; + ToDel = obj; break; } } @@ -221,7 +220,9 @@ namespace GameClass.GameObj { GameObjLockDict[gameObj.Type].ExitWriteLock(); } - return flag; + if (ToDel == null) return false; + GameObjDict[gameObj.Type].Remove(ToDel); + return true; } public bool RemoveJustFromMap(GameObj gameObj) { diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs index 6d61367..7f15d59 100644 --- a/logic/Gaming/CharacterManager .cs +++ b/logic/Gaming/CharacterManager .cs @@ -379,6 +379,7 @@ namespace Gaming #if DEBUG Debugger.Output(player, "die."); #endif + if (player.PlayerState == PlayerStateType.Deceased) return; player.RemoveFromGame(PlayerStateType.Deceased); for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++) From b1513c772a934747458645e82c4e68ff57f14dec Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Mon, 24 Apr 2023 22:50:01 +0800 Subject: [PATCH 014/105] Update run.sh --- dependency/shell/run.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 86a88bb..3d63212 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -1,6 +1,8 @@ #!/usr/local -nice -10 ./Server/Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN +python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI + +nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN sleep 5 for k in {1..2} do @@ -9,8 +11,9 @@ do for i in {1..4} do j=$((i - 1)) - if [ -f "./python/player$i.py" ]; then - nice -0 python3 ./python/player$i.py -I 127.0.0.1 -P 8888 -p $j + if [ -f "./player$i.py" ]; then + cp -f ./player$i.py $python_dir/AI.py + nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j elif [ -f "./capi$i" ]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j else @@ -21,8 +24,9 @@ do for i in {5..5} do j=$((i - 1)) - if [ -f "./python/player$i.py" ]; then - nice -0 python3 ./python/player$i.py -I 127.0.0.1 -P 8888 -p $j + if [ -f "./player$i.py" ]; then + cp -f ./player$i.py $python_dir/AI.py + nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j elif [ -f "./capi$i" ]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j else From 86d2024cb321310a07a0db10d09f706ea5be0a0e Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:16:52 +0800 Subject: [PATCH 015/105] Update run.sh --- dependency/shell/run.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 3d63212..c61860a 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -1,8 +1,9 @@ #!/usr/local python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI +playback_dir=/usr/local/playback -nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN +nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video > $playback_dir/server.log & sleep 5 for k in {1..2} do @@ -13,9 +14,9 @@ do j=$((i - 1)) if [ -f "./player$i.py" ]; then cp -f ./player$i.py $python_dir/AI.py - nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j + nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & elif [ -f "./capi$i" ]; then - nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j + nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & else echo "ERROR. $i is not found." fi @@ -26,9 +27,9 @@ do j=$((i - 1)) if [ -f "./player$i.py" ]; then cp -f ./player$i.py $python_dir/AI.py - nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j + nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & elif [ -f "./capi$i" ]; then - nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j + nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & else echo "ERROR. $i is not found." fi From f7261bbfdcc561ff8cea4e54ebb19dd12bf253d3 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:29:17 +0800 Subject: [PATCH 016/105] Update run.sh --- dependency/shell/run.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index c61860a..bf5381a 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -4,6 +4,7 @@ python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI playback_dir=/usr/local/playback nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video > $playback_dir/server.log & +server_pid=$! sleep 5 for k in {1..2} do @@ -37,3 +38,12 @@ do fi popd done + +ps -p $server_pid +while [ $? -eq 0 ] +do + sleep 1 + ps -p $server_pid +done + +echo "Finish" From a1cd670dd44883d04a53fa1bddca1ec3c7bb92e1 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:42:15 +0800 Subject: [PATCH 017/105] Update run.sh --- dependency/shell/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index bf5381a..5167827 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -15,7 +15,7 @@ do j=$((i - 1)) if [ -f "./player$i.py" ]; then cp -f ./player$i.py $python_dir/AI.py - nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & + nice -0 python3 $python_dir/main.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & elif [ -f "./capi$i" ]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & else @@ -28,7 +28,7 @@ do j=$((i - 1)) if [ -f "./player$i.py" ]; then cp -f ./player$i.py $python_dir/AI.py - nice -0 python3 $python_dir/AI.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & + nice -0 python3 $python_dir/main.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & elif [ -f "./capi$i" ]; then nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & else From 825a51bfafab918e47f132a633c32302022fcc0f Mon Sep 17 00:00:00 2001 From: DragonAura <32223554+DragonAura@users.noreply.github.com> Date: Tue, 25 Apr 2023 00:33:45 +0800 Subject: [PATCH 018/105] =?UTF-8?q?Update=20CAPI=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=88python=EF=BC=89.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/CAPI接口(python).md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index e470ac2..da5fc05 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -64,6 +64,7 @@ - `def GetTrickers(self) -> List[THUAI6.Tricker]` :返回所有可视捣蛋鬼的信息。 - `def GetProps(self) -> List[THUAI6.Prop]` :返回所有可视道具的信息。 - `def GetBullets(self) -> List[THUAI6.Bullet]` :返回所有可视子弹(攻击)的信息。 + - `def HaveView(self, gridX: int, gridY: int) -> bool`:判断坐标是否可见 #### 查询特定位置物体的信息 @@ -264,6 +265,10 @@ class IAPI(metaclass=ABCMeta): @abstractmethod def GetGameInfo(self) -> THUAI6.GameInfo: pass + + @abstractmethod + def HaveView(self, gridX: int, gridY: int) -> bool + pass # 用于DEBUG的输出函数,仅在DEBUG模式下有效 From 3cb9b4fbb719515e42cfdb811e036db9080fa899 Mon Sep 17 00:00:00 2001 From: DragonAura <32223554+DragonAura@users.noreply.github.com> Date: Tue, 25 Apr 2023 00:36:27 +0800 Subject: [PATCH 019/105] =?UTF-8?q?Update=20CAPI=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=88cpp=EF=BC=89.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/CAPI接口(cpp).md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/CAPI接口(cpp).md b/docs/CAPI接口(cpp).md index b7f4087..70bb297 100644 --- a/docs/CAPI接口(cpp).md +++ b/docs/CAPI接口(cpp).md @@ -52,6 +52,7 @@ - `std::vector> GetTrickers() const` :返回所有可视捣蛋鬼的信息。 - `std::vector> GetProps() const` :返回所有可视道具的信息。 - `std::vector> GetBullets() const` :返回所有可视子弹(攻击)的信息。 + - `bool HaveView(int gridX, int gridY) const`:判断坐标是否可见 #### 查询特定位置物体的信息 @@ -158,6 +159,8 @@ { return grid / numOfGridPerCell; } + + [[nodiscard]] virtual bool HaveView(int gridX, int gridY) const = 0; // 用于DEBUG的输出函数,选手仅在开启Debug模式的情况下可以使用 From ee543e5e6419893981bbac4216600607ac9efdbc Mon Sep 17 00:00:00 2001 From: Timothy Liu Date: Tue, 25 Apr 2023 00:45:23 +0800 Subject: [PATCH 020/105] docs: :memo: add algorithm intro of THUAI4 and THUAI5 --- dependency/algorithm/README.md | 244 +++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 dependency/algorithm/README.md diff --git a/dependency/algorithm/README.md b/dependency/algorithm/README.md new file mode 100644 index 0000000..b8bcec0 --- /dev/null +++ b/dependency/algorithm/README.md @@ -0,0 +1,244 @@ +# Algorithm + +--- + +天梯分数计算算法 + +原始记录在: + +内容如下: + +## THUAI4 + +关于根据队式每场比赛的分数映射到天梯分数的问题: +队式比赛为两队对战,每队得分的区间均为 [0, 2500]。 +以 tanh 函数为基础进行设计。 +设计原则如下: + +1. 输的扣少量天梯分,赢的得大量天梯分 +2. 本就有极高天梯分数的虐本就天梯分数低的,这种降维打击现象,天梯分数涨幅极小甚至不涨天梯分 +3. 如果在某场比赛中,两者表现差不多,即赢的比输的得分高得不多的话,那么天梯分数涨幅也不是很高 +4. 如果本来天梯分数很低的,赢了天梯分数很高的,那么他得到的天梯分会较高,而另一个人,天梯分数降分稍多一些 +5. 如果天梯分数低的赢了天梯分数高的,但是这场比赛赢得不多的话,会把两人的分数向中间靠拢 +6. 总体上,赢的队伍不会降天梯分;输的队伍不会加天梯分 +7. 其他条件相同的情况下,在本场游戏中得分越多,加的天梯分数也越高 + +上述原则可以保证以下两个目的的达成: + +1. 总体来看,进行的游戏场次越多,所有队伍的平均天梯分数就越高 +2. 经过足够多次的游戏场次,实力有一定差距的队伍的天体分数差距逐渐拉开,实力相近的队伍的天梯分数不会差别过大,各支队伍的排名趋近于收敛 + +用 cpp 代码编写算法代码如下(`cal` 函数): + +```cpp +#include +#include +#include +using namespace std; + +template +using mypair = pair; + +// orgScore 是天梯中两队的分数;competitionScore 是这次游戏两队的得分 + +mypair cal(mypair orgScore, mypair competitionScore) +{ + + // 调整顺序,让第一个元素成为获胜者,便于计算 + + bool reverse = false; // 记录是否需要调整 + + if (competitionScore.first < competitionScore.second) + { + reverse = true; + } + else if (competitionScore.first == competitionScore.second) + { + if (orgScore.first == orgScore.second) // 完全平局,不改变天梯分数 + { + return orgScore; + } + + if (orgScore.first > orgScore.second) // 本次游戏平局,但一方天梯分数高,另一方天梯分数低,需要将两者向中间略微靠拢,因此天梯分数低的定为获胜者 + { + reverse = true; + } + else + { + reverse = false; + } + } + + if (reverse) // 如果需要换,换两者的顺序 + { + swap(competitionScore.first, competitionScore.second); + swap(orgScore.first, orgScore.second); + } + + + // 转成浮点数 + mypair orgScoreLf; + mypair competitionScoreLf; + orgScoreLf.first = orgScore.first; + orgScoreLf.second = orgScore.second; + competitionScoreLf.first = competitionScore.first; + competitionScoreLf.second = competitionScore.second; + mypair resScore; + + const double deltaWeight = 80.0; // 差距悬殊判断参数,比赛分差超过此值就可以认定为非常悬殊了,天梯分数增量很小,防止大佬虐菜鸡的现象造成两极分化 + + double delta = (orgScoreLf.first - orgScoreLf.second) / deltaWeight; + cout << "Tanh delta: " << tanh(delta) << endl; + { + + const double firstnerGet = 8e-5; // 胜利者天梯得分权值 + const double secondrGet = 5e-6; // 失败者天梯得分权值 + + double deltaScore = 100.0; // 两队竞争分差超过多少时就认为非常大 + double correctRate = (orgScoreLf.first - orgScoreLf.second) / 100.0; // 订正的幅度,该值越小,则在势均力敌时天梯分数改变越大 + double correct = 0.5 * (tanh((competitionScoreLf.first - competitionScoreLf.second - deltaScore) / deltaScore - correctRate) + 1.0); // 一场比赛中,在双方势均力敌时,减小天梯分数的改变量 + + resScore.first = orgScore.first + round(competitionScoreLf.first * competitionScoreLf.first * firstnerGet * (1 - tanh(delta)) * correct); // 胜者所加天梯分 + resScore.second = orgScore.second - round((2500.0 - competitionScoreLf.second) * (2500.0 - competitionScoreLf.second) * secondrGet * (1 - tanh(delta)) * correct); // 败者所扣天梯分,2500 为得分的最大值(THUAI4 每场得分介于 0~2500 之间) + } + + // 如果换过,再换回来 + if (reverse) + { + swap(resScore.first, resScore.second); + } + + return resScore; +} +``` + +**特别注意**:此算法是在 THUAI4 的比赛直接得分封顶为 2500 分、最低不低于 0 分的前提下设计的,因此并不一定适用于 THUAI5 的情形。 + +## THUAI5 + +今年把得分上限这个东西去掉了。理论上今年可以得很高很高分,但是我估计大部分比赛得分在400-600左右,最高估计1000左右。算法 借 鉴 了THUAI4,算法,换了个激活函数(正态CDF),感觉分数变化相对更好了一些? +代码如下: +~~~C++ +#include +#include +#include +using namespace std; + +template +using mypair = pair; + +double PHI(double x) // THUAI3: Sigmoid; THUAI4: Tanh; THUAI5: Normal Distribution CDF +{ + //double a1 = 0.2548292592; + //double a2 = -0.284496736; + //double a3 = 1.421413741; + //double a4 = -1.453152027; + //double a5 = 1.061405429; + //double p = 0.3275911; + //int sign = 1; + //if (x < 0) + // sign = -1; + //x = fabs(x) / sqrt(2.0); + //double t = 1.0 / (1.0 + p * x); + //double y = 1.0 - ((((((a5 * t + a4) * t + a3) * t) + a2) * t) + a1) * t * exp(-x * x); + //double cdf = 0.5 * (1.0 + sign * y); + //return (cdf - 0.5) * 2.0; // 化到[-1,1]之间 + + return erf(x / sqrt(2)); +} + +// orgScore 是天梯中两队的分数;competitionScore 是这次游戏两队的得分 +mypair cal(mypair orgScore, mypair competitionScore) +{ + + // 调整顺序,让第一个元素成为获胜者,便于计算 + + bool reverse = false; // 记录是否需要调整 + + if (competitionScore.first < competitionScore.second) + { + reverse = true; + } + else if (competitionScore.first == competitionScore.second) + { + if (orgScore.first == orgScore.second) // 完全平局,不改变天梯分数 + { + return orgScore; + } + + if (orgScore.first > orgScore.second) // 本次游戏平局,但一方天梯分数高,另一方天梯分数低,需要将两者向中间略微靠拢,因此天梯分数低的定为获胜者 + { + reverse = true; + } + else + { + reverse = false; + } + } + + if (reverse) // 如果需要换,换两者的顺序 + { + swap(competitionScore.first, competitionScore.second); + swap(orgScore.first, orgScore.second); + } + + + // 转成浮点数 + mypair orgScoreLf; + mypair competitionScoreLf; + orgScoreLf.first = orgScore.first; + orgScoreLf.second = orgScore.second; + competitionScoreLf.first = competitionScore.first; + competitionScoreLf.second = competitionScore.second; + mypair resScore; + + const double deltaWeight = 90.0; // 差距悬殊判断参数,比赛分差超过此值就可以认定为非常悬殊了,天梯分数增量很小,防止大佬虐菜鸡的现象造成两极分化 + + double delta = (orgScoreLf.first - orgScoreLf.second) / deltaWeight; + cout << "Normal CDF delta: " << PHI(delta) << endl; + { + + const double firstnerGet = 3e-4; // 胜利者天梯得分权值 + const double secondrGet = 1e-4; // 失败者天梯得分权值 + + double deltaScore = 100.0; // 两队竞争分差超过多少时就认为非常大 + double correctRate = (orgScoreLf.first - orgScoreLf.second) / 100.0; // 订正的幅度,该值越小,则在势均力敌时天梯分数改变越大 + double correct = 0.5 * (PHI((competitionScoreLf.first - competitionScoreLf.second - deltaScore) / deltaScore - correctRate) + 1.0); // 一场比赛中,在双方势均力敌时,减小天梯分数的改变量 + + resScore.first = orgScore.first + round(competitionScoreLf.first * competitionScoreLf.first * firstnerGet * (1 - PHI(delta)) * correct); // 胜者所加天梯分 + if (competitionScoreLf.second < 1000) + resScore.second = orgScore.second - round((1000.0 - competitionScoreLf.second) * (1000.0 - competitionScoreLf.second) * secondrGet * (1 - PHI(delta)) * correct); // 败者所扣天梯分 + else + resScore.second = orgScore.second; // 败者拿1000分,已经很强了,不扣分 + } + + // 如果换过,再换回来 + if (reverse) + { + swap(resScore.first, resScore.second); + } + + return resScore; +} + +void Print(mypair score) +{ + std::cout << " team1: " << score.first << std::endl + << "team2: " << score.second << std::endl; +} + +int main() +{ + int x, y; + std::cout << "origin score of team 1 and 2: " << std::endl; + std::cin >> x >> y; + auto ori = mypair(x, y); + std::cout << "game score of team 1 and 2: " << std::endl; + std::cin >> x >> y; + auto sco = mypair(x, y); + Print(cal(ori, sco)); +} + +`1000 - score`(x +`ReLU(1000 - score)`(√ +防止真的超过了 1000) From 52a36afa1d9f31c63aada6790485be4ad5b0219b Mon Sep 17 00:00:00 2001 From: Timothy Liu Date: Tue, 25 Apr 2023 00:47:03 +0800 Subject: [PATCH 021/105] docs: :memo: fix code style --- dependency/algorithm/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dependency/algorithm/README.md b/dependency/algorithm/README.md index b8bcec0..a26b650 100644 --- a/dependency/algorithm/README.md +++ b/dependency/algorithm/README.md @@ -118,7 +118,7 @@ mypair cal(mypair orgScore, mypair competitionScore) 今年把得分上限这个东西去掉了。理论上今年可以得很高很高分,但是我估计大部分比赛得分在400-600左右,最高估计1000左右。算法 借 鉴 了THUAI4,算法,换了个激活函数(正态CDF),感觉分数变化相对更好了一些? 代码如下: -~~~C++ +```cpp #include #include #include @@ -238,6 +238,7 @@ int main() auto sco = mypair(x, y); Print(cal(ori, sco)); } +``` `1000 - score`(x `ReLU(1000 - score)`(√ From df6bdbbb19c5bbf595873a13b8b0df2bf0bc2e1f Mon Sep 17 00:00:00 2001 From: Timothy Liu Date: Tue, 25 Apr 2023 00:47:47 +0800 Subject: [PATCH 022/105] docs: :memo: fix code style --- dependency/algorithm/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency/algorithm/README.md b/dependency/algorithm/README.md index a26b650..58d3de8 100644 --- a/dependency/algorithm/README.md +++ b/dependency/algorithm/README.md @@ -240,6 +240,6 @@ int main() } ``` -`1000 - score`(x -`ReLU(1000 - score)`(√ +`1000 - score`(x +`ReLU(1000 - score)`(√ 防止真的超过了 1000) From f92b520ed7d73689e8e75eccbb4cbbcde65d29f6 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Tue, 25 Apr 2023 01:07:47 +0800 Subject: [PATCH 023/105] ci: :green_heart: Try to fix Hash --- .github/workflows/upload_COS.yml | 14 -------------- logic/GameEngine/MoveEngine.cs | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/upload_COS.yml b/.github/workflows/upload_COS.yml index e67fe86..506b433 100644 --- a/.github/workflows/upload_COS.yml +++ b/.github/workflows/upload_COS.yml @@ -138,13 +138,6 @@ jobs: - name: Remove Files run: | rm ./THUAI6/hash.json - - rm ./THUAI6/win/win64/PresentationCore.dll - rm ./THUAI6/win/win64/PresentationFramework.dll - rm ./THUAI6/win/win64/Debug/Microsoft.DiaSymReader.Native.amd64.dll - rm ./THUAI6/win/win64/WindowsBase.dll - rm ./THUAI6/win/win64/Debug/grpc_csharp_ext.x64.dll - rm ./THUAI6/win/win64/grpc_csharp_ext.x64.dll rm -r ./THUAI6/win/CAPI/cpp/grpc rm -r ./THUAI6/win/CAPI/cpp/spdlog @@ -155,13 +148,6 @@ jobs: rm -r ./THUAI6/osx/CAPI/cpp/grpc rm -r ./THUAI6/osx/CAPI/cpp/spdlog rm -r ./THUAI6/osx/CAPI/cpp/tclap - - rm ./THUAI6/linux/linux64/System.*.dll - rm ./THUAI6/linux/linux64/Debug/System.*.dll - rm ./THUAI6/osx/osx64/System.*.dll - rm ./THUAI6/osx/osx64/Debug/System.*.dll - rm ./THUAI6/win/win64/System.*.dll - rm ./THUAI6/win/win64/Debug/System.*.dll rm ./THUAI6/linux/linux64/*.so rm ./THUAI6/linux/linux64/Debug/*.so diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs index ac6bdbe..d0a44b2 100644 --- a/logic/GameEngine/MoveEngine.cs +++ b/logic/GameEngine/MoveEngine.cs @@ -87,7 +87,7 @@ namespace GameEngine obj.IsMoving = true; double moveVecLength = 0.0; - XY res = new XY(direction, moveVecLength); + XY res = new(direction, moveVecLength); double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); // 转向,并用deltaLen存储行走的误差 IGameObj? collisionObj = null; bool isDestroyed = false; From 0e86cf5de92a861f9a0f60087767669c8acad59b Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Tue, 25 Apr 2023 01:29:29 +0800 Subject: [PATCH 024/105] Update run.sh --- dependency/shell/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 5167827..2f83f8a 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -47,3 +47,4 @@ do done echo "Finish" +touch $playback_dir/finish.lock From ec9856c8148f35535e62d2ea9ecdea1f59e3d487 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Tue, 25 Apr 2023 01:34:53 +0800 Subject: [PATCH 025/105] Update README.md --- dependency/shell/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dependency/shell/README.md b/dependency/shell/README.md index 03496ee..b25b71a 100644 --- a/dependency/shell/README.md +++ b/dependency/shell/README.md @@ -2,3 +2,12 @@ 本目录用于存放程序所需的shell脚本 +## run.sh + +注意: + +1. server 和 client 程序要在后台进行 + +2. 忙等待到 server 结束 + +3. 结束后生成标志结束的文件 From b29441a9410d66aa62fabf072f8fdb560707a065 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Tue, 25 Apr 2023 01:35:12 +0800 Subject: [PATCH 026/105] Update run.sh --- dependency/shell/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 2f83f8a..70a1286 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -46,5 +46,5 @@ do ps -p $server_pid done -echo "Finish" touch $playback_dir/finish.lock +echo "Finish" From 3eda4af66ff529f66d2cab1474eedcdd05b89d7e Mon Sep 17 00:00:00 2001 From: Shawqeem <1004837646@qq.com> Date: Tue, 25 Apr 2023 02:01:37 +0800 Subject: [PATCH 027/105] docs: :sparkles: add the algorithm of ranking in THUAI6 to the readme file add the algorithm of ranking in THUAI6 to the readme file --- dependency/algorithm/README.md | 87 ++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/dependency/algorithm/README.md b/dependency/algorithm/README.md index 58d3de8..fe9624e 100644 --- a/dependency/algorithm/README.md +++ b/dependency/algorithm/README.md @@ -118,6 +118,7 @@ mypair cal(mypair orgScore, mypair competitionScore) 今年把得分上限这个东西去掉了。理论上今年可以得很高很高分,但是我估计大部分比赛得分在400-600左右,最高估计1000左右。算法 借 鉴 了THUAI4,算法,换了个激活函数(正态CDF),感觉分数变化相对更好了一些? 代码如下: + ```cpp #include #include @@ -243,3 +244,89 @@ int main() `1000 - score`(x `ReLU(1000 - score)`(√ 防止真的超过了 1000) + +## THUAI6 + +因为今年的对局得分是两局得分之和,所以会出现一定程度的“数值膨胀”,在这里调低了胜者得分权值,同时提高了比赛分差距悬殊阈值和天梯分差距悬殊阈值。同时由于今年得分的上限不好确定,所以负者失分的基础值变为与胜者的得分之差。 + +```c++ +#include +#include +#include +using namespace std; + +template +using mypair = pair; + +// orgScore 是天梯中两队的分数;competitionScore 是这次游戏两队的得分 + +mypair cal(mypair orgScore, mypair competitionScore) +{ + + // 调整顺序,让第一个元素成为获胜者,便于计算 + + bool reverse = false; // 记录是否需要调整 + + if (competitionScore.first < competitionScore.second) + { + reverse = true; + } + else if (competitionScore.first == competitionScore.second) + { + if (orgScore.first == orgScore.second) // 完全平局,不改变天梯分数 + { + return orgScore; + } + + if (orgScore.first > orgScore.second) // 本次游戏平局,但一方天梯分数高,另一方天梯分数低,需要将两者向中间略微靠拢,因此天梯分数低的定为获胜者 + { + reverse = true; + } + else + { + reverse = false; + } + } + + if (reverse) // 如果需要换,换两者的顺序 + { + swap(competitionScore.first, competitionScore.second); + swap(orgScore.first, orgScore.second); + } + + // 转成浮点数 + mypair orgScoreLf; + mypair competitionScoreLf; + orgScoreLf.first = orgScore.first; + orgScoreLf.second = orgScore.second; + competitionScoreLf.first = competitionScore.first; + competitionScoreLf.second = competitionScore.second; + mypair resScore; + + const double deltaWeight = 1000.0; // 差距悬殊判断参数,比赛分差超过此值就可以认定为非常悬殊了,天梯分数增量很小,防止大佬虐菜鸡的现象造成两极分化 + + double delta = (orgScoreLf.first - orgScoreLf.second) / deltaWeight; + cout << "Tanh delta: " << tanh(delta) << endl; + { + + const double firstnerGet = 9e-6; // 胜利者天梯得分权值 + const double secondrGet = 5e-6; // 失败者天梯得分权值 + + double deltaScore = 2100.0; // 两队竞争分差超过多少时就认为非常大 + double correctRate = (orgScoreLf.first - orgScoreLf.second) / (deltaWeight * 1.2); // 订正的幅度,该值越小,则在势均力敌时天梯分数改变越大 + double correct = 0.5 * (tanh((competitionScoreLf.first - competitionScoreLf.second - deltaScore) / deltaScore - correctRate) + 1.0); // 一场比赛中,在双方势均力敌时,减小天梯分数的改变量 + cout << "correct: " << correct << endl; + resScore.first = orgScore.first + round(competitionScoreLf.first * competitionScoreLf.first * firstnerGet * (1 - tanh(delta)) * correct); // 胜者所加天梯分 + resScore.second = orgScore.second - round((competitionScoreLf.first - competitionScoreLf.second) * (competitionScoreLf.first - competitionScoreLf.second) * secondrGet * (1 - tanh(delta)) * correct); // 败者所扣天梯分 + } + + // 如果换过,再换回来 + if (reverse) + { + swap(resScore.first, resScore.second); + } + + return resScore; +} +``` + From 77c923cdc55d85fdf77515d1481cbf0379858a0d Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Tue, 25 Apr 2023 02:18:52 +0800 Subject: [PATCH 028/105] fix: :bug: fix the storaged files --- .github/workflows/upload_COS.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/upload_COS.yml b/.github/workflows/upload_COS.yml index 506b433..543212a 100644 --- a/.github/workflows/upload_COS.yml +++ b/.github/workflows/upload_COS.yml @@ -138,19 +138,27 @@ jobs: - name: Remove Files run: | rm ./THUAI6/hash.json + + rm ./THUAI6/win/win64/PresentationCore.dll + rm ./THUAI6/win/win64/PresentationFramework.dll + rm ./THUAI6/win/win64/Debug/Microsoft.DiaSymReader.Native.amd64.dll + rm ./THUAI6/win/win64/WindowsBase.dll + rm ./THUAI6/win/win64/Debug/grpc_csharp_ext.x64.dll + rm ./THUAI6/win/win64/grpc_csharp_ext.x64.dll rm -r ./THUAI6/win/CAPI/cpp/grpc - rm -r ./THUAI6/win/CAPI/cpp/spdlog rm -r ./THUAI6/win/CAPI/cpp/tclap rm -r ./THUAI6/linux/CAPI/cpp/grpc - rm -r ./THUAI6/linux/CAPI/cpp/spdlog rm -r ./THUAI6/linux/CAPI/cpp/tclap rm -r ./THUAI6/osx/CAPI/cpp/grpc - rm -r ./THUAI6/osx/CAPI/cpp/spdlog rm -r ./THUAI6/osx/CAPI/cpp/tclap - - rm ./THUAI6/linux/linux64/*.so - rm ./THUAI6/linux/linux64/Debug/*.so + + rm ./THUAI6/linux/linux64/System.*.dll + rm ./THUAI6/linux/linux64/Debug/System.*.dll + rm ./THUAI6/osx/osx64/System.*.dll + rm ./THUAI6/osx/osx64/Debug/System.*.dll + rm ./THUAI6/win/win64/System.*.dll + rm ./THUAI6/win/win64/Debug/System.*.dll - name: Upload COS uses: zkqiang/tencent-cos-action@v0.1.0 From 40d5806f53ed5db1aba179c0564375b28fa040b7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 03:37:51 +0000 Subject: [PATCH 029/105] chore(deps): update dependency google.protobuf.tools to v3.22.3 --- dependency/proto/Protos.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency/proto/Protos.csproj b/dependency/proto/Protos.csproj index 98000c5..edba4dd 100755 --- a/dependency/proto/Protos.csproj +++ b/dependency/proto/Protos.csproj @@ -15,7 +15,7 @@ - + From 5ec70aeb6e554cfa618a3abec800f3342043829e Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Tue, 25 Apr 2023 13:39:20 +0800 Subject: [PATCH 030/105] docs: :memo: edit GameRules.md --- docs/GameRules.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/GameRules.md b/docs/GameRules.md index 8586e40..d92ccfb 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -1,5 +1,5 @@ # 规则 -V5.2 +V5.3 - [规则](#规则) - [简则](#简则) - [地图](#地图) @@ -140,9 +140,9 @@ $$ ### 信息相关 - Bgm (在structures.h/.py中的student类或Tricker类中作为其属性) - 1. 不详的感觉(dangerAlert):如果捣蛋鬼进入(学生的警戒半径/捣蛋鬼的隐蔽度)的距离,则学生的dangerAlert=(int)(警戒半径/二者距离) - 2. 期待搞事的感觉(trickDesire):如果有学生进入(捣蛋鬼的警戒半径/学生的隐蔽度)的距离,则捣蛋鬼trickDesire=(int)(警戒半径/可被发觉的最近的学生距离) - 3. 学习的声音(classVolume): 警戒半径内有人学习时,捣蛋鬼classVolume=(int)((警戒半径x学习进度百分比)/二者距离) + 1. 不详的感觉(dangerAlert):如果捣蛋鬼进入(学生的警戒半径/捣蛋鬼的隐蔽度)的距离,则学生的dangerAlert=(警戒半径/二者距离) + 2. 期待搞事的感觉(trickDesire):如果有学生进入(捣蛋鬼的警戒半径/学生的隐蔽度)的距离,则捣蛋鬼trickDesire=(警戒半径/可被发觉的最近的学生距离) + 3. 学习的声音(classVolume): 警戒半径内有人学习时,捣蛋鬼classVolume=((警戒半径x学习进度百分比)/二者距离) - 可以向每一个队友发送不超过256字节的信息 ### 可视范围 From b2164037dbee17bfe8f910a8c9c4009b97b36495 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 06:03:29 +0000 Subject: [PATCH 031/105] chore(deps): update dependency google.protobuf to v3.22.3 --- dependency/proto/Protos.csproj | 2 +- logic/Client/Client.csproj | 2 +- logic/ClientTest/ClientTest.csproj | 2 +- logic/Preparation/Preparation.csproj | 2 +- logic/Server/Server.csproj | 2 +- playback/Playback/Playback.csproj | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dependency/proto/Protos.csproj b/dependency/proto/Protos.csproj index edba4dd..3d025bc 100755 --- a/dependency/proto/Protos.csproj +++ b/dependency/proto/Protos.csproj @@ -14,7 +14,7 @@ --> - + diff --git a/logic/Client/Client.csproj b/logic/Client/Client.csproj index db66157..6af7e5c 100644 --- a/logic/Client/Client.csproj +++ b/logic/Client/Client.csproj @@ -19,7 +19,7 @@ - + diff --git a/logic/ClientTest/ClientTest.csproj b/logic/ClientTest/ClientTest.csproj index 2e8f16d..b0894ed 100644 --- a/logic/ClientTest/ClientTest.csproj +++ b/logic/ClientTest/ClientTest.csproj @@ -8,7 +8,7 @@ - + diff --git a/logic/Preparation/Preparation.csproj b/logic/Preparation/Preparation.csproj index 73cc535..4a5e031 100644 --- a/logic/Preparation/Preparation.csproj +++ b/logic/Preparation/Preparation.csproj @@ -9,7 +9,7 @@ - + diff --git a/logic/Server/Server.csproj b/logic/Server/Server.csproj index 50052fe..43c37b5 100644 --- a/logic/Server/Server.csproj +++ b/logic/Server/Server.csproj @@ -10,7 +10,7 @@ - + diff --git a/playback/Playback/Playback.csproj b/playback/Playback/Playback.csproj index 74fc21b..ada2c68 100644 --- a/playback/Playback/Playback.csproj +++ b/playback/Playback/Playback.csproj @@ -7,7 +7,7 @@ - + From dd8eb8581666bc61620bb5ad6f7e5bd899e721d5 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Tue, 25 Apr 2023 14:52:20 +0800 Subject: [PATCH 032/105] ci: :green_heart: del README.md --- .github/workflows/upload_COS.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/upload_COS.yml b/.github/workflows/upload_COS.yml index 543212a..a1be1f8 100644 --- a/.github/workflows/upload_COS.yml +++ b/.github/workflows/upload_COS.yml @@ -113,6 +113,9 @@ jobs: name: my-artifact path: ./THUAI6 + - name: Remove ReadMe.md + run: rm ./docs/README.md + - name: Markdown to PDF and HTML uses: BaileyJM02/markdown-to-pdf@v1.2.0 with: @@ -145,12 +148,14 @@ jobs: rm ./THUAI6/win/win64/WindowsBase.dll rm ./THUAI6/win/win64/Debug/grpc_csharp_ext.x64.dll rm ./THUAI6/win/win64/grpc_csharp_ext.x64.dll - rm -r ./THUAI6/win/CAPI/cpp/grpc + rm -r ./THUAI6/win/CAPI/cpp/spdlog rm -r ./THUAI6/win/CAPI/cpp/tclap rm -r ./THUAI6/linux/CAPI/cpp/grpc + rm -r ./THUAI6/linux/CAPI/cpp/spdlog rm -r ./THUAI6/linux/CAPI/cpp/tclap rm -r ./THUAI6/osx/CAPI/cpp/grpc + rm -r ./THUAI6/osx/CAPI/cpp/spdlog rm -r ./THUAI6/osx/CAPI/cpp/tclap rm ./THUAI6/linux/linux64/System.*.dll @@ -159,6 +164,8 @@ jobs: rm ./THUAI6/osx/osx64/Debug/System.*.dll rm ./THUAI6/win/win64/System.*.dll rm ./THUAI6/win/win64/Debug/System.*.dll + rm ./THUAI6/linux/linux64/*.so + rm ./THUAI6/linux/linux64/Debug/*.so - name: Upload COS uses: zkqiang/tencent-cos-action@v0.1.0 From c6d5fddcb8394d037215f7198c445ef811909e33 Mon Sep 17 00:00:00 2001 From: Shawqeem <1004837646@qq.com> Date: Tue, 25 Apr 2023 15:41:01 +0800 Subject: [PATCH 033/105] fix: :bug: fix the bug that the map will not be refreshed at the beginning of a game fix the bug that the map will not be refreshed at the beginning of a game --- logic/Client/MainWindow.xaml.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/logic/Client/MainWindow.xaml.cs b/logic/Client/MainWindow.xaml.cs index 9001d75..4ab6665 100644 --- a/logic/Client/MainWindow.xaml.cs +++ b/logic/Client/MainWindow.xaml.cs @@ -300,6 +300,24 @@ namespace Client } } + private void ZoomMapAtFirst() + { + for (int i = 0; i < 50; i++) + { + for (int j = 0; j < 50; j++) + { + if (mapPatches[i, j] != null) + { + mapPatches[i, j].Width = UpperLayerOfMap.ActualWidth / 50; + mapPatches[i, j].Height = UpperLayerOfMap.ActualHeight / 50; + mapPatches[i, j].HorizontalAlignment = HorizontalAlignment.Left; + mapPatches[i, j].VerticalAlignment = VerticalAlignment.Top; + mapPatches[i, j].Margin = new Thickness(UpperLayerOfMap.ActualWidth / 50 * j, UpperLayerOfMap.ActualHeight / 50 * i, 0, 0); + } + } + } + } + private void DrawMap() { for (int i = 0; i < defaultMap.GetLength(0); i++) @@ -750,7 +768,10 @@ namespace Client StatusBarsOfCircumstance.SetValue(data, gateOpened, isEmergencyDrawed, isEmergencyOpened, playerID, isPlaybackMode); } if (!hasDrawed && mapFlag) + { DrawMap(); + ZoomMapAtFirst(); + } foreach (var data in listOfHuman) { if (data.StudentType != StudentType.Robot) From fdfc7911a7d7a233d26c200209c64f02bbc3744d Mon Sep 17 00:00:00 2001 From: DragonAura Date: Tue, 25 Apr 2023 18:20:09 +0800 Subject: [PATCH 034/105] fix(CAPI): :bug: fix wrong frame count --- CAPI/cpp/API/src/logic.cpp | 1 + CAPI/python/PyAPI/logic.py | 1 + 2 files changed, 2 insertions(+) diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 13c174b..c06eb09 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -618,6 +618,7 @@ void Logic::LoadBuffer(const protobuf::MessageToClient& message) { std::lock_guard lock(mtxState); std::swap(currentState, bufferState); + counterState = counterBuffer; logger->info("Update State!"); } freshed = true; diff --git a/CAPI/python/PyAPI/logic.py b/CAPI/python/PyAPI/logic.py index 65af3bb..b3763c6 100644 --- a/CAPI/python/PyAPI/logic.py +++ b/CAPI/python/PyAPI/logic.py @@ -476,6 +476,7 @@ class Logic(ILogic): if Setting.asynchronous(): with self.__mtxState: self.__currentState, self.__bufferState = self.__bufferState, self.__currentState + self.__counterState = self.__counterBuffer self.__logger.info("Update state!") self.__freshed = True else: From 55ac501a8135d783d7995f08e6dbe509b84bf233 Mon Sep 17 00:00:00 2001 From: gsy1519 <614054460@qq.com> Date: Tue, 25 Apr 2023 19:17:27 +0800 Subject: [PATCH 035/105] fix: :bug: change default value of AllowSpectator --- logic/Server/ArgumentOption.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logic/Server/ArgumentOption.cs b/logic/Server/ArgumentOption.cs index 2dddf7d..c39204e 100644 --- a/logic/Server/ArgumentOption.cs +++ b/logic/Server/ArgumentOption.cs @@ -40,7 +40,7 @@ namespace Server public string FileName { get; set; } = DefaultArgumentOptions.FileName; [Option('s', "allowSpectator", Required = false, HelpText = "Whether to allow a spectator to watch the game.")] - public bool AllowSpectator { get; set; } = true; + public bool AllowSpectator { get; set; } = false; [Option('b', "playback", Required = false, HelpText = "Whether open the server in a playback mode.")] public bool Playback { get; set; } = false; From 8ad613c408711aa35c00f906b7c19ed8fbdf1b04 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Tue, 25 Apr 2023 20:59:17 +0800 Subject: [PATCH 036/105] fix: :rewind: cancel removing the student --- logic/Gaming/CharacterManager .cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs index 7f15d59..9f4b984 100644 --- a/logic/Gaming/CharacterManager .cs +++ b/logic/Gaming/CharacterManager .cs @@ -398,10 +398,8 @@ namespace Gaming ((SummonGolem)(((Golem)player).Parent.FindIActiveSkill(ActiveSkillType.SummonGolem))).GolemSummoned = null; player.FindIActiveSkill(ActiveSkillType.UseRobot).IsBeingUsed = false; } - gameMap.Remove(player); return; } - gameMap.Remove(player); ++gameMap.NumOfDeceasedStudent; } From 43a71d02aa86b953fb10cc42f7d72e40e12c5653 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Tue, 25 Apr 2023 22:38:56 +0800 Subject: [PATCH 037/105] fix: :bug: Try to fix the problem about attacking When clipping --- docs/QandA.md | 9 ++++++--- logic/GameClass/GameObj/Bullet/Bullet.cs | 1 + logic/GameClass/GameObj/Character/Character.cs | 2 +- logic/Gaming/AttackManager.cs | 6 ++++-- logic/Preparation/Utility/GameData.cs | 3 ++- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/QandA.md b/docs/QandA.md index 90096d9..9483d9a 100644 --- a/docs/QandA.md +++ b/docs/QandA.md @@ -62,12 +62,15 @@ A: - 可能措施1. 首先保证Python版本在3.9及以上 - 可能措施2. 更换为国内镜像源 -在终端输入 - `pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple` +在终端输入 `pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple` - 可能措施3. 更新pip `python -m pip install --upgrade pip` (pip 版本最好为23.1) ## 比赛相关 Q:职业数值会修改吗? -A:初赛结束会调数值及机制,增加新角色 \ No newline at end of file +A:初赛结束会调数值及机制,增加新角色 + +Q:初赛后会修改什么呢? + +A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业 \ No newline at end of file diff --git a/logic/GameClass/GameObj/Bullet/Bullet.cs b/logic/GameClass/GameObj/Bullet/Bullet.cs index 1a389b2..29f2d78 100644 --- a/logic/GameClass/GameObj/Bullet/Bullet.cs +++ b/logic/GameClass/GameObj/Bullet/Bullet.cs @@ -36,6 +36,7 @@ namespace GameClass.GameObj public override bool IgnoreCollideExecutor(IGameObj targetObj) { + if (targetObj == Parent && CanMove) return true; if (targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet) return true; return false; diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs index b0c3d3b..2231030 100644 --- a/logic/GameClass/GameObj/Character/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -594,7 +594,7 @@ namespace GameClass.GameObj { return true; } - if (targetObj.Type == GameObjType.Character && XY.DistanceFloor3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius) + if (targetObj.Type == GameObjType.Character && XY.DistanceFloor3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius - GameData.adjustLength) return true; return false; } diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index f17ef0d..5dca755 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -34,6 +34,7 @@ namespace Gaming Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty) BulletBomb((Bullet)obj, null); + obj.CanMove = false; } ); this.characterManager = characterManager; @@ -173,14 +174,15 @@ namespace Gaming XY res = player.Position + new XY // 子弹紧贴人物生成。 ( - (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle)), - (int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle)) + (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle))) * ((Math.Cos(angle) > 0) ? 1 : -1), + (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1) ); Bullet? bullet = player.Attack(res, gameMap.GetPlaceType(res)); if (bullet != null) { + player.FacingDirection = new(angle, bullet.BulletAttackRange); Debugger.Output(player, "Attack in " + bullet.ToString()); bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0; bullet.CanMove = true; diff --git a/logic/Preparation/Utility/GameData.cs b/logic/Preparation/Utility/GameData.cs index 17aca10..b788f41 100644 --- a/logic/Preparation/Utility/GameData.cs +++ b/logic/Preparation/Utility/GameData.cs @@ -9,7 +9,8 @@ namespace Preparation.Utility #region 基本常数 public const int numOfStepPerSecond = 20; // 每秒行走的步数 - public const int tolerancesLength = 10; + public const int tolerancesLength = 3; + public const int adjustLength = 3; public const int frameDuration = 50; // 每帧时长 public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长 From c9593643a3965f5b5bbc6fd736019b007ca0e5c8 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Wed, 26 Apr 2023 00:17:20 +0800 Subject: [PATCH 038/105] fix: :bug: fix the bug about attacking When clipping --- docs/CAPI接口(python).md | 3 +- docs/QandA.md | 2 +- .../GameClass/GameObj/Character/Character.cs | 2 +- logic/GameEngine/MoveEngine.cs | 188 ++++++++++-------- logic/Gaming/ActionManager.cs | 1 + logic/Gaming/AttackManager.cs | 3 +- 6 files changed, 114 insertions(+), 85 deletions(-) diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index da5fc05..1b36a28 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -8,7 +8,8 @@ #### 移动 -- `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为 x 轴,水平向右方向为 y 轴**因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 +- `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为 x 轴,水平向右方向为 y 轴**因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 + - 5ms以内的移动指令会被禁止,你不应当使用过小的移动指令 - `def MoveRight(self, timeInMilliseconds: int) -> Future[bool]`即向右移动,`MoveLeft`、`MoveDown`、`MoveUp`同理 #### 使用技能 diff --git a/docs/QandA.md b/docs/QandA.md index 9483d9a..1ccc5c8 100644 --- a/docs/QandA.md +++ b/docs/QandA.md @@ -73,4 +73,4 @@ A:初赛结束会调数值及机制,增加新角色 Q:初赛后会修改什么呢? -A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业 \ No newline at end of file +A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业;规范Debug信息 \ No newline at end of file diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs index 2231030..c6c0624 100644 --- a/logic/GameClass/GameObj/Character/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -594,7 +594,7 @@ namespace GameClass.GameObj { return true; } - if (targetObj.Type == GameObjType.Character && XY.DistanceFloor3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius - GameData.adjustLength) + if (targetObj.Type == GameObjType.Character && XY.DistanceCeil3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius - GameData.adjustLength) return true; return false; } diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs index d0a44b2..443d989 100644 --- a/logic/GameEngine/MoveEngine.cs +++ b/logic/GameEngine/MoveEngine.cs @@ -91,106 +91,132 @@ namespace GameEngine double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); // 转向,并用deltaLen存储行走的误差 IGameObj? collisionObj = null; bool isDestroyed = false; - new FrameRateTaskExecutor( - () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting && obj.IsMoving, - () => + + bool flag; // 循环标志 + do + { + flag = false; + collisionObj = collisionChecker.CheckCollision(obj, obj.Position); + if (collisionObj == null) + break; + + switch (OnCollision(obj, collisionObj, res)) { - moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; - res = new XY(direction, moveVecLength); + case AfterCollision.ContinueCheck: + flag = true; + break; + case AfterCollision.Destroyed: + Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); + isDestroyed = true; + break; + case AfterCollision.MoveMax: + break; + } + } while (flag); - // 越界情况处理:如果越界,则与越界方块碰撞 - bool flag; // 循环标志 - do + if (!isDestroyed) + { + new FrameRateTaskExecutor( + () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting && obj.IsMoving, + () => { - flag = false; - collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res); - if (collisionObj == null) - break; + moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; + res = new XY(direction, moveVecLength); - switch (OnCollision(obj, collisionObj, res)) + // 越界情况处理:如果越界,则与越界方块碰撞 + bool flag; // 循环标志 + do { - case AfterCollision.ContinueCheck: - flag = true; - break; - case AfterCollision.Destroyed: - Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); - isDestroyed = true; - return false; - case AfterCollision.MoveMax: - MoveMax(obj, res); - moveVecLength = 0; - res = new XY(direction, moveVecLength); + flag = false; + collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res); + if (collisionObj == null) break; - } - } while (flag); - deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); + switch (OnCollision(obj, collisionObj, res)) + { + case AfterCollision.ContinueCheck: + flag = true; + break; + case AfterCollision.Destroyed: + Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); + isDestroyed = true; + return false; + case AfterCollision.MoveMax: + MoveMax(obj, res); + moveVecLength = 0; + res = new XY(direction, moveVecLength); + break; + } + } while (flag); - return true; - }, - GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, - () => - { - int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); - bool flag; - do + deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); + + return true; + }, + GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, + () => { - flag = false; - if (!isDestroyed) + int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); + bool flag; + do { - moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; - res = new XY(direction, moveVecLength); - if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) - { - obj.MovingSetPos(res, GetPlaceType(obj.Position + res)); - } - else + flag = false; + if (!isDestroyed) { - switch (OnCollision(obj, collisionObj, res)) + moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; + res = new XY(direction, moveVecLength); + if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) + { + obj.MovingSetPos(res, GetPlaceType(obj.Position + res)); + } + else { - case AfterCollision.ContinueCheck: - flag = true; - break; - case AfterCollision.Destroyed: - Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); - isDestroyed = true; - break; - case AfterCollision.MoveMax: - MoveMax(obj, res); - moveVecLength = 0; - res = new XY(direction, moveVecLength); - break; + switch (OnCollision(obj, collisionObj, res)) + { + case AfterCollision.ContinueCheck: + flag = true; + break; + case AfterCollision.Destroyed: + Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); + isDestroyed = true; + break; + case AfterCollision.MoveMax: + MoveMax(obj, res); + moveVecLength = 0; + res = new XY(direction, moveVecLength); + break; + } } } + } while (flag); + if (leftTime > 0 && obj.IsMoving) + { + Thread.Sleep(leftTime); // 多移动的在这里补回来 } - } while (flag); - if (leftTime > 0 && obj.IsMoving) - { - Thread.Sleep(leftTime); // 多移动的在这里补回来 - } - lock (obj.MoveLock) - obj.IsMoving = false; // 结束移动 - EndMove(obj); - return 0; - }, - maxTotalDuration: moveTime - ) - { - AllowTimeExceed = true, - MaxTolerantTimeExceedCount = ulong.MaxValue, - TimeExceedAction = b => + lock (obj.MoveLock) + obj.IsMoving = false; // 结束移动 + EndMove(obj); + return 0; + }, + maxTotalDuration: moveTime + ) { - if (b) - Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); + AllowTimeExceed = true, + MaxTolerantTimeExceedCount = ulong.MaxValue, + TimeExceedAction = b => + { + if (b) + Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); #if DEBUG - else - { - Console.WriteLine("Debug info: Object moving time exceed for once."); - } + else + { + Console.WriteLine("Debug info: Object moving time exceed for once."); + } #endif - } - }.Start(); + } + }.Start(); + } } ).Start(); } diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index b4f88fb..68db0be 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -35,6 +35,7 @@ namespace Gaming } public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) { + if (moveTimeInMilliseconds < 5) return false; if (!playerToMove.Commandable() || !TryToStop()) return false; characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving); moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 5dca755..96be026 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -172,6 +172,7 @@ namespace Gaming return false; Debugger.Output(player, player.CharacterType.ToString() + "Attack in " + player.BulletOfPlayer.ToString()); + Debugger.Output(player, player.Position.ToString() + " " + player.Radius.ToString() + " " + BulletFactory.BulletRadius(player.BulletOfPlayer).ToString()); XY res = player.Position + new XY // 子弹紧贴人物生成。 ( (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle))) * ((Math.Cos(angle) > 0) ? 1 : -1), @@ -183,7 +184,7 @@ namespace Gaming if (bullet != null) { player.FacingDirection = new(angle, bullet.BulletAttackRange); - Debugger.Output(player, "Attack in " + bullet.ToString()); + Debugger.Output(bullet, "Attack in " + bullet.Position.ToString()); bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0; bullet.CanMove = true; gameMap.Add(bullet); From ebd775085855abc7437d680049d6b134b75e0297 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Wed, 26 Apr 2023 17:39:41 +0800 Subject: [PATCH 039/105] fix: :bug: fix the bug about EndAllAction --- docs/GameRules.md | 24 +++++----- .../GameClass/GameObj/Character/Character.cs | 44 +++++++++++++----- logic/GameEngine/MoveEngine.cs | 5 ++ logic/Gaming/ActionManager.cs | 28 ++++++----- logic/Gaming/AttackManager.cs | 5 +- logic/Gaming/CharacterManager .cs | 46 +++++++++++++------ logic/Gaming/Game.cs | 7 +-- logic/Preparation/Interface/ICharacter.cs | 1 + logic/Server/CopyInfo.cs | 2 - logic/cmd/gameServerAndClient.cmd | 7 +++ 10 files changed, 109 insertions(+), 60 deletions(-) create mode 100644 logic/cmd/gameServerAndClient.cmd diff --git a/docs/GameRules.md b/docs/GameRules.md index d92ccfb..464632f 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -1,5 +1,5 @@ # 规则 -V5.3 +V5.4 - [规则](#规则) - [简则](#简则) - [地图](#地图) @@ -201,11 +201,11 @@ $$ #### Assassin - 普通攻击为 CommonAttackOfGhost - 主动技能 - - 隐身 BecomeInvisible + 0. 隐身 BecomeInvisible - CD:40s 持续时间:10s - 在持续时间内玩家隐身 - 使用瞬间得分15 - - 使用飞刀 + 1. 使用飞刀 - CD:30s 持续时间:1s - 在持续时间内,攻击类型变为飞刀 - 不直接得分 @@ -213,7 +213,7 @@ $$ #### Klee - 普通攻击为 CommonAttackOfGhost - 主动技能 - - 蹦蹦炸弹 JumpyBomb + 0. 蹦蹦炸弹 JumpyBomb - CD:15s 持续时间:3s - 在持续时间内,攻击类型变为蹦蹦炸弹 - 当蹦蹦炸弹因为碰撞而爆炸,向子弹方向上加上90°,270° 发出2个小炸弹 @@ -223,7 +223,7 @@ $$ #### 喧哗者ANoisyPerson - 普通攻击为 CommonAttackOfGhost - 主动技能 - - 嚎叫 Howl + 0. 嚎叫 Howl - CD:25s - 使用瞬间,在视野半径范围内(不是可视区域)的学生被眩晕5500ms,自己进入800ms的后摇 - 通过眩晕获得对应得分 @@ -233,7 +233,7 @@ $$ #### Idol - 普通攻击为 CommonAttackOfGhost - 主动技能 - - ShowTime + 0. ShowTime - CD: 80s 持续时间:10s - 持续时间内 - 使警戒范围外的学生眩晕并每200ms发送向自己移动200ms的指令(速度为学生本应速度*二者距离/警戒范围) @@ -258,14 +258,14 @@ $$ #### 运动员 - 主动技能 - - 冲撞 CanBeginToCharge + 0. 冲撞 CanBeginToCharge - CD:60s 持续时间:3s - 在持续时间内,速度变为三倍,期间撞到捣蛋鬼,会导致捣蛋鬼眩晕7.22s,学生眩晕2.09s - 通过眩晕获得对应得分 #### 教师 - 主动技能 - - 惩罚 Punish + 0. 惩罚 Punish - CD:30s - 使用瞬间,在可视范围内的翻窗、开锁门、攻击前后摇的捣蛋鬼会被眩晕(3070+300*已受伤害/基本伤害(1500000))ms, - 通过眩晕获得对应得分 @@ -279,22 +279,22 @@ $$ - 当处于可接受指令状态且不在学习时,会积累“冥想进度”,速度为40/ms - 受到攻击(并非伤害)、进入学习状态或进入不可接受指令状态(包括翻窗)冥想进度清零 - 主动技能5 - - 写答案 WriteAnswers + 0. 写答案 WriteAnswers - CD:30s - 使用瞬间,对于可交互范围内的一间教室的作业增加冥想进度,冥想进度清零 - 通过学习获得对应得分 #### 开心果 - 主动技能 - - 唤醒 Rouse + 0. 唤醒 Rouse - CD:120s - 使用瞬间,唤醒可视范围内一个沉迷中的人 - 通过唤醒获得对应得分 - - 勉励 Encourage + 1. 勉励 Encourage - CD:120s - 使用瞬间,为可视范围内随机一个毅力不足的人试图补充750000的毅力值 - 获得勉励750000的毅力值对应得分 - - 鼓舞 Inspire + 2. 鼓舞 Inspire - CD:120s - 使用瞬间,可视范围内学生(包括自己)获得持续6秒的1.6倍速Buff - 每鼓舞一个学生得分10 diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs index c6c0624..d8dea18 100644 --- a/logic/GameClass/GameObj/Character/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -291,7 +291,7 @@ namespace GameClass.GameObj } } #endregion - + #region 状态相关的基本属性与方法 private PlayerStateType playerState = PlayerStateType.Null; public PlayerStateType PlayerState { @@ -318,7 +318,23 @@ namespace GameClass.GameObj private GameObj? whatInteractingWith = null; public GameObj? WhatInteractingWith => whatInteractingWith; + private long threadNum = 0; + public long ThreadNum => threadNum; + public void ChangePlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) + { + lock (gameObjLock) + { + ++threadNum; + whatInteractingWith = gameObj; + if (value != PlayerStateType.Moving) + IsMoving = false; + playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value; + //Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString()); + } + } + + public void ChangePlayerStateInOneThread(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) { lock (gameObjLock) { @@ -334,11 +350,26 @@ namespace GameClass.GameObj { lock (gameObjLock) { + ++threadNum; whatInteractingWith = null; + IsMoving = false; playerState = PlayerStateType.Null; } } + public void RemoveFromGame(PlayerStateType playerStateType) + { + lock (gameObjLock) + { + playerState = playerStateType; + CanMove = false; + IsResetting = true; + Position = GameData.PosWhoDie; + place = PlaceType.Grass; + } + } + #endregion + private int score = 0; public int Score { @@ -572,17 +603,6 @@ namespace GameClass.GameObj this.Vampire = this.OriVampire; } }*/ - public void RemoveFromGame(PlayerStateType playerStateType) - { - lock (gameObjLock) - { - playerState = playerStateType; - CanMove = false; - IsResetting = true; - Position = GameData.PosWhoDie; - place = PlaceType.Grass; - } - } public override bool IsRigid => true; public override ShapeType Shape => ShapeType.Circle; diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs index 443d989..978f6c5 100644 --- a/logic/GameEngine/MoveEngine.cs +++ b/logic/GameEngine/MoveEngine.cs @@ -79,6 +79,8 @@ namespace GameEngine return; if (!obj.IsAvailable || !gameTimer.IsGaming) return; + + long threadNum = (obj.Type == GameObjType.Character) ? ((ICharacter)obj).ThreadNum : 0;//对人特殊处理 new Thread ( () => @@ -123,6 +125,9 @@ namespace GameEngine moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; res = new XY(direction, moveVecLength); + //对人特殊处理 + if (threadNum > 0 && ((ICharacter)obj).ThreadNum != threadNum) return false; + // 越界情况处理:如果越界,则与越界方块碰撞 bool flag; // 循环标志 do diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 68db0be..f39cfcd 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -71,12 +71,13 @@ namespace Gaming ++generatorForFix.NumOfFixing; characterManager.SetPlayerState(player, PlayerStateType.Fixing); + long threadNum = player.ThreadNum; new Thread ( () => { new FrameRateTaskExecutor( - loopCondition: () => gameMap.Timer.IsGaming && player.PlayerState == PlayerStateType.Fixing, + loopCondition: () => gameMap.Timer.IsGaming && threadNum == player.ThreadNum, loopToDo: () => { if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) @@ -170,8 +171,10 @@ namespace Gaming { characterManager.SetPlayerState(playerTreated, PlayerStateType.Treated); characterManager.SetPlayerState(player, PlayerStateType.Treating); + long threadNum = player.ThreadNum; + new FrameRateTaskExecutor( - loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && player.PlayerState == PlayerStateType.Treating && gameMap.Timer.IsGaming, + loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && threadNum == player.ThreadNum && gameMap.Timer.IsGaming, loopToDo: () => { if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player)) @@ -182,7 +185,7 @@ namespace Gaming ) .Start(); - if (player.PlayerState == PlayerStateType.Treating) characterManager.SetPlayerState(player); + if (threadNum == player.ThreadNum) characterManager.SetPlayerState(player); else if (playerTreated.PlayerState == PlayerStateType.Treated) characterManager.SetPlayerState(playerTreated); } ) @@ -200,13 +203,14 @@ namespace Gaming return false; characterManager.SetPlayerState(player, PlayerStateType.Rescuing); characterManager.SetPlayerState(playerRescued, PlayerStateType.Rescued); + long threadNum = player.ThreadNum; new Thread ( () => { new FrameRateTaskExecutor( - loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && player.PlayerState == PlayerStateType.Rescuing && gameMap.Timer.IsGaming, + loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && threadNum == player.ThreadNum && gameMap.Timer.IsGaming, loopToDo: () => { playerRescued.TimeOfRescue += GameData.frameDuration; @@ -228,7 +232,7 @@ namespace Gaming else characterManager.SetPlayerState(playerRescued, PlayerStateType.Addicted); } - if (player.PlayerState == PlayerStateType.Rescuing) characterManager.SetPlayerState(player); + if (threadNum == player.ThreadNum) characterManager.SetPlayerState(player); playerRescued.TimeOfRescue = 0; } ) @@ -297,13 +301,14 @@ namespace Gaming // gameMap.Add(addWall); characterManager.SetPlayerState(player, PlayerStateType.ClimbingThroughWindows); + long threadNum = player.ThreadNum; windowForClimb.WhoIsClimbing = player; new Thread ( () => { new FrameRateTaskExecutor( - loopCondition: () => player.PlayerState == PlayerStateType.ClimbingThroughWindows && gameMap.Timer.IsGaming, + loopCondition: () => threadNum == player.ThreadNum && gameMap.Timer.IsGaming, loopToDo: () => { }, timeInterval: GameData.frameDuration, finallyReturn: () => 0, @@ -322,7 +327,7 @@ namespace Gaming moveEngine.MoveObj(player, (int)(windowToPlayer.Length() * 3.0 * 1000 / player.MoveSpeed), (-1 * windowToPlayer).Angle()); new FrameRateTaskExecutor( - loopCondition: () => player.PlayerState == PlayerStateType.ClimbingThroughWindows && gameMap.Timer.IsGaming, + loopCondition: () => threadNum == player.ThreadNum && gameMap.Timer.IsGaming, loopToDo: () => { }, @@ -336,7 +341,7 @@ namespace Gaming player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); windowForClimb.WhoIsClimbing = null; // gameMap.Remove(addWall); - if (player.PlayerState == PlayerStateType.ClimbingThroughWindows) + if (threadNum == player.ThreadNum) { characterManager.SetPlayerState(player); } @@ -379,12 +384,13 @@ namespace Gaming if (!flag) return false; characterManager.SetPlayerState(player, PlayerStateType.LockingOrOpeningTheDoor); + long threadNum = player.ThreadNum; new Thread ( () => { new FrameRateTaskExecutor( - loopCondition: () => flag && player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor && gameMap.Timer.IsGaming && doorToLock.OpenOrLockDegree < GameData.degreeOfLockingOrOpeningTheDoor, + loopCondition: () => flag && threadNum == player.ThreadNum && gameMap.Timer.IsGaming && doorToLock.OpenOrLockDegree < GameData.degreeOfLockingOrOpeningTheDoor, loopToDo: () => { flag = ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) == null); @@ -399,7 +405,7 @@ namespace Gaming { doorToLock.IsOpen = (!doorToLock.IsOpen); } - if (player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor) + if (threadNum == player.ThreadNum) characterManager.SetPlayerState(player); doorToLock.OpenOrLockDegree = 0; } @@ -472,7 +478,7 @@ namespace Gaming OnCollision: (obj, collisionObj, moveVec) => { SkillWhenColliding((Character)obj, collisionObj); - Preparation.Utility.Debugger.Output(obj, " end move with " + collisionObj.ToString()); + //Preparation.Utility.Debugger.Output(obj, " end move with " + collisionObj.ToString()); //if (collisionObj is Mine) //{ // ActivateMine((Character)obj, (Mine)collisionObj); diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 96be026..e86e429 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -192,12 +192,13 @@ namespace Gaming if (bullet.CastTime > 0) { characterManager.SetPlayerState(player, PlayerStateType.TryingToAttack); + long threadNum = player.ThreadNum; new Thread (() => { new FrameRateTaskExecutor( - loopCondition: () => player.PlayerState == PlayerStateType.TryingToAttack && gameMap.Timer.IsGaming, + loopCondition: () => threadNum == player.ThreadNum && gameMap.Timer.IsGaming, loopToDo: () => { }, @@ -209,7 +210,7 @@ namespace Gaming if (gameMap.Timer.IsGaming) { - if (player.PlayerState == PlayerStateType.TryingToAttack) + if (threadNum == player.ThreadNum) { characterManager.SetPlayerState(player); } diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs index 9f4b984..b0e5c7b 100644 --- a/logic/Gaming/CharacterManager .cs +++ b/logic/Gaming/CharacterManager .cs @@ -20,20 +20,33 @@ namespace Gaming public void SetPlayerState(Character player, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) { - switch (player.PlayerState) + lock (player.MoveLock) { - case PlayerStateType.OpeningTheChest: - ((Chest)player.WhatInteractingWith).StopOpen(); - break; - case PlayerStateType.OpeningTheDoorway: - Doorway doorway = (Doorway)player.WhatInteractingWith; - doorway.OpenDegree += gameMap.Timer.nowTime() - doorway.OpenStartTime; - doorway.OpenStartTime = 0; - break; - default: - break; + switch (player.PlayerState) + { + case PlayerStateType.OpeningTheChest: + ((Chest)player.WhatInteractingWith).StopOpen(); + player.ChangePlayerState(value, gameObj); + break; + case PlayerStateType.OpeningTheDoorway: + Doorway doorway = (Doorway)player.WhatInteractingWith; + doorway.OpenDegree += gameMap.Timer.nowTime() - doorway.OpenStartTime; + doorway.OpenStartTime = 0; + player.ChangePlayerState(value, gameObj); + break; + case PlayerStateType.Addicted: + if (value == PlayerStateType.Rescued) + player.ChangePlayerStateInOneThread(value, gameObj); + break; + case PlayerStateType.Rescued: + if (value == PlayerStateType.Addicted) + player.ChangePlayerStateInOneThread(value, gameObj); + break; + default: + player.ChangePlayerState(value, gameObj); + break; + } } - player.ChangePlayerState(value, gameObj); } public Character? AddPlayer(XY pos, int teamID, int playerID, CharacterType characterType, Character? parent = null) @@ -233,6 +246,7 @@ namespace Gaming } } SetPlayerState(player, PlayerStateType.Addicted); + long threadNum = player.ThreadNum; new Thread (() => { @@ -240,7 +254,7 @@ namespace Gaming Debugger.Output(player, " is addicted "); #endif new FrameRateTaskExecutor( - () => (player.PlayerState == PlayerStateType.Addicted || player.PlayerState == PlayerStateType.Rescued) && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, + () => threadNum == player.ThreadNum && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, () => { player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0; @@ -269,8 +283,9 @@ namespace Gaming (() => { SetPlayerState(player, PlayerStateType.Stunned); + long threadNum = player.ThreadNum; Thread.Sleep(time); - if (player.PlayerState == PlayerStateType.Stunned) + if (threadNum == player.ThreadNum) SetPlayerState(player); } ) @@ -358,13 +373,14 @@ namespace Gaming if (time <= 0) return false; if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false; SetPlayerState(player, PlayerStateType.Swinging); + long threadNum = player.ThreadNum; new Thread (() => { Thread.Sleep(time); - if (player.PlayerState == PlayerStateType.Swinging) + if (threadNum == player.ThreadNum) { SetPlayerState(player); } diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index 4236430..8378eba 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -80,12 +80,7 @@ namespace Gaming Character? player = gameMap.FindPlayerToAction(playerID); if (player != null) { - bool res = actionManager.MovePlayer(player, moveTimeInMilliseconds, angle); -#if DEBUG - Console.WriteLine($"PlayerID:{playerID} move to ({player.Position.x},{player.Position.y})!"); -#endif - return res; - + return actionManager.MovePlayer(player, moveTimeInMilliseconds, angle); } else { diff --git a/logic/Preparation/Interface/ICharacter.cs b/logic/Preparation/Interface/ICharacter.cs index ce2965c..29d087f 100644 --- a/logic/Preparation/Interface/ICharacter.cs +++ b/logic/Preparation/Interface/ICharacter.cs @@ -14,6 +14,7 @@ namespace Preparation.Interface public BulletType BulletOfPlayer { get; set; } public CharacterType CharacterType { get; } public int BulletNum { get; } + public long ThreadNum { get; } public bool IsGhost(); } diff --git a/logic/Server/CopyInfo.cs b/logic/Server/CopyInfo.cs index 77dd8af..42a6b1b 100644 --- a/logic/Server/CopyInfo.cs +++ b/logic/Server/CopyInfo.cs @@ -1,7 +1,5 @@ using Protobuf; -using System.Collections.Generic; using GameClass.GameObj; -using System.Numerics; using Preparation.Utility; using Gaming; diff --git a/logic/cmd/gameServerAndClient.cmd b/logic/cmd/gameServerAndClient.cmd new file mode 100644 index 0000000..71f90c7 --- /dev/null +++ b/logic/cmd/gameServerAndClient.cmd @@ -0,0 +1,7 @@ +@echo off + +start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName test + +ping -n 2 127.0.0.1 > NUL + +start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --port 8888 --characterID 114514 --type 0 --occupation 1 \ No newline at end of file From 9de01bc0303847014c180647db358a9844d9c1ea Mon Sep 17 00:00:00 2001 From: DragonAura Date: Wed, 26 Apr 2023 18:17:54 +0800 Subject: [PATCH 040/105] fix(CAPI): :bug: fix load buffer --- CAPI/cpp/API/include/logic.h | 6 +++--- CAPI/cpp/API/src/logic.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CAPI/cpp/API/include/logic.h b/CAPI/cpp/API/include/logic.h index 5ca41ea..8eef2fc 100644 --- a/CAPI/cpp/API/include/logic.h +++ b/CAPI/cpp/API/include/logic.h @@ -148,9 +148,9 @@ private: void ProcessMessage(); // 将信息加载到buffer - void LoadBufferSelf(const protobuf::MessageToClient& message); - void LoadBufferCase(const protobuf::MessageOfObj& item); - void LoadBuffer(const protobuf::MessageToClient& message); + void LoadBufferSelf(protobuf::MessageToClient message); + void LoadBufferCase(protobuf::MessageOfObj item); + void LoadBuffer(protobuf::MessageToClient message); // 解锁AI线程 void UnBlockAI(); diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index c06eb09..51a6d73 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -398,7 +398,7 @@ void Logic::ProcessMessage() std::thread(messageThread).detach(); } -void Logic::LoadBufferSelf(const protobuf::MessageToClient& message) +void Logic::LoadBufferSelf(protobuf::MessageToClient message) { if (playerType == THUAI6::PlayerType::StudentPlayer) { @@ -432,7 +432,7 @@ void Logic::LoadBufferSelf(const protobuf::MessageToClient& message) } } -void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) +void Logic::LoadBufferCase(protobuf::MessageOfObj item) { int32_t x, y, viewRange; if (playerType == THUAI6::PlayerType::StudentPlayer) @@ -593,7 +593,7 @@ void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) } } -void Logic::LoadBuffer(const protobuf::MessageToClient& message) +void Logic::LoadBuffer(protobuf::MessageToClient message) { // 将消息读入到buffer中 { From 6924a36c7c09719f0773f2e0477e91ee8013a849 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Wed, 26 Apr 2023 18:54:19 +0800 Subject: [PATCH 041/105] fix(CAPI): :bug: add read message buffer --- CAPI/cpp/API/include/Communication.h | 1 + CAPI/cpp/API/include/logic.h | 6 +++--- CAPI/cpp/API/src/Communication.cpp | 3 ++- CAPI/cpp/API/src/logic.cpp | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CAPI/cpp/API/include/Communication.h b/CAPI/cpp/API/include/Communication.h index 2f75e43..7df447b 100644 --- a/CAPI/cpp/API/include/Communication.h +++ b/CAPI/cpp/API/include/Communication.h @@ -52,6 +52,7 @@ private: std::unique_ptr THUAI6Stub; bool haveNewMessage = false; protobuf::MessageToClient message2Client; + protobuf::MessageToClient buffer2Client; std::mutex mtxMessage; std::condition_variable cvMessage; }; diff --git a/CAPI/cpp/API/include/logic.h b/CAPI/cpp/API/include/logic.h index 8eef2fc..5ca41ea 100644 --- a/CAPI/cpp/API/include/logic.h +++ b/CAPI/cpp/API/include/logic.h @@ -148,9 +148,9 @@ private: void ProcessMessage(); // 将信息加载到buffer - void LoadBufferSelf(protobuf::MessageToClient message); - void LoadBufferCase(protobuf::MessageOfObj item); - void LoadBuffer(protobuf::MessageToClient message); + void LoadBufferSelf(const protobuf::MessageToClient& message); + void LoadBufferCase(const protobuf::MessageOfObj& item); + void LoadBuffer(const protobuf::MessageToClient& message); // 解锁AI线程 void UnBlockAI(); diff --git a/CAPI/cpp/API/src/Communication.cpp b/CAPI/cpp/API/src/Communication.cpp index 6bcf8d8..a4ccd3c 100644 --- a/CAPI/cpp/API/src/Communication.cpp +++ b/CAPI/cpp/API/src/Communication.cpp @@ -249,10 +249,11 @@ void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, T grpc::ClientContext context; auto MessageReader = THUAI6Stub->AddPlayer(&context, playerMsg); - while (MessageReader->Read(&message2Client)) + while (MessageReader->Read(&buffer2Client)) { { std::lock_guard lock(mtxMessage); + message2Client = buffer2Client; haveNewMessage = true; } cvMessage.notify_one(); diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 51a6d73..c06eb09 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -398,7 +398,7 @@ void Logic::ProcessMessage() std::thread(messageThread).detach(); } -void Logic::LoadBufferSelf(protobuf::MessageToClient message) +void Logic::LoadBufferSelf(const protobuf::MessageToClient& message) { if (playerType == THUAI6::PlayerType::StudentPlayer) { @@ -432,7 +432,7 @@ void Logic::LoadBufferSelf(protobuf::MessageToClient message) } } -void Logic::LoadBufferCase(protobuf::MessageOfObj item) +void Logic::LoadBufferCase(const protobuf::MessageOfObj& item) { int32_t x, y, viewRange; if (playerType == THUAI6::PlayerType::StudentPlayer) @@ -593,7 +593,7 @@ void Logic::LoadBufferCase(protobuf::MessageOfObj item) } } -void Logic::LoadBuffer(protobuf::MessageToClient message) +void Logic::LoadBuffer(const protobuf::MessageToClient& message) { // 将消息读入到buffer中 { From 1187cdde629e85a10a8f5ad5ccf1cf2a9dc02133 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Wed, 26 Apr 2023 19:45:43 +0800 Subject: [PATCH 042/105] refactor(CAPI): :fire: remove class variable buffer2Client --- CAPI/cpp/API/include/Communication.h | 1 - CAPI/cpp/API/src/Communication.cpp | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CAPI/cpp/API/include/Communication.h b/CAPI/cpp/API/include/Communication.h index 7df447b..2f75e43 100644 --- a/CAPI/cpp/API/include/Communication.h +++ b/CAPI/cpp/API/include/Communication.h @@ -52,7 +52,6 @@ private: std::unique_ptr THUAI6Stub; bool haveNewMessage = false; protobuf::MessageToClient message2Client; - protobuf::MessageToClient buffer2Client; std::mutex mtxMessage; std::condition_variable cvMessage; }; diff --git a/CAPI/cpp/API/src/Communication.cpp b/CAPI/cpp/API/src/Communication.cpp index a4ccd3c..f808e22 100644 --- a/CAPI/cpp/API/src/Communication.cpp +++ b/CAPI/cpp/API/src/Communication.cpp @@ -249,11 +249,13 @@ void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, T grpc::ClientContext context; auto MessageReader = THUAI6Stub->AddPlayer(&context, playerMsg); + protobuf::MessageToClient buffer2Client; + while (MessageReader->Read(&buffer2Client)) { { std::lock_guard lock(mtxMessage); - message2Client = buffer2Client; + message2Client = std::move(buffer2Client); haveNewMessage = true; } cvMessage.notify_one(); From b4bb327a45bc7d7d4cc6635050e97eb3be3693d2 Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 00:05:36 +0800 Subject: [PATCH 043/105] chore: add startlockfile in server --- logic/Server/ArgumentOption.cs | 3 +++ logic/Server/GameServer.cs | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/logic/Server/ArgumentOption.cs b/logic/Server/ArgumentOption.cs index 2dddf7d..fa680b1 100644 --- a/logic/Server/ArgumentOption.cs +++ b/logic/Server/ArgumentOption.cs @@ -71,5 +71,8 @@ namespace Server [Option("resultFileName", Required = false, HelpText = "Result file name, saved as .json")] public string ResultFileName { get; set; } = DefaultArgumentOptions.FileName; + + [Option("startLockFile", Required = false, HelpText = "Whether to create a file that identifies whether the game has started")] + public string StartLockFile { get; set; } = DefaultArgumentOptions.FileName; } } \ No newline at end of file diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index b81bfe7..080ae7b 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -45,6 +45,7 @@ namespace Server if (id == GameObj.invalidID) return; //如果有未初始化的玩家,不开始游戏 } Console.WriteLine("Game starts!"); + CreateStartFile(); game.StartGame((int)options.GameTimeInSecond * 1000); Thread.Sleep(1); new Thread(() => @@ -74,6 +75,16 @@ namespace Server }) { IsBackground = true }.Start(); } + + public void CreateStartFile() + { + if (options.StartLockFile != DefaultArgumentOptions.FileName) + { + using var _ = File.Create(options.StartLockFile); + Console.WriteLine("Successfully Created StartLockFile!"); + } + } + public void WaitForEnd() { this.endGameSem.Wait(); From 06e326e0ab0d346398575bfe551899dce0d35e73 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Thu, 27 Apr 2023 00:10:28 +0800 Subject: [PATCH 044/105] Update run.sh --- dependency/shell/run.sh | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 70a1286..5b44566 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -3,7 +3,7 @@ python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI playback_dir=/usr/local/playback -nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video > $playback_dir/server.log & +nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & server_pid=$! sleep 5 for k in {1..2} @@ -39,12 +39,20 @@ do popd done -ps -p $server_pid -while [ $? -eq 0 ] -do - sleep 1 - ps -p $server_pid -done +sleep 10 -touch $playback_dir/finish.lock -echo "Finish" +if [ -f $playback_dir/start.lock ]; then + ps -p $server_pid + while [ $? -eq 0 ] + do + sleep 1 + ps -p $server_pid + done + touch $playback_dir/finish.lock + echo "Finish" +else + echo "Failed to start game." + touch temp.lock + mv -f temp.lock $playback_dir/video.thuaipb + kill -9 $server_pid +fi From 5cdddd66670fc48c5e351ab84be64f3053eaa6d4 Mon Sep 17 00:00:00 2001 From: gsy1519 <614054460@qq.com> Date: Thu, 27 Apr 2023 00:20:41 +0800 Subject: [PATCH 045/105] fix: change AllowSpectator to NotAllowSpectator and restrict deceased student sending message --- logic/Server/ArgumentOption.cs | 4 ++-- logic/Server/GameServer.cs | 20 +++++++++++++++++--- logic/Server/RpcServices.cs | 4 ++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/logic/Server/ArgumentOption.cs b/logic/Server/ArgumentOption.cs index c39204e..a9032c8 100644 --- a/logic/Server/ArgumentOption.cs +++ b/logic/Server/ArgumentOption.cs @@ -39,8 +39,8 @@ namespace Server [Option('f', "fileName", Required = false, HelpText = "The file to store playback file or to read file.")] public string FileName { get; set; } = DefaultArgumentOptions.FileName; - [Option('s', "allowSpectator", Required = false, HelpText = "Whether to allow a spectator to watch the game.")] - public bool AllowSpectator { get; set; } = false; + [Option("notAllowSpectator", Required = false, HelpText = "Whether to allow a spectator to watch the game.")] + public bool NotAllowSpectator { get; set; } = false; [Option('b', "playback", Required = false, HelpText = "Whether open the server in a playback mode.")] public bool Playback { get; set; } = false; diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index b81bfe7..b7e3048 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -168,6 +168,23 @@ namespace Server kvp.Value.Item2.Wait(); } } + private bool playerDeceased(int playerID) + { + game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); + try + { + foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) + { + if (character.PlayerID == playerID && character.PlayerState == PlayerStateType.Deceased) return true; + } + } + finally + { + game.GameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); + } + return false; + } + public int[] GetScore() { int[] score = new int[2]; // 0代表Student,1代表Tricker @@ -222,9 +239,6 @@ namespace Server int[] score = GetScore(); msg.StudentScore = score[0]; msg.TrickerScore = score[1]; - //msg.GateOpened - //msg.HiddenGateRefreshed - //msg.HiddenGateOpened return msg; } diff --git a/logic/Server/RpcServices.cs b/logic/Server/RpcServices.cs index 0e95b63..44de1bd 100644 --- a/logic/Server/RpcServices.cs +++ b/logic/Server/RpcServices.cs @@ -56,7 +56,7 @@ namespace Server { Console.WriteLine($"AddPlayer: {request.PlayerId}"); - if (request.PlayerId >= spectatorMinPlayerID && options.AllowSpectator == true) + if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) { // 观战模式 uint tp = (uint)request.PlayerId; @@ -194,7 +194,7 @@ namespace Server public override Task SendMessage(SendMsg request, ServerCallContext context) { var boolRes = new BoolRes(); - if (request.PlayerId >= spectatorMinPlayerID) + if (request.PlayerId >= spectatorMinPlayerID || playerDeceased((int)request.PlayerId)) { boolRes.ActSuccess = false; return Task.FromResult(boolRes); From 89f1ef8075f9b362c2e19e8cbc12ec3af636e85e Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Thu, 27 Apr 2023 00:20:48 +0800 Subject: [PATCH 046/105] docs: :memo: add constant --- CAPI/cpp/API/include/constants.h | 54 ++++++++++++++++++++++++++ CAPI/cpp/API/src/AI.cpp | 2 +- CAPI/python/PyAPI/AI.py | 2 +- CAPI/python/PyAPI/constants.py | 65 ++++++++++++++++++++++++++------ docs/GameRules.md | 14 +++---- docs/QandA.md | 3 ++ docs/使用文档.md | 2 + 7 files changed, 122 insertions(+), 20 deletions(-) diff --git a/CAPI/cpp/API/include/constants.h b/CAPI/cpp/API/include/constants.h index 1bf0cd6..19b8331 100644 --- a/CAPI/cpp/API/include/constants.h +++ b/CAPI/cpp/API/include/constants.h @@ -303,5 +303,59 @@ namespace Constants SCCI int skillCD = commonSkillCD * 1; SCCI int durationTime = commonSkillTime * 0; }; + + struct CommonAttackOfTricker + { + SCCI double BulletBombRange = 0; + SCCI double BulletAttackRange = basicAttackShortRange; + SCCI int ap = basicApOfTricker; + SCCI int Speed = basicBulletMoveSpeed; + SCCI bool IsRemoteAttack = false; + + SCCI int CastTime = (int)BulletAttackRange * 1000 / Speed; + SCCI int Backswing =basicBackswing; + SCCI int RecoveryFromHit =basicRecoveryFromHit; + SCCI int cd = basicBackswing; + SCCI int maxBulletNum = 1; + }; + + struct FlyingKnife + { + SCCI double BulletBombRange = 0; + SCCI double BulletAttackRange = basicRemoteAttackRange * 13; + SCCI int ap = basicApOfTricker* 4 / 5; + SCCI int Speed = basicBulletMoveSpeed* 25 / 10; + SCCI bool IsRemoteAttack = true; + + SCCI int CastTime = basicCastTime * 4 / 5; + SCCI int Backswing =0; + SCCI int RecoveryFromHit =0; + SCCI int cd = basicBackswing / 2; + SCCI int maxBulletNum = 1; + }; + + struct BombBomb + { + SCCI double BulletBombRange = basicBulletBombRange; + SCCI double BulletAttackRange = basicAttackShortRange; + SCCI int ap = basicApOfTricker * 6 / 5; + SCCI int Speed = basicBulletMoveSpeed* 30 / 37; + SCCI bool IsRemoteAttack = false; + + SCCI int CastTime = (int)BulletAttackRange * 1000 / Speed; + SCCI int Backswing =basicRecoveryFromHit; + SCCI int RecoveryFromHit =basicRecoveryFromHit; + SCCI int cd = basicCD; + SCCI int maxBulletNum = 1; + }; + + struct JumpyDumpty + { + SCCI double BulletBombRange = basicBulletBombRange / 2; + SCCI double BulletAttackRange = basicRemoteAttackRange * 2; + SCCI int ap = (int)(basicApOfTricker* 0.6); + SCCI int Speed = basicBulletMoveSpeed* 43 / 37; + SCCI bool IsRemoteAttack = false; + }; } // namespace Constants #endif diff --git a/CAPI/cpp/API/src/AI.cpp b/CAPI/cpp/API/src/AI.cpp index c37b914..19b8208 100644 --- a/CAPI/cpp/API/src/AI.cpp +++ b/CAPI/cpp/API/src/AI.cpp @@ -20,7 +20,7 @@ extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin; // 可以在AI.cpp内部声明变量与函数 -void AI::play(IStudentAPI& api) +void AI::play(IStudentAPI& api)//每帧执行一次AI::play(IStudentAPI& api)或AI::play(ITrickerAPI& api)(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 { // 公共操作 if (this->playerID == 0) diff --git a/CAPI/python/PyAPI/AI.py b/CAPI/python/PyAPI/AI.py index efa1a1a..09af335 100644 --- a/CAPI/python/PyAPI/AI.py +++ b/CAPI/python/PyAPI/AI.py @@ -41,7 +41,7 @@ class AssistFunction: class AI(IAI): def __init__(self, pID: int): self.__playerID = pID - + # 每帧执行一次StudentPlay或TrickerPlay(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 def StudentPlay(self, api: IStudentAPI) -> None: # 公共操作 if self.__playerID == 0: diff --git a/CAPI/python/PyAPI/constants.py b/CAPI/python/PyAPI/constants.py index 9426e73..eadf4b8 100644 --- a/CAPI/python/PyAPI/constants.py +++ b/CAPI/python/PyAPI/constants.py @@ -51,22 +51,22 @@ class Constants(NoInstance): # 攻击相关 - basicApOfTricker = 1500000 - basicCD = 3000 # 初始子弹冷却 - basicCastTime = 500 # 基本前摇时间 - basicBackswing = 800 # 基本后摇时间 - basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长 + Constants.basicApOfTricker = 1500000 + Constants.basicCD = 3000 # 初始子弹冷却 + Constants.basicCastTime = 500 # 基本前摇时间 + Constants.basicBackswing = 800 # 基本后摇时间 + Constants.basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长 basicStunnedTimeOfStudent = 4300 - basicBulletmoveSpeed = 7400 # 基本子弹移动速度 - basicRemoteAttackRange = 6000 # 基本远程攻击范围 - basicAttackShortRange = 2200 # 基本近程攻击范围 - basicBulletBombRange = 2000 # 基本子弹爆炸范围 + Constants.basicBulletMoveSpeed = 7400 # 基本子弹移动速度 + Constants.basicRemoteAttackRange = 6000 # 基本远程攻击范围 + Constants.basicAttackShortRange = 2200 # 基本近程攻击范围 + Constants.basicBulletBombRange = 2000 # 基本子弹爆炸范围 # 道具相关 - apPropAdd = basicApOfTricker * 12 / 10 - apSpearAdd = basicApOfTricker * 6 / 10 + apPropAdd = Constants.basicApOfTricker * 12 / 10 + apSpearAdd = Constants.basicApOfTricker * 6 / 10 # 技能相关 maxNumOfSkill = 3 @@ -298,3 +298,46 @@ class WriteAnswers: class SummonGolem: skillCD = (int)(1.0 * Constants.commonSkillCD) durationTime = (int)(0.0 * Constants.commonSkillTime) + +class CommonAttackOfTricker: + BulletBombRange = 0 + BulletAttackRange = Constants.Constants.basicAttackShortRange + ap = Constants.basicApOfTricker + Speed = Constants.basicBulletMoveSpeed + IsRemoteAttack = False + CastTime = BulletAttackRange * 1000 / Speed + Backswing =Constants.basicBackswing + RecoveryFromHit =Constants.basicRecoveryFromHit + cd = Constants.basicBackswing + maxBulletNum = 1 + +class FlyingKnife: + BulletBombRange = 0 + BulletAttackRange = Constants.basicRemoteAttackRange * 13 + ap = Constants.basicApOfTricker* 4 / 5 + Speed = Constants.basicBulletMoveSpeed* 25 / 10 + IsRemoteAttack = True + CastTime = Constants.basicCastTime * 4 / 5 + Backswing =0 + RecoveryFromHit =0 + cd = Constants.basicBackswing / 2 + maxBulletNum = 1 + +class BombBomb: + BulletBombRange = Constants.basicBulletBombRange + BulletAttackRange = Constants.basicAttackShortRange + ap = Constants.basicApOfTricker * 6 / 5 + Speed = Constants.basicBulletMoveSpeed* 30 / 37 + IsRemoteAttack = False + CastTime = BulletAttackRange * 1000 / Speed + Backswing =Constants.basicRecoveryFromHit + RecoveryFromHit =Constants.basicRecoveryFromHit + cd = Constants.basicCD + maxBulletNum = 1 + +class JumpyDumpty: + BulletBombRange = Constants.basicBulletBombRange / 2 + BulletAttackRange = Constants.basicRemoteAttackRange * 2 + ap = (int)(Constants.basicApOfTricker* 0.6) + Speed = Constants.basicBulletMoveSpeed* 43 / 37 + IsRemoteAttack = False \ No newline at end of file diff --git a/docs/GameRules.md b/docs/GameRules.md index 464632f..c88870f 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -1,5 +1,5 @@ # 规则 -V5.4 +V5.5 - [规则](#规则) - [简则](#简则) - [地图](#地图) @@ -89,10 +89,10 @@ $$ 8. 翻窗 Climbing ### 攻击 -- 攻击类型CommonAttackOfGhost攻击未写完的作业,会造成对应攻击力的损坏 +- 攻击类型CommonAttackOfTricker攻击未写完的作业,会造成对应攻击力的损坏 - 捣蛋鬼攻击交互状态或前后摇的学生,将使学生眩晕4.3s -| 攻击(子弹)类型 |搞蛋鬼的一般攻击CommonAttackOfGhost| 飞刀FlyingKnife | 蹦蹦炸弹BombBomb | 小炸弹JumpyDumpty | +| 攻击(子弹)类型 |搞蛋鬼的一般攻击CommonAttackOfTricker| 飞刀FlyingKnife | 蹦蹦炸弹BombBomb | 小炸弹JumpyDumpty | | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | 子弹爆炸范围 | 0 | 0 | 2000 | 1000 | | 子弹攻击距离 | 2200 | 78000 | 2200 | 4400 | @@ -199,7 +199,7 @@ $$ | 翻箱速度/ms | 1000 | 1100 | 1000 |1000| #### Assassin -- 普通攻击为 CommonAttackOfGhost +- 普通攻击为 CommonAttackOfTricker - 主动技能 0. 隐身 BecomeInvisible - CD:40s 持续时间:10s @@ -211,7 +211,7 @@ $$ - 不直接得分 #### Klee -- 普通攻击为 CommonAttackOfGhost +- 普通攻击为 CommonAttackOfTricker - 主动技能 0. 蹦蹦炸弹 JumpyBomb - CD:15s 持续时间:3s @@ -221,7 +221,7 @@ $$ - 不直接得分,通过眩晕等获得对应得分 #### 喧哗者ANoisyPerson -- 普通攻击为 CommonAttackOfGhost +- 普通攻击为 CommonAttackOfTricker - 主动技能 0. 嚎叫 Howl - CD:25s @@ -231,7 +231,7 @@ $$ - 在场所有学生Bgm系统被设为无用的值 #### Idol -- 普通攻击为 CommonAttackOfGhost +- 普通攻击为 CommonAttackOfTricker - 主动技能 0. ShowTime - CD: 80s 持续时间:10s diff --git a/docs/QandA.md b/docs/QandA.md index 1ccc5c8..ae141da 100644 --- a/docs/QandA.md +++ b/docs/QandA.md @@ -18,6 +18,9 @@ Q: 怎么修改.cmd参数? A: 见选手包中的使用文档部分 +Q:卡死在第一帧不动 + +A:大概率是你的代码死循环了 Q: 怎么开始游戏? diff --git a/docs/使用文档.md b/docs/使用文档.md index 2f1205e..9edc8ae 100644 --- a/docs/使用文档.md +++ b/docs/使用文档.md @@ -17,6 +17,7 @@ - Linux:首先自行安装`gRPC`,具体方法可以参考官方教程https://grpc.io/docs/languages/cpp/quickstart/。 - 然后在`CAPI\cpp\API\src\AI.cpp`中编写代码 - 选手不应当修改`AI.cpp`中原来有的代码,除了`void AI::play(IStudentAPI& api)`和`void AI::play(ITrickerAPI& api)` + - 每帧执行一次`AI::play(IStudentAPI& api)`或`AI::play(ITrickerAPI& api)`(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 - 选手可以在`AI.cpp`内`void AI::play`外新增函数和变量 - Windows:然后用Visual Studio打开`CAPI\cpp\CAPI.sln`编译,注意使用Debug模式 - Linux:用`cmake`,对`CAPI\cpp\CMakeLists.txt`进行编译 @@ -28,6 +29,7 @@ - 首先在Python环境下运行`GeneratePythonProto.cmd`,以安装必要的包、并生成对应的grpc python文件 - 然后在`CAPI\python\PyAPI\AI.py`中编写代码 - 选手不应当修改`AI.py`中原来有的代码,除了`StudentPlay(self, api: IStudentAPI)`和`TrickerPlay(self, api: ITrickerAPI)` + - 每帧执行一次`AI::play(IStudentAPI& api)`或`AI::play(ITrickerAPI& api)`(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 - 选手可以在`AI.py`内新增函数和变量 - Windows:最后通过运行`RunPython.cmd`执行比赛代码 - Linux:通过运行`RunPython.sh`执行比赛代码 From 6a9c2bc48bd2f00ab149ca0d0209fd3d0bef81a9 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Thu, 27 Apr 2023 00:30:03 +0800 Subject: [PATCH 047/105] style: :art: format --- CAPI/cpp/API/include/constants.h | 28 ++++++++++++++-------------- CAPI/cpp/API/src/AI.cpp | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/CAPI/cpp/API/include/constants.h b/CAPI/cpp/API/include/constants.h index 19b8331..d9407dd 100644 --- a/CAPI/cpp/API/include/constants.h +++ b/CAPI/cpp/API/include/constants.h @@ -313,48 +313,48 @@ namespace Constants SCCI bool IsRemoteAttack = false; SCCI int CastTime = (int)BulletAttackRange * 1000 / Speed; - SCCI int Backswing =basicBackswing; - SCCI int RecoveryFromHit =basicRecoveryFromHit; + SCCI int Backswing = basicBackswing; + SCCI int RecoveryFromHit = basicRecoveryFromHit; SCCI int cd = basicBackswing; SCCI int maxBulletNum = 1; }; - + struct FlyingKnife { SCCI double BulletBombRange = 0; SCCI double BulletAttackRange = basicRemoteAttackRange * 13; - SCCI int ap = basicApOfTricker* 4 / 5; - SCCI int Speed = basicBulletMoveSpeed* 25 / 10; + SCCI int ap = basicApOfTricker * 4 / 5; + SCCI int Speed = basicBulletMoveSpeed * 25 / 10; SCCI bool IsRemoteAttack = true; SCCI int CastTime = basicCastTime * 4 / 5; - SCCI int Backswing =0; - SCCI int RecoveryFromHit =0; + SCCI int Backswing = 0; + SCCI int RecoveryFromHit = 0; SCCI int cd = basicBackswing / 2; SCCI int maxBulletNum = 1; }; - + struct BombBomb { SCCI double BulletBombRange = basicBulletBombRange; SCCI double BulletAttackRange = basicAttackShortRange; SCCI int ap = basicApOfTricker * 6 / 5; - SCCI int Speed = basicBulletMoveSpeed* 30 / 37; + SCCI int Speed = basicBulletMoveSpeed * 30 / 37; SCCI bool IsRemoteAttack = false; SCCI int CastTime = (int)BulletAttackRange * 1000 / Speed; - SCCI int Backswing =basicRecoveryFromHit; - SCCI int RecoveryFromHit =basicRecoveryFromHit; + SCCI int Backswing = basicRecoveryFromHit; + SCCI int RecoveryFromHit = basicRecoveryFromHit; SCCI int cd = basicCD; SCCI int maxBulletNum = 1; }; - + struct JumpyDumpty { SCCI double BulletBombRange = basicBulletBombRange / 2; SCCI double BulletAttackRange = basicRemoteAttackRange * 2; - SCCI int ap = (int)(basicApOfTricker* 0.6); - SCCI int Speed = basicBulletMoveSpeed* 43 / 37; + SCCI int ap = (int)(basicApOfTricker * 0.6); + SCCI int Speed = basicBulletMoveSpeed * 43 / 37; SCCI bool IsRemoteAttack = false; }; } // namespace Constants diff --git a/CAPI/cpp/API/src/AI.cpp b/CAPI/cpp/API/src/AI.cpp index 19b8208..6895409 100644 --- a/CAPI/cpp/API/src/AI.cpp +++ b/CAPI/cpp/API/src/AI.cpp @@ -20,7 +20,7 @@ extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin; // 可以在AI.cpp内部声明变量与函数 -void AI::play(IStudentAPI& api)//每帧执行一次AI::play(IStudentAPI& api)或AI::play(ITrickerAPI& api)(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 +void AI::play(IStudentAPI& api) // 每帧执行一次AI::play(IStudentAPI& api)或AI::play(ITrickerAPI& api)(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 { // 公共操作 if (this->playerID == 0) From 7c3337ea19e32541cb7b1a51f5963d21f218fecb Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 00:36:29 +0800 Subject: [PATCH 048/105] build: update dockerfile --- dependency/Dockerfile/Dockerfile_run | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dependency/Dockerfile/Dockerfile_run b/dependency/Dockerfile/Dockerfile_run index 4efce6b..7d29dde 100644 --- a/dependency/Dockerfile/Dockerfile_run +++ b/dependency/Dockerfile/Dockerfile_run @@ -1,6 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0.408-jammy-amd64 AS build +MAINTAINER eesast +WORKDIR /usr/local +COPY . . +RUN dotnet publish logic/Server/Server.csproj -c Release -o /usr/local/Server + FROM eesast/thuai6_base:base MAINTAINER eesast WORKDIR /usr/local +COPY --from=build /usr/local/Server . RUN mkdir /usr/local/team1 && mkdir /usr/local/team2 && mkdir /usr/local/playback COPY ./dependency/shell/run.sh . COPY ./CAPI/python /usr/local/PlayerCode/CAPI/python @@ -10,7 +17,4 @@ WORKDIR /usr/local/PlayerCode/CAPI/python RUN bash ../../dependency/shell/generate_proto.sh WORKDIR /usr/local -RUN wget -P . https://cloud.tsinghua.edu.cn/f/e48940314a6d4cdb8bd0/?dl=1 -RUN mv 'index.html?dl=1' Server.tar.gz -RUN tar -zxvf Server.tar.gz ENTRYPOINT [ "bash","./run.sh" ] From 5b4d8c8ca507c6e2be4e35d7160212094e66a8cc Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 00:46:25 +0800 Subject: [PATCH 049/105] fix: docker build server --- dependency/Dockerfile/Dockerfile_run | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency/Dockerfile/Dockerfile_run b/dependency/Dockerfile/Dockerfile_run index 7d29dde..e4689da 100644 --- a/dependency/Dockerfile/Dockerfile_run +++ b/dependency/Dockerfile/Dockerfile_run @@ -2,12 +2,12 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0.408-jammy-amd64 AS build MAINTAINER eesast WORKDIR /usr/local COPY . . -RUN dotnet publish logic/Server/Server.csproj -c Release -o /usr/local/Server +RUN dotnet publish logic/Server/Server.csproj -c Release -o /usr/local/Server --self-contained true FROM eesast/thuai6_base:base MAINTAINER eesast WORKDIR /usr/local -COPY --from=build /usr/local/Server . +COPY --from=build /usr/local/Server/* . RUN mkdir /usr/local/team1 && mkdir /usr/local/team2 && mkdir /usr/local/playback COPY ./dependency/shell/run.sh . COPY ./CAPI/python /usr/local/PlayerCode/CAPI/python From e2f02514701e006e754e13bbe25527b1dad15e3c Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 00:52:43 +0800 Subject: [PATCH 050/105] fix: docker build on linux --- dependency/Dockerfile/Dockerfile_run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency/Dockerfile/Dockerfile_run b/dependency/Dockerfile/Dockerfile_run index e4689da..31ed2ab 100644 --- a/dependency/Dockerfile/Dockerfile_run +++ b/dependency/Dockerfile/Dockerfile_run @@ -2,7 +2,7 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0.408-jammy-amd64 AS build MAINTAINER eesast WORKDIR /usr/local COPY . . -RUN dotnet publish logic/Server/Server.csproj -c Release -o /usr/local/Server --self-contained true +RUN dotnet publish logic/Server/Server.csproj -c Release -o /usr/local/Server --self-contained true -r linux-x64 FROM eesast/thuai6_base:base MAINTAINER eesast From a2f522135d956491f579f6fdbc234db107276116 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Thu, 27 Apr 2023 00:54:41 +0800 Subject: [PATCH 051/105] docs: :memo: fix constants.py --- CAPI/python/PyAPI/constants.py | 22 +++++++++++----------- docs/使用文档.md | 4 +--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/CAPI/python/PyAPI/constants.py b/CAPI/python/PyAPI/constants.py index eadf4b8..5354d75 100644 --- a/CAPI/python/PyAPI/constants.py +++ b/CAPI/python/PyAPI/constants.py @@ -51,22 +51,22 @@ class Constants(NoInstance): # 攻击相关 - Constants.basicApOfTricker = 1500000 - Constants.basicCD = 3000 # 初始子弹冷却 - Constants.basicCastTime = 500 # 基本前摇时间 - Constants.basicBackswing = 800 # 基本后摇时间 - Constants.basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长 + basicApOfTricker = 1500000 + basicCD = 3000 # 初始子弹冷却 + basicCastTime = 500 # 基本前摇时间 + basicBackswing = 800 # 基本后摇时间 + basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长 basicStunnedTimeOfStudent = 4300 - Constants.basicBulletMoveSpeed = 7400 # 基本子弹移动速度 - Constants.basicRemoteAttackRange = 6000 # 基本远程攻击范围 - Constants.basicAttackShortRange = 2200 # 基本近程攻击范围 - Constants.basicBulletBombRange = 2000 # 基本子弹爆炸范围 + basicBulletMoveSpeed = 7400 # 基本子弹移动速度 + basicRemoteAttackRange = 6000 # 基本远程攻击范围 + basicAttackShortRange = 2200 # 基本近程攻击范围 + basicBulletBombRange = 2000 # 基本子弹爆炸范围 # 道具相关 - apPropAdd = Constants.basicApOfTricker * 12 / 10 - apSpearAdd = Constants.basicApOfTricker * 6 / 10 + apPropAdd = basicApOfTricker * 12 / 10 + apSpearAdd = basicApOfTricker * 6 / 10 # 技能相关 maxNumOfSkill = 3 diff --git a/docs/使用文档.md b/docs/使用文档.md index 9edc8ae..12aa824 100644 --- a/docs/使用文档.md +++ b/docs/使用文档.md @@ -7,9 +7,7 @@ - 不要使用conio.h,Windows.h ## 请注意下载器不更新AI.py,AI.cpp和脚本 -- 最新版AI.cpp和AI.py -![AIcpp](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/AIcpp.png) -![AIpy](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/AIpy.png) +- [最新版AI.cpp云盘](https://cloud.tsinghua.edu.cn/lib/54b4eb7b-956e-474c-b932-7b1ac29a9267/file/AI.cpp) 和[AI.py云盘](https://cloud.tsinghua.edu.cn/lib/54b4eb7b-956e-474c-b932-7b1ac29a9267/file/AI.py) ## C++接口使用说明 From 2f623ca002caeed620bbe5fc9e1863f05f48fefa Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 00:57:21 +0800 Subject: [PATCH 052/105] fix: fix copy server in docker --- dependency/Dockerfile/Dockerfile_run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency/Dockerfile/Dockerfile_run b/dependency/Dockerfile/Dockerfile_run index 31ed2ab..001d93a 100644 --- a/dependency/Dockerfile/Dockerfile_run +++ b/dependency/Dockerfile/Dockerfile_run @@ -7,7 +7,7 @@ RUN dotnet publish logic/Server/Server.csproj -c Release -o /usr/local/Server -- FROM eesast/thuai6_base:base MAINTAINER eesast WORKDIR /usr/local -COPY --from=build /usr/local/Server/* . +COPY --from=build /usr/local/Server . RUN mkdir /usr/local/team1 && mkdir /usr/local/team2 && mkdir /usr/local/playback COPY ./dependency/shell/run.sh . COPY ./CAPI/python /usr/local/PlayerCode/CAPI/python From 0ce7e3716dca4bfe85c45d5708a8ac7a9815c347 Mon Sep 17 00:00:00 2001 From: BlitherBoom812 Date: Thu, 27 Apr 2023 02:19:29 +0800 Subject: [PATCH 053/105] add result.json --- dependency/shell/run.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 5b44566..7ee81e0 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -56,3 +56,8 @@ else mv -f temp.lock $playback_dir/video.thuaipb kill -9 $server_pid fi + +result=$(cat /usr/local/playback/result.json) +score0=$(parse_json $result "Student") +score1=$(parse_json $result "Tricker") +curl $URL -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"result":[{"team_id":0, "score":'${score0}'}, {"team_id":1, "score":'${score1}'}], "mode":'${MODE}'}' \ No newline at end of file From 9dbe08c67d72f6ac5d210f0134ffa404bc179cbf Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 02:33:49 +0800 Subject: [PATCH 054/105] fix!: :bug: fix deadlock problem of spectator --- logic/Client/Properties/launchSettings.json | 4 +- logic/Server/GameServer.cs | 24 +++++++---- logic/Server/Properties/launchSettings.json | 4 +- logic/Server/RpcServices.cs | 47 +++++++++++++++------ 4 files changed, 53 insertions(+), 26 deletions(-) diff --git a/logic/Client/Properties/launchSettings.json b/logic/Client/Properties/launchSettings.json index 5cdc367..59aa8f1 100644 --- a/logic/Client/Properties/launchSettings.json +++ b/logic/Client/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Client": { "commandName": "Project", - "commandLineArgs": "--port 8888 --characterID 3 --type 1 --occupation 5" + "commandLineArgs": "--port 8892 --characterID 8880 --type 1 --occupation 1 --ip thuai6.eesast.com --cl" } } -} +} \ No newline at end of file diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index 5a6c14a..49e8614 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -11,14 +11,15 @@ using Playback; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Preparation.Interface; +using System.Collections.Concurrent; namespace Server { public partial class GameServer : AvailableService.AvailableServiceBase { - private Dictionary semaDict = new(); - private object semaDictLock = new(); + private ConcurrentDictionary semaDict = new(); + // private object semaDictLock = new(); protected readonly ArgumentOptions options; private HttpSender? httpSender; private object gameLock = new(); @@ -29,13 +30,13 @@ namespace Server private SemaphoreSlim endGameSem = new(0); protected readonly Game game; private uint spectatorMinPlayerID = 2023; - private List spectatorList = new List(); public int playerNum; public int TeamCount => options.TeamCount; protected long[] communicationToGameID; // 通信用的ID映射到游戏内的ID,通信中0-3为Student,4为Tricker private readonly object messageToAllClientsLock = new(); public static readonly long SendMessageToClientIntervalInMilliseconds = 50; private MessageWriter? mwr = null; + private object spetatorJoinLock = new(); public void StartGame() { @@ -169,14 +170,19 @@ namespace Server break; } } - foreach (var kvp in semaDict) + lock (spetatorJoinLock) { - kvp.Value.Item1.Release(); - } + foreach (var kvp in semaDict) + { + kvp.Value.Item1.Release(); + } - foreach (var kvp in semaDict) - { - kvp.Value.Item2.Wait(); + // 若此时观战者加入,则死锁,所以需要 spetatorJoinLock + + foreach (var kvp in semaDict) + { + kvp.Value.Item2.Wait(); + } } } private bool playerDeceased(int playerID) diff --git a/logic/Server/Properties/launchSettings.json b/logic/Server/Properties/launchSettings.json index d126864..97ec2d3 100644 --- a/logic/Server/Properties/launchSettings.json +++ b/logic/Server/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Server": { "commandName": "Project", - "commandLineArgs": "--ip 0.0.0.0 -p 8888 --characterID 2030" + "commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName video" } } -} +} \ No newline at end of file diff --git a/logic/Server/RpcServices.cs b/logic/Server/RpcServices.cs index 44de1bd..cac7984 100644 --- a/logic/Server/RpcServices.cs +++ b/logic/Server/RpcServices.cs @@ -16,6 +16,7 @@ namespace Server { public partial class GameServer : AvailableService.AvailableServiceBase { + private int playerCountNow = 0; protected object spectatorLock = new object(); protected bool isSpectatorJoin = false; protected bool IsSpectatorJoin @@ -59,17 +60,18 @@ namespace Server if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) { // 观战模式 - uint tp = (uint)request.PlayerId; - if (!spectatorList.Contains(tp)) + lock (spetatorJoinLock) // 具体原因见另一个上锁的地方 { - spectatorList.Add(tp); - Console.WriteLine("A new spectator comes to watch this game."); - var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)); - lock (semaDictLock) + if (semaDict.TryAdd(request.PlayerId, (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)))) { - semaDict.Add(request.PlayerId, temp); + Console.WriteLine("A new spectator comes to watch this game."); + IsSpectatorJoin = true; + } + else + { + Console.WriteLine($"Duplicated Spectator ID {request.PlayerId}"); + return; } - IsSpectatorJoin = true; } do { @@ -82,13 +84,30 @@ namespace Server //Console.WriteLine("Send!"); } } + catch (InvalidOperationException) + { + if (semaDict.TryRemove(request.PlayerId, out var semas)) + { + try + { + semas.Item1.Release(); + semas.Item2.Release(); + } + catch { } + Console.WriteLine($"The spectator {request.PlayerId} exited"); + } + } catch (Exception) { - //Console.WriteLine(ex); + // Console.WriteLine(ex); } finally { - semaDict[request.PlayerId].Item2.Release(); + try + { + semaDict[request.PlayerId].Item2.Release(); + } + catch { } } } while (game.GameMap.Timer.IsGaming); return; @@ -117,10 +136,12 @@ namespace Server var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)); bool start = false; Console.WriteLine($"Id: {request.PlayerId} joins."); - lock (semaDictLock) + // lock (semaDictLock) { - semaDict.Add(request.PlayerId, temp); - start = (semaDict.Count - spectatorList.Count) == playerNum; + if (semaDict.TryAdd(request.PlayerId, temp)) + { + start = Interlocked.Increment(ref playerCountNow) == playerNum; + } } if (start) StartGame(); } From 8e16b638af5329c8e6ac4afe0639a0b54ce88993 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Thu, 27 Apr 2023 02:55:14 +0800 Subject: [PATCH 055/105] Update run.sh --- dependency/shell/run.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 7ee81e0..e11e3f8 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -3,8 +3,13 @@ python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI playback_dir=/usr/local/playback -nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & -server_pid=$! +if [ $EXPOSED -eq 1 ]; then + nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & + server_pid=$! +else + nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --notAllowSpectator --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & + server_pid=$! +fi sleep 5 for k in {1..2} do @@ -60,4 +65,4 @@ fi result=$(cat /usr/local/playback/result.json) score0=$(parse_json $result "Student") score1=$(parse_json $result "Tricker") -curl $URL -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"result":[{"team_id":0, "score":'${score0}'}, {"team_id":1, "score":'${score1}'}], "mode":'${MODE}'}' \ No newline at end of file +curl $URL -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"result":[{"team_id":0, "score":'${score0}'}, {"team_id":1, "score":'${score1}'}], "mode":'${MODE}'}' From 5ff6401fafec935ca71305131c001d6cff0a034b Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 03:03:55 +0800 Subject: [PATCH 056/105] chore: add result filename check --- logic/Server/GameServer.cs | 2 +- logic/Server/Properties/launchSettings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index 49e8614..5d2724c 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -127,7 +127,7 @@ namespace Server game.ClearAllLists(); mwr?.Flush(); if (options.ResultFileName != DefaultArgumentOptions.FileName) - SaveGameResult(options.ResultFileName + ".json"); + SaveGameResult(options.ResultFileName.EndsWith(".json") ? options.ResultFileName : options.ResultFileName + ".json"); SendGameResult(); this.endGameSem.Release(); } diff --git a/logic/Server/Properties/launchSettings.json b/logic/Server/Properties/launchSettings.json index 97ec2d3..6d2873f 100644 --- a/logic/Server/Properties/launchSettings.json +++ b/logic/Server/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Server": { "commandName": "Project", - "commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName video" + "commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --resultFileName result --gameTimeInSecond 1 --fileName video" } } } \ No newline at end of file From 0ff169d673135e6e822a4f724ccea08bd8a8e900 Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 03:05:17 +0800 Subject: [PATCH 057/105] chore: add result file in docker --- dependency/shell/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index e11e3f8..104220f 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -4,10 +4,10 @@ python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI playback_dir=/usr/local/playback if [ $EXPOSED -eq 1 ]; then - nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & + nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --resultFileName $playback_dir/result --gameTimeInSecond $TIME --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & server_pid=$! else - nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --notAllowSpectator --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & + nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --resultFileName $playback_dir/result --gameTimeInSecond $TIME --notAllowSpectator --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & server_pid=$! fi sleep 5 From e7a6036b0da18fea768b9123c496335fbbd87770 Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 03:42:40 +0800 Subject: [PATCH 058/105] fix: grap json --- dependency/shell/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 104220f..c452721 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -63,6 +63,6 @@ else fi result=$(cat /usr/local/playback/result.json) -score0=$(parse_json $result "Student") -score1=$(parse_json $result "Tricker") +score_0=$(echo "$result" | grep -oP '(?<="Student":)\d+') +score_1=$(echo "$result" | grep -oP '(?<="Tricker":)\d+') curl $URL -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"result":[{"team_id":0, "score":'${score0}'}, {"team_id":1, "score":'${score1}'}], "mode":'${MODE}'}' From 03715b3fa94554378f1de1679e9e22fbf5ccc660 Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 03:43:40 +0800 Subject: [PATCH 059/105] fix: grap json --- dependency/shell/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index c452721..e76139c 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -63,6 +63,6 @@ else fi result=$(cat /usr/local/playback/result.json) -score_0=$(echo "$result" | grep -oP '(?<="Student":)\d+') -score_1=$(echo "$result" | grep -oP '(?<="Tricker":)\d+') +score0=$(echo "$result" | grep -oP '(?<="Student":)\d+') +score1=$(echo "$result" | grep -oP '(?<="Tricker":)\d+') curl $URL -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"result":[{"team_id":0, "score":'${score0}'}, {"team_id":1, "score":'${score1}'}], "mode":'${MODE}'}' From f33760a551f60ff2f213f1ecf574ff7b1927660a Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 05:19:12 +0800 Subject: [PATCH 060/105] chore: add finish when G --- dependency/shell/run.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index e76139c..80c60d6 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -57,6 +57,7 @@ if [ -f $playback_dir/start.lock ]; then echo "Finish" else echo "Failed to start game." + touch $playback_dir/finish.lock touch temp.lock mv -f temp.lock $playback_dir/video.thuaipb kill -9 $server_pid From 1933968157ef6c352c4c480b9e38e03ff80ab675 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Thu, 27 Apr 2023 06:15:09 +0800 Subject: [PATCH 061/105] Update constants.py --- CAPI/python/PyAPI/constants.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CAPI/python/PyAPI/constants.py b/CAPI/python/PyAPI/constants.py index 5354d75..de7d171 100644 --- a/CAPI/python/PyAPI/constants.py +++ b/CAPI/python/PyAPI/constants.py @@ -301,13 +301,13 @@ class SummonGolem: class CommonAttackOfTricker: BulletBombRange = 0 - BulletAttackRange = Constants.Constants.basicAttackShortRange + BulletAttackRange = Constants.basicAttackShortRange ap = Constants.basicApOfTricker Speed = Constants.basicBulletMoveSpeed IsRemoteAttack = False CastTime = BulletAttackRange * 1000 / Speed - Backswing =Constants.basicBackswing - RecoveryFromHit =Constants.basicRecoveryFromHit + Backswing = Constants.basicBackswing + RecoveryFromHit = Constants.basicRecoveryFromHit cd = Constants.basicBackswing maxBulletNum = 1 @@ -340,4 +340,4 @@ class JumpyDumpty: BulletAttackRange = Constants.basicRemoteAttackRange * 2 ap = (int)(Constants.basicApOfTricker* 0.6) Speed = Constants.basicBulletMoveSpeed* 43 / 37 - IsRemoteAttack = False \ No newline at end of file + IsRemoteAttack = False From 28dd2371d133012bf06ab414df53181a6f809e6d Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 27 Apr 2023 10:16:33 +0800 Subject: [PATCH 062/105] fix(CAPI): :bug: fix various of bugs --- CAPI/cpp/API/include/logic.h | 3 --- CAPI/cpp/API/src/logic.cpp | 29 ++++++++--------------------- CAPI/python/PyAPI/logic.py | 36 +++++++++++++++--------------------- 3 files changed, 23 insertions(+), 45 deletions(-) diff --git a/CAPI/cpp/API/include/logic.h b/CAPI/cpp/API/include/logic.h index 5ca41ea..23098db 100644 --- a/CAPI/cpp/API/include/logic.h +++ b/CAPI/cpp/API/include/logic.h @@ -49,9 +49,6 @@ private: THUAI6::TrickerType trickerType; THUAI6::StudentType studentType; - // GUID信息 - std::vector playerGUIDs; - std::unique_ptr timer; std::thread tAI; // 用于运行AI的线程 diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index c06eb09..54ec745 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -323,17 +323,6 @@ void Logic::ProcessMessage() case THUAI6::GameState::GameStart: logger->info("Game Start!"); - // 重新读取玩家的guid,保证人类在前屠夫在后 - playerGUIDs.clear(); - for (const auto& obj : clientMsg.obj_message()) - if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage) - playerGUIDs.push_back(obj.student_message().guid()); - for (const auto& obj : clientMsg.obj_message()) - if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage) - playerGUIDs.push_back(obj.tricker_message().guid()); - currentState->guids = playerGUIDs; - bufferState->guids = playerGUIDs; - // 读取地图 for (const auto& item : clientMsg.obj_message()) if (Proto2THUAI6::messageOfObjDict[item.message_of_obj_case()] == THUAI6::MessageOfObj::MapMessage) @@ -368,16 +357,6 @@ void Logic::ProcessMessage() break; case THUAI6::GameState::GameRunning: - // 重新读取玩家的guid,guid确保人类在前屠夫在后 - playerGUIDs.clear(); - for (const auto& obj : clientMsg.obj_message()) - if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage) - playerGUIDs.push_back(obj.student_message().guid()); - for (const auto& obj : clientMsg.obj_message()) - if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage) - playerGUIDs.push_back(obj.tricker_message().guid()); - currentState->guids = playerGUIDs; - bufferState->guids = playerGUIDs; LoadBuffer(clientMsg); break; @@ -605,9 +584,16 @@ void Logic::LoadBuffer(const protobuf::MessageToClient& message) bufferState->props.clear(); bufferState->bullets.clear(); bufferState->bombedBullets.clear(); + bufferState->guids.clear(); logger->debug("Buffer cleared!"); // 读取新的信息 + for (const auto& obj : message.obj_message()) + if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::StudentMessage) + bufferState->guids.push_back(obj.student_message().guid()); + for (const auto& obj : message.obj_message()) + if (Proto2THUAI6::messageOfObjDict[obj.message_of_obj_case()] == THUAI6::MessageOfObj::TrickerMessage) + bufferState->guids.push_back(obj.tricker_message().guid()); bufferState->gameInfo = Proto2THUAI6::Protobuf2THUAI6GameInfo(message.all_message()); LoadBufferSelf(message); for (const auto& item : message.obj_message()) @@ -689,6 +675,7 @@ bool Logic::TryConnection() bool Logic::HaveView(int gridX, int gridY, int selfX, int selfY, int viewRange) const { + std::unique_lock lock(mtxState); return AssistFunction::HaveView(viewRange, selfX, selfY, gridX, gridY, currentState->gameMap); } diff --git a/CAPI/python/PyAPI/logic.py b/CAPI/python/PyAPI/logic.py index b3763c6..a1cacdd 100644 --- a/CAPI/python/PyAPI/logic.py +++ b/CAPI/python/PyAPI/logic.py @@ -22,7 +22,6 @@ class Logic(ILogic): # ID self.__playerID: int = playerID - self.__playerGUIDs: List[int] = [] self.__playerType: THUAI6.PlayerType = playerType @@ -214,7 +213,7 @@ class Logic(ILogic): def GetPlayerGUIDs(self) -> List[int]: with self.__mtxState: - return copy.deepcopy(self.__playerGUIDs) + return copy.deepcopy(self.__currentState.guids) # IStudentAPI使用的接口 @@ -263,7 +262,8 @@ class Logic(ILogic): return self.__comm.EndAllAction(self.__playerID) def HaveView(self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int) -> bool: - return AssistFunction.HaveView(viewRange, selfX, selfY, gridX, gridY, self.__currentState.gameMap) + with self.__mtxState: + return AssistFunction.HaveView(viewRange, selfX, selfY, gridX, gridY, self.__currentState.gameMap) # Logic内部逻辑 def __TryConnection(self) -> bool: @@ -286,15 +286,6 @@ class Logic(ILogic): if self.__gameState == THUAI6.GameState.GameStart: # 读取玩家的GUID self.__logger.info("Game start!") - self.__playerGUIDs.clear() - for obj in clientMsg.obj_message: - if obj.WhichOneof("message_of_obj") == "student_message": - self.__playerGUIDs.append(obj.student_message.guid) - for obj in clientMsg.obj_message: - if obj.WhichOneof("message_of_obj") == "tricker_message": - self.__playerGUIDs.append(obj.tricker_message.guid) - self.__currentState.guids = self.__playerGUIDs - self.__bufferState.guids = self.__playerGUIDs for obj in clientMsg.obj_message: if obj.WhichOneof("message_of_obj") == "map_message": @@ -318,15 +309,6 @@ class Logic(ILogic): elif self.__gameState == THUAI6.GameState.GameRunning: # 读取玩家的GUID - self.__playerGUIDs.clear() - for obj in clientMsg.obj_message: - if obj.WhichOneof("message_of_obj") == "student_message": - self.__playerGUIDs.append(obj.student_message.guid) - for obj in clientMsg.obj_message: - if obj.WhichOneof("message_of_obj") == "tricker_message": - self.__playerGUIDs.append(obj.tricker_message.guid) - self.__currentState.guids = self.__playerGUIDs - self.__bufferState.guids = self.__playerGUIDs self.__LoadBuffer(clientMsg) else: self.__logger.error("Unknown GameState!") @@ -467,9 +449,21 @@ class Logic(ILogic): self.__bufferState.students.clear() self.__bufferState.trickers.clear() self.__bufferState.props.clear() + self.__bufferState.bullets.clear() + self.__bufferState.bombedBullets.clear() + self.__bufferState.guids.clear() self.__logger.debug("Buffer cleared!") + + for obj in message.obj_message: + if obj.WhichOneof("message_of_obj") == "student_message": + self.__bufferState.guids.append(obj.student_message.guid) + for obj in message.obj_message: + if obj.WhichOneof("message_of_obj") == "tricker_message": + self.__bufferState.guids.append(obj.tricker_message.guid) + self.__bufferState.gameInfo = Proto2THUAI6.Protobuf2THUAI6GameInfo( message.all_message) + self.__LoadBufferSelf(message) for item in message.obj_message: self.__LoadBufferCase(item) From a75b8fcfc086628d5f52c20ed9f26f0e6cf7e373 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 27 Apr 2023 10:20:46 +0800 Subject: [PATCH 063/105] docs: :memo: fix wrong capi docs --- docs/CAPI接口(cpp).md | 4 ++-- docs/CAPI接口(python).md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CAPI接口(cpp).md b/docs/CAPI接口(cpp).md index 70bb297..8fba77c 100644 --- a/docs/CAPI接口(cpp).md +++ b/docs/CAPI接口(cpp).md @@ -59,13 +59,13 @@ 下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 - `THUAI6::PlaceType GetPlaceType(int32_t cellX, int32_t cellY)` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - - `bool IsDoorOpen(int32_t cellX, int32_t cellY) const`:查询特定位置门是否开启,没有门也返回false - 以下指令,若查询物品当前在视野内,则返回最新进度;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 - `int32_t GetChestProgress(int32_t cellX, int32_t cellY) const`:查询特定位置箱子开启进度 - `int32_t GetGateProgress(int32_t cellX, int32_t cellY) const`:查询特定位置校门开启进度 - `int32_t GetClassroomProgress(int32_t cellX, int32_t cellY) const`:查询特定位置教室作业完成进度 - `int32_t GetDoorProgress(int32_t cellX, int32_t cellY) const`:查询特定位置门开启状态 - - `THUAI6::HiddenGateState GetHiddenGateState(int32_t cellX, int32_t cellY) const`::查询特定位置隐藏校门状态,没有隐藏校门返回THUAI6::HiddenGateState::Null + - `bool IsDoorOpen(int32_t cellX, int32_t cellY) const`:查询特定位置门是否开启,没有门/不在视野内也返回false + - `THUAI6::HiddenGateState GetHiddenGateState(int32_t cellX, int32_t cellY) const`::查询特定位置隐藏校门状态,没有隐藏校门/不在视野内返回THUAI6::HiddenGateState::Null #### 其他 - `std::shared_ptr GetGameInfo() const`:查询当前游戏状态 diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index 1b36a28..bfbf84d 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -72,13 +72,13 @@ 下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 - `def GetPlaceType(self, cellX: int, cellY: int) -> THUAI6.PlaceType` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - - `def IsDoorOpen(self, cellX: int, cellY: int) -> bool`:查询特定位置门是否开启,没有门也返回false - 以下指令,若查询物品当前在视野内,则返回最新进度;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 - `def GetChestProgress(self, cellX: int, cellY: int) -> int`:查询特定位置箱子开启进度 - `def GetGateProgress(self, cellX: int, cellY: int) -> int`:查询特定位置校门开启进度 - `def GetClassroomProgress(self, cellX: int, cellY: int) -> int`:查询特定位置教室作业完成进度 - `def GetDoorProgress(self, cellX: int, cellY: int) -> int`:查询特定位置门开启状态 - - `def GetHiddenGateState(self, cellX: int, cellY: int) -> THUAI6.HiddenGateState`::查询特定位置隐藏校门状态,没有隐藏校门返回THUAI6::HiddenGateState::Null + - `def IsDoorOpen(self, cellX: int, cellY: int) -> bool`:查询特定位置门是否开启,没有门/不在视野内也返回false + - `def GetHiddenGateState(self, cellX: int, cellY: int) -> THUAI6.HiddenGateState`::查询特定位置隐藏校门状态,没有隐藏校门/不在视野内返回THUAI6::HiddenGateState::Null #### 其他 From f41e07960352cac98901bf063eed6c4e3051e5ff Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 27 Apr 2023 10:26:39 +0800 Subject: [PATCH 064/105] fix(CAPI): :bug: try to fix wrong file path --- CAPI/python/PyAPI/logic.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/CAPI/python/PyAPI/logic.py b/CAPI/python/PyAPI/logic.py index a1cacdd..e1dcf7f 100644 --- a/CAPI/python/PyAPI/logic.py +++ b/CAPI/python/PyAPI/logic.py @@ -3,6 +3,7 @@ from typing import List, Union, Callable, Tuple import threading import logging import copy +import platform import proto.MessageType_pb2 as MessageType import proto.Message2Server_pb2 as Message2Server import proto.Message2Clients_pb2 as Message2Clients @@ -505,9 +506,16 @@ class Logic(ILogic): formatter = logging.Formatter( "[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s", '%H:%M:%S') # 确保文件存在 - if not os.path.exists(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"): - os.makedirs(os.path.dirname(os.path.dirname( - os.path.realpath(__file__))) + "/logs") + # if not os.path.exists(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"): + # os.makedirs(os.path.dirname(os.path.dirname( + # os.path.realpath(__file__))) + "/logs") + + if platform.system().lower() == "windows": + os.system( + f"mkdir {os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/logs'}") + else: + os.system( + f"mkdir -p {os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '/logs'}") fileHandler = logging.FileHandler(os.path.dirname( os.path.dirname(os.path.realpath(__file__))) + "/logs/logic" + str(self.__playerID) + "-log.txt", "w+", encoding="utf-8") From 67fafd55be342b8120625d02797028f9d324b2d0 Mon Sep 17 00:00:00 2001 From: Timothy Liu Date: Thu, 27 Apr 2023 12:58:34 +0800 Subject: [PATCH 065/105] feat: change client icon to eesast software icon --- logic/Client/Client.csproj | 4 ++-- logic/Client/eesast_software_trans.ico | Bin 0 -> 270398 bytes .../Client/eesast_software_trans_enlarged.ico | Bin 0 -> 270398 bytes resource/eesast_software.png | Bin 0 -> 52506 bytes resource/eesast_software_trans.ico | Bin 0 -> 270398 bytes resource/eesast_software_trans.png | Bin 0 -> 56319 bytes resource/eesast_software_trans_enlarged.ico | Bin 0 -> 270398 bytes 7 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 logic/Client/eesast_software_trans.ico create mode 100644 logic/Client/eesast_software_trans_enlarged.ico create mode 100644 resource/eesast_software.png create mode 100644 resource/eesast_software_trans.ico create mode 100644 resource/eesast_software_trans.png create mode 100644 resource/eesast_software_trans_enlarged.ico diff --git a/logic/Client/Client.csproj b/logic/Client/Client.csproj index 6af7e5c..abcb9a6 100644 --- a/logic/Client/Client.csproj +++ b/logic/Client/Client.csproj @@ -5,7 +5,7 @@ net6.0-windows enable true - EESAST.ico + eesast_software_trans_enlarged.ico @@ -13,7 +13,7 @@ - + diff --git a/logic/Client/eesast_software_trans.ico b/logic/Client/eesast_software_trans.ico new file mode 100644 index 0000000000000000000000000000000000000000..2544246f363ad3fbc0699505c2c5d6a968d103aa GIT binary patch literal 270398 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 C+vP|A literal 0 HcmV?d00001 diff --git a/logic/Client/eesast_software_trans_enlarged.ico b/logic/Client/eesast_software_trans_enlarged.ico new file mode 100644 index 0000000000000000000000000000000000000000..cbafc97f8ee28af4b4d98412f9f788f967d6479b GIT binary patch literal 270398 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 literal 0 HcmV?d00001 diff --git a/resource/eesast_software.png b/resource/eesast_software.png new file mode 100644 index 0000000000000000000000000000000000000000..5d980f21e46fe58edad24f3bf83919fad98f0e3b GIT binary patch literal 52506 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 literal 0 HcmV?d00001 diff --git a/resource/eesast_software_trans.ico b/resource/eesast_software_trans.ico new file mode 100644 index 0000000000000000000000000000000000000000..2544246f363ad3fbc0699505c2c5d6a968d103aa GIT binary patch literal 270398 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 C+vP|A literal 0 HcmV?d00001 diff --git a/resource/eesast_software_trans.png b/resource/eesast_software_trans.png new file mode 100644 index 0000000000000000000000000000000000000000..6d7d511416087278769370e779613dc11547e983 GIT binary patch literal 56319 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 Lo^wyTNWS|o;SVEq literal 0 HcmV?d00001 diff --git a/resource/eesast_software_trans_enlarged.ico b/resource/eesast_software_trans_enlarged.ico new file mode 100644 index 0000000000000000000000000000000000000000..cbafc97f8ee28af4b4d98412f9f788f967d6479b GIT binary patch literal 270398 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 literal 0 HcmV?d00001 From 7909cb75507b71799f452cc89d80abb370ceadd1 Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 27 Apr 2023 16:10:59 +0800 Subject: [PATCH 066/105] fix(CAPI): :bug: fix windows get message define --- CAPI/cpp/API/include/AI.h | 4 ++++ CAPI/cpp/API/include/API.h | 4 ++++ CAPI/cpp/API/include/Communication.h | 4 ++++ CAPI/cpp/API/include/ConcurrentQueue.hpp | 4 ++++ CAPI/cpp/API/include/constants.h | 4 ++++ CAPI/cpp/API/include/logic.h | 4 ++++ CAPI/cpp/API/include/state.h | 4 ++++ CAPI/cpp/API/include/structures.h | 4 ++++ CAPI/cpp/API/include/utils.hpp | 4 ++++ CAPI/cpp/API/src/AI.cpp | 4 ++++ CAPI/cpp/API/src/API.cpp | 5 +++++ CAPI/cpp/API/src/Communication.cpp | 4 ++++ CAPI/cpp/API/src/DebugAPI.cpp | 5 +++++ CAPI/cpp/API/src/logic.cpp | 4 ++++ CAPI/cpp/API/src/main.cpp | 4 ++++ CAPI/python/run.sh | 6 +++--- 16 files changed, 65 insertions(+), 3 deletions(-) diff --git a/CAPI/cpp/API/include/AI.h b/CAPI/cpp/API/include/AI.h index cb6b373..d99063f 100644 --- a/CAPI/cpp/API/include/AI.h +++ b/CAPI/cpp/API/include/AI.h @@ -4,6 +4,10 @@ #include "API.h" +#undef GetMessage +#undef SendMessage +#undef PeekMessage + class IAI { public: diff --git a/CAPI/cpp/API/include/API.h b/CAPI/cpp/API/include/API.h index 1b89718..b3dec9e 100644 --- a/CAPI/cpp/API/include/API.h +++ b/CAPI/cpp/API/include/API.h @@ -22,6 +22,10 @@ #include "structures.h" +#undef GetMessage +#undef SendMessage +#undef PeekMessage + const constexpr int numOfGridPerCell = 1000; class IAI; diff --git a/CAPI/cpp/API/include/Communication.h b/CAPI/cpp/API/include/Communication.h index 2f75e43..9b2c19e 100644 --- a/CAPI/cpp/API/include/Communication.h +++ b/CAPI/cpp/API/include/Communication.h @@ -14,6 +14,10 @@ #include #include +#undef GetMessage +#undef SendMessage +#undef PeekMessage + class Logic; class Communication diff --git a/CAPI/cpp/API/include/ConcurrentQueue.hpp b/CAPI/cpp/API/include/ConcurrentQueue.hpp index 19fdf04..08e4a7c 100644 --- a/CAPI/cpp/API/include/ConcurrentQueue.hpp +++ b/CAPI/cpp/API/include/ConcurrentQueue.hpp @@ -8,6 +8,10 @@ #include #include +#undef GetMessage +#undef SendMessage +#undef PeekMessage + template class ConcurrentQueue { diff --git a/CAPI/cpp/API/include/constants.h b/CAPI/cpp/API/include/constants.h index d9407dd..51d2034 100644 --- a/CAPI/cpp/API/include/constants.h +++ b/CAPI/cpp/API/include/constants.h @@ -6,6 +6,10 @@ #define SCCI static const constexpr inline #endif +#undef GetMessage +#undef SendMessage +#undef PeekMessage + namespace Constants { SCCI int frameDuration = 50; // 每帧毫秒数 diff --git a/CAPI/cpp/API/include/logic.h b/CAPI/cpp/API/include/logic.h index 23098db..a6bd187 100644 --- a/CAPI/cpp/API/include/logic.h +++ b/CAPI/cpp/API/include/logic.h @@ -31,6 +31,10 @@ #include "Communication.h" #include "ConcurrentQueue.hpp" +#undef GetMessage +#undef SendMessage +#undef PeekMessage + // 封装了通信组件和对AI对象进行操作 class Logic : public ILogic { diff --git a/CAPI/cpp/API/include/state.h b/CAPI/cpp/API/include/state.h index 02f5543..c27c479 100644 --- a/CAPI/cpp/API/include/state.h +++ b/CAPI/cpp/API/include/state.h @@ -9,6 +9,10 @@ #include "structures.h" +#undef GetMessage +#undef SendMessage +#undef PeekMessage + // 存储场上的状态 struct State { diff --git a/CAPI/cpp/API/include/structures.h b/CAPI/cpp/API/include/structures.h index ccda444..5553c0d 100644 --- a/CAPI/cpp/API/include/structures.h +++ b/CAPI/cpp/API/include/structures.h @@ -8,6 +8,10 @@ #include #include +#undef GetMessage +#undef SendMessage +#undef PeekMessage + namespace THUAI6 { diff --git a/CAPI/cpp/API/include/utils.hpp b/CAPI/cpp/API/include/utils.hpp index 1044b74..de14b02 100644 --- a/CAPI/cpp/API/include/utils.hpp +++ b/CAPI/cpp/API/include/utils.hpp @@ -13,6 +13,10 @@ #include "structures.h" +#undef GetMessage +#undef SendMessage +#undef PeekMessage + namespace AssistFunction { diff --git a/CAPI/cpp/API/src/AI.cpp b/CAPI/cpp/API/src/AI.cpp index 6895409..d4d8e2c 100644 --- a/CAPI/cpp/API/src/AI.cpp +++ b/CAPI/cpp/API/src/AI.cpp @@ -3,6 +3,10 @@ #include #include "AI.h" #include "constants.h" + +#undef GetMessage +#undef SendMessage +#undef PeekMessage // 注意不要使用conio.h,Windows.h等非标准库 // 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新 diff --git a/CAPI/cpp/API/src/API.cpp b/CAPI/cpp/API/src/API.cpp index 895abcd..26926cc 100644 --- a/CAPI/cpp/API/src/API.cpp +++ b/CAPI/cpp/API/src/API.cpp @@ -1,6 +1,11 @@ #include #include "AI.h" #include "API.h" + +#undef GetMessage +#undef SendMessage +#undef PeekMessage + #define PI 3.14159265358979323846 int StudentAPI::GetFrameCount() const diff --git a/CAPI/cpp/API/src/Communication.cpp b/CAPI/cpp/API/src/Communication.cpp index f808e22..b620765 100644 --- a/CAPI/cpp/API/src/Communication.cpp +++ b/CAPI/cpp/API/src/Communication.cpp @@ -5,6 +5,10 @@ #include #include +#undef GetMessage +#undef SendMessage +#undef PeekMessage + using grpc::ClientContext; Communication::Communication(std::string sIP, std::string sPort) diff --git a/CAPI/cpp/API/src/DebugAPI.cpp b/CAPI/cpp/API/src/DebugAPI.cpp index fdeb857..34507c7 100644 --- a/CAPI/cpp/API/src/DebugAPI.cpp +++ b/CAPI/cpp/API/src/DebugAPI.cpp @@ -4,6 +4,11 @@ #include "API.h" #include "utils.hpp" #include "structures.h" + +#undef GetMessage +#undef SendMessage +#undef PeekMessage + #define PI 3.14159265358979323846 StudentDebugAPI::StudentDebugAPI(ILogic& logic, bool file, bool print, bool warnOnly, int64_t playerID) : diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 54ec745..b3e42ab 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -8,6 +8,10 @@ #include "utils.hpp" #include "Communication.h" +#undef GetMessage +#undef SendMessage +#undef PeekMessage + extern const bool asynchronous; Logic::Logic(THUAI6::PlayerType type, int64_t ID, THUAI6::TrickerType tricker, THUAI6::StudentType student) : diff --git a/CAPI/cpp/API/src/main.cpp b/CAPI/cpp/API/src/main.cpp index ee0ecb6..611e347 100644 --- a/CAPI/cpp/API/src/main.cpp +++ b/CAPI/cpp/API/src/main.cpp @@ -4,6 +4,10 @@ #include #include +#undef GetMessage +#undef SendMessage +#undef PeekMessage + #ifdef _MSC_VER #pragma warning(disable : 4996) #endif diff --git a/CAPI/python/run.sh b/CAPI/python/run.sh index f0ff428..d787ec8 100755 --- a/CAPI/python/run.sh +++ b/CAPI/python/run.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 0 -d -o& -python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 1 -o& +python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 0& +# python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 1 -o& # python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 2& # python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 3& -# python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 4& \ No newline at end of file +python PyAPI/main.py -I 172.22.32.1 -P 8888 -p 4 -d& \ No newline at end of file From aeb707be02b88a2f9b4e1b77eddd418f41f177a6 Mon Sep 17 00:00:00 2001 From: DragonAura <32223554+DragonAura@users.noreply.github.com> Date: Thu, 27 Apr 2023 17:01:13 +0800 Subject: [PATCH 067/105] Update AI.cpp --- CAPI/cpp/API/src/AI.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/CAPI/cpp/API/src/AI.cpp b/CAPI/cpp/API/src/AI.cpp index d4d8e2c..6895409 100644 --- a/CAPI/cpp/API/src/AI.cpp +++ b/CAPI/cpp/API/src/AI.cpp @@ -3,10 +3,6 @@ #include #include "AI.h" #include "constants.h" - -#undef GetMessage -#undef SendMessage -#undef PeekMessage // 注意不要使用conio.h,Windows.h等非标准库 // 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新 From d5aa4fe4ede1d54dbbdae11952db7b186c3f141c Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Thu, 27 Apr 2023 17:08:39 +0800 Subject: [PATCH 068/105] docs: :memo: edit DOCS --- CAPI/cpp/API/src/AI.cpp | 2 +- CAPI/python/PyAPI/AI.py | 2 +- docs/CAPI接口(cpp).md | 8 ++++++++ docs/CAPI接口(python).md | 8 +++++++- docs/QandA.md | 16 ++++++++++------ docs/使用文档.md | 4 ++-- logic/GameClass/GameObj/Map/Map.cs | 4 ++-- resource/CompileFaster.png | Bin 0 -> 61403 bytes 8 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 resource/CompileFaster.png diff --git a/CAPI/cpp/API/src/AI.cpp b/CAPI/cpp/API/src/AI.cpp index 6895409..6152fd0 100644 --- a/CAPI/cpp/API/src/AI.cpp +++ b/CAPI/cpp/API/src/AI.cpp @@ -5,7 +5,7 @@ #include "constants.h" // 注意不要使用conio.h,Windows.h等非标准库 -// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新 +// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新,大致一帧更新一次 extern const bool asynchronous = false; // 选手需要依次将player0到player4的职业在这里定义 diff --git a/CAPI/python/PyAPI/AI.py b/CAPI/python/PyAPI/AI.py index 09af335..740f7cb 100644 --- a/CAPI/python/PyAPI/AI.py +++ b/CAPI/python/PyAPI/AI.py @@ -8,7 +8,7 @@ import time class Setting: - # 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新 + # 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新,大致一帧更新一次 @staticmethod def asynchronous() -> bool: return False diff --git a/docs/CAPI接口(cpp).md b/docs/CAPI接口(cpp).md index 8fba77c..b427644 100644 --- a/docs/CAPI接口(cpp).md +++ b/docs/CAPI接口(cpp).md @@ -88,6 +88,14 @@ void PrintSelfInfo() const; ~~~ +### 部分属性解释 stuctures.h +~~~c++ + struct Player + { + std::vector props;//大小固定为3,空的位置为NullPropType + } +~~~ + ## 接口一览 ~~~c++ // 指挥本角色进行移动,`timeInMilliseconds` 为移动时间,单位为毫秒;`angleInRadian` 表示移动的方向,单位是弧度,使用极坐标——竖直向下方向为 x 轴,水平向右方向为 y 轴 diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index bfbf84d..500da59 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -80,7 +80,6 @@ - `def IsDoorOpen(self, cellX: int, cellY: int) -> bool`:查询特定位置门是否开启,没有门/不在视野内也返回false - `def GetHiddenGateState(self, cellX: int, cellY: int) -> THUAI6.HiddenGateState`::查询特定位置隐藏校门状态,没有隐藏校门/不在视野内返回THUAI6::HiddenGateState::Null - #### 其他 - `def GetGameInfo(self) -> THUAI6.GameInfo`:查询当前游戏状态 @@ -105,6 +104,13 @@ def PrintSelfInfo(self) -> None: ~~~ +### 部分属性解释 stuctures.h +~~~python +class Player: + def __init__(self, **kwargs) -> None: + self.prop: List[PropType] = []//大小固定为3,空的位置为NullPropType +~~~ + ## 接口一览 ~~~python diff --git a/docs/QandA.md b/docs/QandA.md index ae141da..6995cec 100644 --- a/docs/QandA.md +++ b/docs/QandA.md @@ -22,11 +22,6 @@ Q:卡死在第一帧不动 A:大概率是你的代码死循环了 -Q: 怎么开始游戏? - -A: -需要确保学生阵营和捣蛋鬼阵营的人数都达到Server.cmd中设定的值。人数不足也可以打开WPF,参考使用文档,修改RunGUIClient.cmd的参数,然后运行RunGUIClient.cmd,这样可以通过WPF运行部分客户端,来达到人数限制。 - ## C++ Q:显示API项目已卸载 @@ -54,6 +49,15 @@ Q:CAPI编译不通过(第二种) A:查看`.\win\CAPI\cpp\`文件夹下是否有`lib`文件夹,没有则https://cloud.tsinghua.edu.cn/d/6972138f641d4e81a446/ 下载并复制粘贴 +Q:编译好慢啊 + +A: +1. 尽量不要改其他文件,甚至连点下保存都别点 +2. 不要点重新生成,要点生成 +3. 开启下图选项 +![CompileFaster](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/CompileFaster.png) + + ## Python ### grpc版本更新失败 @@ -76,4 +80,4 @@ A:初赛结束会调数值及机制,增加新角色 Q:初赛后会修改什么呢? -A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业;规范Debug信息 \ No newline at end of file +A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业;规范Debug信息;提供不同格式的信息传递;增加职业;优化游戏结束条件 \ No newline at end of file diff --git a/docs/使用文档.md b/docs/使用文档.md index 12aa824..b9f3d46 100644 --- a/docs/使用文档.md +++ b/docs/使用文档.md @@ -14,7 +14,7 @@ - Windows:先查看`.\win\CAPI\cpp\`文件夹下是否有`lib`文件夹,没有则https://cloud.tsinghua.edu.cn/d/6972138f641d4e81a446/ 下载并复制粘贴 - Linux:首先自行安装`gRPC`,具体方法可以参考官方教程https://grpc.io/docs/languages/cpp/quickstart/。 - 然后在`CAPI\cpp\API\src\AI.cpp`中编写代码 - - 选手不应当修改`AI.cpp`中原来有的代码,除了`void AI::play(IStudentAPI& api)`和`void AI::play(ITrickerAPI& api)` + - 选手不应当修改`AI.cpp`中原来有的代码,除了`void AI::play(IStudentAPI& api)`和`void AI::play(ITrickerAPI& api)`,及修改asynchronous的返回值 - 每帧执行一次`AI::play(IStudentAPI& api)`或`AI::play(ITrickerAPI& api)`(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 - 选手可以在`AI.cpp`内`void AI::play`外新增函数和变量 - Windows:然后用Visual Studio打开`CAPI\cpp\CAPI.sln`编译,注意使用Debug模式 @@ -26,7 +26,7 @@ - 首先在Python环境下运行`GeneratePythonProto.cmd`,以安装必要的包、并生成对应的grpc python文件 - 然后在`CAPI\python\PyAPI\AI.py`中编写代码 - - 选手不应当修改`AI.py`中原来有的代码,除了`StudentPlay(self, api: IStudentAPI)`和`TrickerPlay(self, api: ITrickerAPI)` + - 选手不应当修改`AI.py`中原来有的代码,除了`StudentPlay(self, api: IStudentAPI)`和`TrickerPlay(self, api: ITrickerAPI)`,及修改asynchronous的返回值 - 每帧执行一次`AI::play(IStudentAPI& api)`或`AI::play(ITrickerAPI& api)`(除非执行该函数超过一帧50ms),获取的信息都是这一帧的开始的状态 - 选手可以在`AI.py`内新增函数和变量 - Windows:最后通过运行`RunPython.cmd`执行比赛代码 diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 1a5eafa..427c76d 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -23,7 +23,7 @@ namespace GameClass.GameObj if (GameData.numOfStudent - NumOfDeceasedStudent - NumOfEscapedStudent == 1) { - GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock(); + GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); try { foreach (EmergencyExit emergencyExit in GameObjDict[GameObjType.EmergencyExit]) @@ -35,7 +35,7 @@ namespace GameClass.GameObj } finally { - GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); + GameObjLockDict[GameObjType.EmergencyExit].ExitWriteLock(); } } } diff --git a/resource/CompileFaster.png b/resource/CompileFaster.png new file mode 100644 index 0000000000000000000000000000000000000000..f27537d6c7c7f278dca541778f122e9350269b7c GIT binary patch literal 61403 zcmagG2Ut^0(>HEIL_h>okZJ)Vq9D>Cz^$N2F+q^t1f=&KY80eNQzAu5A__!=fJl{k zN1F5=git~a5UBw|fROL#t9Lx&Er zYTQ@TJ#^?8^3b89k|&M>cZf3I9|0eSy>->^94hMOTLiuwv%me|_Mt;1iOl;}48V6L zkNd{nhYp<+{`q%ULsw|+(4kci4Yk{kU=}}U0k4Je=94k=D(-a$J+#2B&qHoCNyBB= zuh>Z5k3YG1N*cu@DOx(ej(e%^`zl!`{KoUz(a*dwD~$7_Ol2-cEotasx4{-I53)@7 z&7P$3irXh9$~ihHCsS^mZ!^^T&fy{K8Bu1re`(skJAuD}A2gjA{Y^4h**U~Ozhy+P zscj52ouPQia0MAiSV3y@fj#_>o33=XHDN<2gE38drYjSps+GP|uYx=l9VrV-m0zM} zYByY0Zok{7Kcj5P30edwPz^ilCo~UKx(jP@>kZqLAPdNW<&?o^_a$0W&{DJdN>SPm z_}koD@BFgv+6;gX+)0? z7zzq27jB!Zc$n%EH&iJL(@gGwq)4eBj2aFO{-+*MFunx2a=g*Ldqijpxe8 zni9XRakGXMH&nx-oBNngB@QuD7Jyf(s+dF8zv83wwgsggWWe+uR0u0qQ+vl7{CdXg zVIAX|ui-wNAn_y z?o}jWF?!gJ>kBtyKxZBH2@cnZ(ni-iRaK8l7ii%Q={fx9fB+}HsCifOaalahu>bkOAGe8Zp8!M9PmXgOnz%$4Jfu`z88 ziA|gI$|O`nPW-IgM0>{sBw@8{cCw?5LY#k9s!_u=rbjXy=a*RYcJQhlLVK+i#viEc zD@>-OJeWW|qA9qOiqba=CO8qU@Ak*OHTWYcR<6ucp@P|zYSV+=$7_iK=eHqI6A!ihKg@X^SW!vUf9|a^cO*#qUM;v8jNSwyjHQB@ErHHkbq3*HR;?7j%j>Xdid8SxdBhd6l^mHSftyh4jn zh&CA!M47kyW%)!%_cOOE#B0M)m+B5sQV-RJIKJEG>%aX?-hX~=WOh=z66vCds=ZPq z2(>WG{ZZmunIeksMqinO+|MGrNv?lg&xr>yu8hWbFCKtH4w8a=4y-p;BW5R=+Zs0L zJVhkBIBTVbBHP^LtkF0)pxYJfd0jrSD$R_oow`;&3)W}}?#@yS#AQLctsugC!bs(c zl)xpUjq-g_e9|yfP+_hc?D^GIKzY%PrCWHI(Ya0jAiV}YUmN7%<~=(KbkvENCGFYw zfZVEs>}3$%w62_q0ROpfj{Z}<7aZ-!U0sESSu%zZ)VaXG6))57xgIkgE{IU8f_yjn zRF)@*lM#ya1c4J7Em5!ypXvO;nI%rpcu6axY9a`EzoM-n90aW#;`Tt;5 zM^LunYF?VTn`sw`&+_efc?slMXm-=Ygzz#+&M&>&f$W3~P8F&t&gP2_ ze`EDVyP>EeIeqiS>f*Z3kM|TKOA4NQi`{#0C1#fNERAnKFA9P34WI$)*fz{I_GK95 z$2FP8M;=CcF*a;$t@O~^+&w1OCPTybQij|;)$5lu{I_|JyUk6sF+yrZvk|cA`Wo+z zP_I|786KqMeiE4uFM!&oXX~``9Mototopea=JtU{UY-(#!}n@!)`dVUe=vJv=~IoXVeV zw7i3sf@x~Ekafb)da0!Zk@HdM5s*|}b^IK?t>VeMREY@GM^x|$Wsg3Dxe)+{Oh|MfH7NnF1Pvip)>J(kl20I`=}ep)W~ zN-N#VtMJww{R_vAQ0pzdu**y#F0rzToExl3ccMbB z*dmIf@_aw{inz*BWkpki#f9h-n%kCPXvMaYS5HNlkwqzCXmpa7sn@e~OP>hrfPq&@ zFi6B(Q9iPAZnBBj>((XEOZA>F&TaJ*-A9E~gxc?17FW{@&$-}m^11} zqT9x9-5}Vfy`es%w$h(twaBvVE84kjKMDD0SO@YAv#d(y+_B=G$(n`QPPmz#YUL`? z7^z?h&kJjlaL_McgQ{G;MFQ>GIyskRnQgXH2#s1Br9P6Z36WSmZkCway_;95)PZ8b zE0$WPFSXN4huw1NseS{l$VESD!|M)sg$M;)U{dl%p9k=JDD?Xm6O;wO|cji`(Y5T5CyA@-Y zw>^|>NaahuYYphuuh|kXIbJOzqfR9JeSjqv&+-d@T zWSRy|Kd%X#cHw!aq`9qrv&r0%k{@qt*f_~ihTB%Lh*A`Og;Y#vu z_U0OEiOHcqVX;s0PD8XQXT4q%Iq%J*EKF~wLp2tJrUs|Si@wp>#?h6MsKE4^!S$`lW4{k~G{;5LsVYjGr}wOXkP6@qWccWcy< z4G}bG5pOq$*w|*~Eh-QHlAfvODl{W^8Q{GHb^H{y+5cQ^oLGybv{~=ldtZ^)FUViR zMjwMh@87(1yN$^oyzcVZk_+LS;N99?J>w2eIj-Z}Iy@GUv#Qm${Ufy`VC^+bLO!wX zWu{>fX!wpjf}$VB=ty?xuQ(2ET+{d}#FPdoT7Plcap;=}f`})#g|J<=zJWb=4(k>L zFr2rTr=`@=)tC^vbM*WT`YXp1$;Y8yaq70}u9;%T?lwOb#itzC+$eT|gGUb1BB7+V zAn%DRjZhp!=}jb0sYi3eefhF4qr-Tlviv%s1A!NSM~W{R(aCk4mv7bO;b5p5N(0X1xE zP~sWuM?xA=2UjSp@TH6~Qp2?A*sJ2eJ7H*yluvcgbm&rDX`9Bxkh?b&)ZU=Dx?@Ed zSPd=SOJ>_o-32?D#YT<$-U3`&q_Oktp6q4wwM8_xhAj=sGs_+O70|>M+nD8EcV&$hNUS=;S#~TJ zkvdix+GVpsq7TYet57CG-|t1LP~%rj={4cNlte*Ho!Q0)3@2YlLMHbNC#H~ef_rtU z%3f5yUGHp$Pr@F0tLy2w@rf)oQq$R1C-bXQ*Bv6xq|CIh`UlBbDCJc}n~=qDH>qZo z%6py%<=xrr>_l_tdJ^7}PHdQ}Cw95}4g=ALvpQ~^)G#0ai;tROI%0C6ei2%S!|aG= zN%`#N3({4V7$Hvm=T}g;jKpQrlbLFyoU_i3K!2gm5uDLD%E|5mTyWg8He!vhz*BOu zuRwgXT#t$Ocqo;AP_ydC+bUj#fM$9Yhjj6d4GY4u_96i*T!lIgnGQOUHLpqPYH<^K z;$%p&KCw4=lIwIqS$(31Mftof%V19^l(c_{2qk6muzLcxzR)&X;j^Hzw$`318+Y(r z{ZvCx-Cj%a&bdmj)us@NgWf^4iC<7wB&0kXontj7h><;CBcU`^2GR7qgo(ZILr?V4 zUxn|tXwS(Xq-AHg$>hT%@L{0+F`#{c^7$&-Hh#sehBFc6nFt?vNFmlw!#zYP&~g7s zzd8I^r8!N8vR}L+&5TSs?g=lOF#B=u4!W&e%+KRo*%5{&1(QjrT(JpRCP6|){8KlV z$3aOc1C4~D2N6_CO<~@48GKZ z!!gUj`UWPJ=Z6XD9lvKodA;EcO!Yhcb2Yu`9VOY+FUNi|C<`#?(B-_hya%5`)eHbl zuFGb6iE=0?g={%e+TfIYYl7OEl(&idl?t1S9vm1>&FhZlwS-Uy^G}z%!*CSm5BkvZ zb{j(zGFV1RKI&7qq=#}@cLN~L+s+WYJH638WL*#%ooAdv`j4{BA=X~32`bqy42dGXoFZ{ywN$e^(YK2-y3+; zGmt4gZ=m`wY(=?P6ML!#iFkyfO7cE*IgrRBhcY3~L`Uyoq%FIu?N4E9N{>NHvuiKn z{3L>BKJhbU0fbk75`JY*eL%853J{haVkMKA$(fD#$kJk8i-hPZOB3=S7&hO_BZ{=U zO@ELd$cp!d9dXFIX?>eCeRQw4`jEQWaSVzvlL6CnLaMVzLX*fpK{{}j!$%V5qpRql zJ*E@$25g1Z$;rvt?tzN#lge=sTGFQl!ko+iY0wr#i|~cyb*^U zNXF{vI`oYhO=>qtV1~CF*MN@4=~xbx-HZlvnE6l$pJ6w}TxHY$r0<|TecjuRYAhSr zPb8s)aBDXv*Uyo;X-g`5Z;eAAmWe5Ua>m4ZsuiNQBqLlMLm+RhypRtS=r=7IsW-tY z>P@t*L|O^GpC-P#A4+jY!Y|TxSNFdq=HbsN1)n5dVS07oPN&en(&ko!wHBqdL_l-7 z$gMy_14gLEv%5YiVIa~2s%V>Rcw8UcJnZuMQo$n{@+0RWHFXUKi=}mVxRf2`;TfAC z{H!#55BvcX5I7bI3V8>&{{9yevVOjxKJU}=>W?R_t`syvxpp}=$9L+PtE0Kp^o`k7@jNf%&4Ul($|5g zMuNylG|i#zqBS>P3xJ-U~+^;5d?MW6N zZtx`XV}*DaF5-Aat}iw&dcc`hYsF=P;^qE86#Rmtp6pJ<$tzvzj#Q!i5YHP9#W|A; zrMV&!n3K09eK>@D6hfX8^8GQgs^wwmG~I5t*FNR1E$_WvyC3$-qsIOE;};Re>h19X!r*aM_97y zI}1YX7(e?wR;1LYzPI-VV?${sM~_p7i!VQmOL4qp4{%fNn#>6j) zps{UvhlOU+a>dfrrfgfiJ#x8SrXb!Z1fFr+;=proTPSz~`Xf}7ey|Q8P8T6N+E)Vp zs&WB9mgV{qg2oY{hX>-z&#|ut`-W+*R;C-}aoFPGnT=LaSE{e{&PJ<1LUs%;f&n*F z{q}Ct2yWN7MWakv@20H0c*&smxlENUupm3dkTq-8lC%{tl?UK_>1n2?=|uegh@aQLe1d!^`#UkBkwS&%*%f*bcyR`L=oAA%b_ z9sizAWv9(tv26W%lg{0ykx?egV!h$|?kqSaR3}GMhtrL@JPb5)CFBu@-0h4Y*Zw&YVxfQe0gTF5=klF%Itr{2Zg<&3FFw97rNze*s0mY)xPC&N_F)hXW&z zF5*#WYrv60M6(C3!qV5yLpSb4WyfE|K7G!9AR{7*pS4t}?Hm4jNPSQr$}?@W{6cq_ z?X~rCa~RqK%;UC$-+$ahS11&1_frxx_*=+{b_I*Tm9&4`b__@Nell|j=6Goo5^KdT zBDxxGc`sR6`Yl4iKzbiE(?FV3M9p^j>uNpTD2a%*Fzwdl(5uVv5eUl>{gX%)+6Y@bW zp+@gP9*%2g3RyO`DxFWCO<_t_&Jia`>#JT+F*+G87Jz}QESE13O)6lTmY|o8cm~q=N0g#@6}A&)XQ|3kni(4E#z3~?QDgP zEWQ9~iHIJ4zVBRT$8gu``{ga+vJ)KNAqS?D`~1(`4qYu5hf?2_v0J6Fe6 z6kXSZmRrNnpAudJnj)`!E7DUG+5fmr(Td#2Gx?FA(eAu+nQpSBn%h~WqrS^*DDZ#> ztdD_x)Ln|kIluEQdFop(X2R}SUmlA4&8Y`6oSg4_<7xExHF(=f(8Puex!f3+u9_!( z4zLb8gPLnX7a>^}zOe;MMXy<=GS7KrEDV>{Cx|Tj@`D$hu8YFRY(5BrMhl3RAZmZ! zbmY<5llcS3p|{)?L1SW?H9S{hbi1$dCSaW;S+dkbIGGc2ltf|uLu$Llk$3cQtjMni zImpSVq8A$-(F*6_mb0WQmAx?s^%2F!TqlhTNnvN%iIyZHKS*M~6Pq4Ll$V=~96lNy zosAolz|4HjrJX|c6C8I8m#+YD$QdS80Va@CXP<|9`>yZ)-}mZI;rjxuK3&Ft)w#bE z@ss74{wOyxTajRz6ce%#h~tfK$LGE#hi6y&qFIqX<+?lRoBV)H*D?+e_sI}oJ|AU? zbJtS^FsE@`nKxZsCZ3+_a0O~TD7m6v!Qd1dADsHSO%T%$z2u2!*j(hC$xEOOW z0B$9N=q0g8Tn|`gh<^R+@j#*yV2OuMMMuArHY~Fp*Kt&7L>q*G9;zO-WDVJrW;(yG zuu%?}yg6sgd%S*#(xCWdO*!`Z3H3E0Cx;nP+s(gZnUHEsXUq8WIRy~CpUfNT_b1^u z=F6~%CCZKV@0eSkmB4NXAFoWP~{m#W~k6o&*gkJk03-e#3n)KMuW! z@y*6X9ID9nmH4N5f*hvjYFrv>k6`U!E_uOvuSme?LAgc7S&aNUR+ZFD)c!DhA1Za~ z)j_*|NM+CvoDAw3uD->L?B)bN_~@(SSsM?m+hZ7p0t3zEs0T>dvjYn2tup0e_t`y5 z%IA*&0gZgb*;*GtPaU2>W$qw#{#XW0sin^Fo*%gS%@!g1+k5Phr^nDc*&F$1B z_#Lo?EUjrMwg@6b&eCL<^EYwO{2C8dj}sFfJ#_9!&OYg@^E-G_M6wBpESHaK7QXZ@ zS32sk9;Qb+ZXrv2D%jav@4~dTa~DI03lF#p*zd`2eNRgioxc_z#Qy-p3ClDfO>?l9 zXgZ5wt4&bu4hvbLQ~UoV`k}2fe!{%k-sG$#f~5g zk@%R2s-)c`?5XO`7Djf$J{w_Z_4(VTGMJ+gTQ?XqtGfbOMav z;#|ryo%-Qu4lwNH*u~mW$OTsNdFR`EPM`FYFq@a1$?Jj(|fs$Ni48v`OI zr+{*0#**wd>T6%I$kJ@z@n_K;@1@1B*J$yAjTw)E{9Qgst!xPoD@e3zl#A`2W~Z1s z*PFOudQ=M?y&$$(iBmru%;7+f4qZ$gE4sj%dG>dk@S}7K(sMp^-=AJiVtUjHv;74k zOY?nM!=hu0r3DEbK;7FwU7vI_(lI{#VD*}+S|%e#-c_PpS+FE>;tO|o9?ti~C9!&3 z@KddG05^xwh+fBA7=*iv9_h|0c2C?8RWx(poFPe)!z_w6zugBnZ1!s{_W0wc z21XkHNXAIjn0-AT8q!|takq&|;Y97IRln=orJ@EUql9552*TpwKaAf?#(P=>%$+6w z+Rv!e6n!YJhn|y%)w_h{T&YPa4BcrIgfz4PA-(aNjwg`Pd4)_ts@a{UyCq#c!oXG) ztFLCpH%A=%+4`nI4Itey|GA^C9xzxu13RRVd(hx8NgHe|L19`Ah?bYy0#_iX4_1u$4htk&8*NK zP8QR#Tw}~CJG)bK%m#VBezk{LWx-;V-?B7rb%nN1gVpU}x#EUPB$<#NR&&P$*|{{r z(A3l(VKp-$dwE#@-)O#jKdSeXB2JBPzX<7aUVFW)C0~}2Ojz71hPJHl3i^l}*@D$? zU%={3`f-ANLkq^E#uP0ICZ(2KDFUS~vh~F6539rVGpZ}9tFYxYx&bx7n|-?#jHT$V zCsF)6<}%XJ3*>F9u;@~EK%T2#%#nM#mZXXGi#0!%DaY`pxAytU+pnklhM}i4JcsOc z4~)Ix{+%)%Q|>{k@rbo*SIEM`k*7TmngVWn!%hi?1)K77QeD@mQ%*K}!ycpv|71~l-sqmd1d-l%=br3&CXu3&gQ@{>! z67nITz%nYijAuc9{W8Aql64FABBVYJ2%jZ`QuqYHZSK>hly@7)8UVn1Kl7H#Q8Wwk zv&=FrEuI-LK`n1skaqKCnS^|enb7F+H|+HgV44QPP+#CxEpMo)6-{{00g89UsUEx zn@&Doid5_C5t;e=&MhNPpX*wz&+W*n+HUK$M`vM%Z-&S>Dzht-+cLRRC`64LhEi+_ z*XD=%xt}CRwcF3d5t^#I&*O&W<=tgr|hBZM>V>tU>AO^zDqV#eR>(#F5 z9N>#$)umkExq^GVT{o)x2T=t+2iGDw1LJivxt2fo1$1W`F3apc#)_j{Wy26J2pY&| zkJ2f*!D}6UHLm<92~@`3z>tLW^&j3AJw|`M+(N{oH;q9!@VWRF{0;#BwobswdtkWW z$vum$iPdlnBh+3-&rr;)iXbB^+jR$FRQ{wvvo7TElP|1w7;Q*V#guh2!cu~Yw*H|Yb;yigI8$=1H!IJ7{D9xnzZ3o((+NGvK%QAVsKmG1T7j2V+ zV;53J`vg5kia7u7-FV^(RgO73!_xW^qA;J67+p%pnB2Fclq80920x(n3DO=?N>%ns z=bfE~v3iS=SGVPFHWRhxhz=GF-S(XhE^|G9E1*;)x4z`elS8*hB10yqsU4Ia z);YH)$0&p92Y9$}>lM+E(c)%kg=B%4-=>l9JZNe(Do(^jtMxp7g*Rd7TDV+d_aIT% z+8L{7B_M4fd%Y`2wS$Y&D1Xsq@`o%c!|53GAXEB!YJqn$-NdI8w-w$!JSAssu&mWZ z$gi<+;{M@{v-s|hbN4;3YQy3hKkQUGvS&F{{dqBHvc#1Unj{?~x+_?q<4s2VeXoJP z9KyGCtQ?j^LY+v2C<7BYIhYPw@Z&vTDz>cm=`S`o1}zR*cJAOht$VN?bQ1rg!Z%nS zv~{p8maupo*xYAFuNy;d?7t*#g=-Y`F{;l<@v+-u*@6j2S2pH4`Vjm6btH4QpdftR z{zk_<$*B^HSRb(qIaRh!wcbiLp-bj1N%kJ>_f<%$``Qt_MP$M2gT-AvqBClfV|H&+ zMJt`ngp6I=iFzK^uJ9Cnvkyigxl8uBmaPXrcvqsmX=N7(BfKTUhkW-7IK zr*^2PW34H;N~ut9w-Xb94VP=}?)*ow22kS?!we&t66uI(;&cn&S>`jEPIzbHJ!R+bAll%yenGkQ+HGEB}QHFzlKpDE-`?!;KosmYqGVcE3c?*Ml<3Y9VqX zcv+DfJqc^xSN7s=&ij#`d|qM7+dk_QQa|W8pu!{;*D!sjd0)FgnJN}yF>h0yw~jpb3Co|fZ8X~h7H=#vws(nw)9-#VOAQ0pGoB0Dt_E|wf@sapF84BMQo zu#HDgS4A%S2Wqp5Zp)9`{ea6wUTJ-I03%g6^1JtZTaQnn#Me{yZ1C6t>Hx3XOlPEN zfRArSj6wFi42x*t+ZIVh5!cg6XCMir<4~Ixm&{%$2Y7_*Sioe8uQ9wY_Nz%!37BwLi1k*ZH(%T8cgi=x=L;IgH`&$JrKn@1FPpEChid0UA9KG4oQ&N zkIUa>i3>eYql9!4ePdg~(4L3&99Jsm_p4Dy1HLTvV9iRq_Q~Hq-|T+DoV@03z(=N< zRqK5CKDiKa+h?+|$A})5JzsJsQ;$OP7AdJC%lnDx}jRFhT~&r{>WJ-JOX;pn9=XqQd1u{18Hs8jhZU=WYDVKB>k z`C)NE-Y7TmPW_TExBNm7sl`et*-?~ZV!qXEsVe^L@^J0CwA{J!R{Yzpyj6H@@Z%qK zlOV-YKmG435&}<*3{YxzhkF*DR2kp5&b%3$iy$mLZT=}T5pmNAN+j3u658Tyn%@kN ztKfL+qvCoDm91(#^h?%4(?cHnE$(T=g-c>D_5{G?TU6`N1ev|Kn9$=_x=q)l{0=IV z4GR%%)u6Owl-@I|j1o>qTHH04;_97Jv2TSk_v}!q7N%$Sc$M<{LW-9Z;Wx@#Vw9&j zKZ)zkEodKN<5vqp#`c)=D933NKN^~d$i6Ph*9G2N3HEK* z$mKa}@N|oB=vy^X>ZUVMO3h5gUoZK5zFqUj~;5_=j1*;a8OM3^JC# zUx)ELNSG7sZkn1E$o#8=t&FaUq(4RP;>$zj0!;8xArUi!Of7<{p1QKF3DL|`^^8#0 zkoqQNb>85XCY7W36Ue}Qvwmv5&k++T<|noC6AEwQkdKeg&lMszlX7LYBwP3RHk3=h z(xOpsiOa9Wu6|S|#`Rd1F24Zs6a*|z2w5`jCDk!vxlgB#yYwP)Hf-cXD z^dci#!*V%|9zu-@I()gnF@Z-EZz(OtCsUx)cNamE2I4S|M&-F#d2oqAY^%d}^)gyT zVtzt-6lZXs%I#D9-qVvp#wiGsI-Teg{YHtl7+C#{K(8NfQu5^vt2Z@!(8EC`5k0Bj zi60(|y`4!U-XeH^qDDu8}BJj+W=xc$59PZy$P$)*clh zoRSN^PcDX|AC6?t8?mPXj%^VpUDR{kypYn+NN@xU@5Mn*8&b*<7cEJci4N8E#Pl>C z$E3W1>e&49JUUh!tEZ*eYkrbT>N#;gbjm!5(m*3PDoIV{SnuzF4h+A(3d z#K(`h#Ag5L%!CO!ZwcTKWB6VCc zfr-livc~?Ct91CU@cW-W?yi-E`h*jhD3<^8>1Rxjup=?q&_ZJGuO_NtXgv@z;DlhB zLa?tPlt#gWPeIhV)Gqf>wWa{w`CI>rxF5QZy%#SFQls~pK+0Cz;nCz(E%CZp3)mC` znF!bIIVL9tKX8kAkD#&EzhIgaB{=Mc?_A$j6r}9rAHqvATl?AGEBjO4 ze_)d6=Ax6~!T4zHGSZ|5Kp*~8THalo z&U*A;ILT#bkLX^l-bh$H{s&&Ubg5znGmtutYjOQoy4U*ik{qHSMy0P)8W;OKVT6% zdq%aVwPbR`e@BD~JlJ9IKlsk@Z$8MaGGxNyd^j!)-Ehzi0Bxqj>F)oC)zdGT;P^h4 zum~VI_tab-{3dInde3~%!)yQ4^Olo1zTS#{uHS>5-WSQ{1g;@JRrXggXnO%t%QX7a zV_}j#_~LX^x9i#_67Obf+g!JjCHUELwZC>1zbau-uo&c4oa6cfue?c!nxIxkOf=9w z#oByyg^+1+KLruHOntv$xa`xc_fG%APZ+S{B6i>y8(#_^;WM^t#ktxaa?&WcHO*kT<_{d zn-fQ02CyPOhloV^m2!Y1XswfUs;}MT(H`3q$bF)SZHsuXbFy?eno@-i$oihPd8EN% zJ*CEu=1h2LborZ8zh5;Q6@UkpY3tjQV8|QamTAUIRsjWF9$??_*F^~dE?{H$6eeZV ztxAbrUrj^)AQ93MLfE{t=E{^-%d1_cKehi-^wo2=)@@ ztycjfKuSw3eYkGL*Jj(&b;8fdDsJ>1Y^;p`vf5RCP|1POKH*((VXSS36-0MsyXt09 zjg5u8fNO_4QFYa)Sag}>u=lAjK-;&oB}k`4Wi%3=sczFB_=?g)pZL}~8)ZDS8s$6o za}{`|WVI1A!XieodQ#B~z-D1l2y3tv?wualzt@Qy#d$O_bKl#u6o)z8O0l}2yC7a7l~C(uSwUHR zTJAx9EVU9mtz}C}y*5T$b;fi#l7uKl51fLi6a1;5ay93|(fB<B_bUFOj!vVh5$eOOX)Z5dQ%VuD>AjxvK(G0vyz(#|sOjKVP1;lr_0M z&?r&N4aFTSY;BTetLj1H#EtEnheQPs--904S=zP=5UprC5~39nZF|ptj<58`RakW$ z9gBcVTsN_O(N4}V;4QkQ9Mm!)sNxwjFF2y|DuW$Yd%&mOoI;m@ddpOEmtp41k1n&MeWH8m zJpS&5w|d-v73L(D@`I%CEIQ$0DQ>TCPNG->IbCnNhe*-d>kF-0HW}tqpH=!skvLbB zU!GW6VQ7VGIkw99(`a><5fi)auL*H|%QpBD7Odh^>ng`1xf?jj@%1@vsjjPY|ehD)Uz zb?LK8+{5X>}PNVbsM zBxH*J_|bny=*B0n1M`qy8`g5OSbVN4B>!xnPk=Tn`9QU6=DZRR^qYlfH&P@g{2V7q zWr}k_IzJ@E?aSq}0g*38xX)o81!hm=xV-aUFXmd_Y6M+|rN5(pav5nGtw?m9FtGZ; z8itOvaXbfRD9#PUJ}fi?wT{WkAp0n{1B0?E#T_TBmB2;wa@MQ2hdgCkJ9krtRbyuy zPY3z{p*s1%hITfNKQ_{)NI7r!V79fLnQVOupYKvh4I)t3)04YK2VKh(rntFeVf|}= zSAXvkkF4v>))-lvhI1?5y%YD&U`@)LK9iZ_Drt5zF#tixA2GVZjJ!4DtL_)jsft;D zf_JOI-%98YO|3+y&qOycu7~iA%*qWr_I&RCy&_1vCGmr2nX-0IA@`YWvZ*Z)+&R(ktjr8I|UvTyaJnmgvJPIZV;pLkObi4ZkLTlQjK_yW+kW{to^Q-l z6ew6kS_H#9gAY&D4%ckJC!MOdmEs#UK!#w;1zW8-X{il-ccsRN2^LYFXu)fB;p{ji za!+zxLb`JgB?IgjcCPBz`9P$Q^-A7lqh~2f^^vQ$G0KRLQxnANpH41Gy(BO(|Mp(3 zAM=2PyMerM62q~N{7=rPB8|SR0Iza5Hwvoq(!VcGre1h? zBC+pNqQjm!pI&1veGv$%Cemoi!XHFli}TBt?;oVJ%kWL^P~L{38i!l?S0y;WR=0n< zTP$WOfuYaB&r~Hc_f(Z{e3j|ANyPeW(Ec!c_Iw~H`MBH&Xo8F<(W~wh}5FiEuZG{a@Flm;`6T0 ze~yBD223N;_fg|$6`JEe^T)Ce1cy@xGw}Vy`SQWCTW?KBq+a_2 z@U}cqbY{sYdT=Fnz$y%#E{Y5@CDh&o*#RfbVKN1(?+eF26#-1RiWqr6bz;z#!0dk9 zyt{Vn7iBMN7O;O7@B_v`#XWzcLRwMi)PDU|=K z{77EfKe~D37x}{RFf=kQO4aE!M{<3FsUpm&*G@|6MWo>|==Y*9X~qu*f1ernM_GT> zKQ!KJyCx;)6KM~Q?+iabgPn*NuG9IpujLuJ6^`C@l{tmn*Z^o#{&!l(wauJk(0zSH zC@U(CpdQW(mrjZVTNx$4-a3lBg4G+BnaO?_ihpaV;*KCN;U9gPKQweQ&Dvy3e=(N8 z^oxVHyw#_W$KL~3%JsoP>M7(c>8mHpkEUM-Z*)Wy#PcvfC$>NS6q+^d`t$#L+)hfc z!1eR~9=6RGA%Woe=3pC!9@ku3LxWS*3e68TWGavy4FZj^K*php@~`fmGA)8(nr5$h ze+ID`SN}BwL;7nzYlPdCUTf!N#YO|%M49uePar>6RGOu!vx5)+r2b3Lhaa4E0a&&g z{}%qzb=c^rCLLoI@j69mp`t?Qgp(pHuusXm_Z09u3qQ;5&q&T*7n^?ck?7+WjzfmI z#ob|Ody7s3KK;T#P0PtZG0SIazf~ZX0a$R|IscZp`EjW6g)>aAH@rB`8DsVQGBO_y zyIV4af$EaQe2hR|&H}%>`76VR2h87Z4^{#eTy)p};86&u34QyrxfJea$??!@jNgWP z!)4en?R|PTr-QKAgg}=@#i~@*%>A$YC<6(ff&H%c7F7R;>pmPikhS;6X#QJlz>9%A zNBDzVl=O^fuW$dSexfMyXZT(J@2bFvc*HbLp9#Wn-*Tkhg$iH%67hluj9J_RDh0G!PZ*??Xd;Jo4(Je>G zZcPYwTkqp@9fQ5T3mS$>wx>v^f9oULCMS42m>@9rxOw0kutTIXLJI(+d|mQh7|6_n z!TFR9=BY@YzGZT~3EOW~ypW3`EH0%4c|_QQS%(hUD(?AzDz#570AM^Wvwuyzco^u{ zWIuIVxCK)v!VZLMQO0o1L4cgQ;cI0?zvBfXn&>)yS)&IBD&IYW>_$!k`6Jk~|C>>Y z1l&2$X7Q+bJ@Mz95|v^7pF~0`5Rp1ZD@*NPcMTD5=P#bjzwrFkEkDH(*N_Mg(P9#B zr2J24WBU``Xzji4BNA1AzW$i)ySWp{6wUvgPZ?Oh>2i_l7sla$7Q_Oh!ojfLAsa?L zj&_#g&3;m^ManrNr8$Bbp1nM4LcQ33bs>hq_SLe+aZwkOi;GTNV^FmFAT@t@K0@DUL}t0B z%qjn!i~fZ(yz1P6(s+BbC;xlHB!Y%n0Bkio$Rm-^W--Od{AlClwe5Yhhp?Wt{8&lj zhp>Q`XA(pO4n?>ooVRxh=4%d3UzHU5AC}zp7_?!_v>`e2cQ%@wZc(x_wGEm+tUGY6 z2gYG2Fa{@7taulg`!pwLZlG0;Pww!-kN$)5Db1N^6ul{Q&UaKgXv+U-_W)<&2OHu?wXWcre9VXVp&ow??1kaZT0`5?9bz&ZrlHHT#F<`WJ#fg zB%y^A!<3ROjdkosWXryfb!081vZRucke#e!pJZQ(tYz%`ZtTVw^F62QzV4gr)Ajy6 ze*JY_J*L;|T#oZNj`MjukLPP-TEQ=+268antHJH2bE8bskVtKEI9xbd=1u>6=J)J? z`?veGK{KRbB&f8Gp3+GPyYWMMROWxVB)8{ClH_fCl=cez8m&P{l_K{t2d0_fP*>H< zazn$Lj}96Uetx1w-y5ahpV&XI>MeEX;pX|W{H^ID6a{x8>(8$h0Ah<`1Oyhx*X z?0K{tXHA2vm<_*(Rbg7fkEtT5L1RyyFOk7gKtJJaX?%5&(rrC=M3d>9w0p;U(u@{0=A+|9g7yfPE*I$LJM`(-i)1?j=yw5&299UqJEfYkdEKgKI91!^=dG z9=E_>GW_o^87r2Mt{MIQzmwhj|9u}w?ZVCf@{j{@(XK_YFC z^N9W%B>kC5)RbMRNcl=ma^>>SC*nxmvtP?Iz4l%+JP_i*@MdkR&#J5w^tWZ0fboyi zFhho~5ltyE)ORY?X6e!#{Id~BHl?zk? z0D$}51iv~BL-l%(o#Sz6g_6sO&jAy0z8<6f5rhHC>qoqhV@r_>c$443X`!4N#=I#%wAu*sY4=_VMK~k2+G9L4x4Z;Op1!`a zIUE`Afcb_E=_l41yFFswPeZPr^wiwi4tGOc;Ho|w0E;JW)(0ijPVOu)G9KV#5U*U_ z6p!5}KU=w_SuI^FQclXM&TR-0;7ZI)%3DulBx&l8G($=1)mPGYq@NO5>l%sYNmxhX zh`qIhEnJl{!0*{|JkaTI2P(R~4U+NRdIs}4Yv7VR8qsx+d0RU{ zC0-HFmyx|~a=ls6V!0%KGk5q1AFW5`myfKoLGsugs|juPUphx}w!74OF=6I9gC{|@ zTcd-YVo7P&1Zlw2pFiCJvjUC*=`bGyDzk^Evi15(Lpp!|c}(fFB0ttTUUBg1A)U2H z71DHDw>x4g$7frH5?&d;Nx~qXZQVcX7qSy&!W9HxE>9Ir+Ny(^U{R4X6^opwn>M0X zMKFfCqZB@DO{3I$jiuY_61Y93mEjh?JUPIprA1?F-g;p$$UWXaPKvlz*^hJZ@9Nqz zX{raDkY4tUzVD|ckIsN_shTah;d*FoFxcCX8!*XS9#sqk_hQ3jF$(ykjPUI|?{reL zc4p5;wSxco3O+#wwq>R}wk459x1;oyGI#8Y*6b2GH#Er-M(h|^lmAHd;<+CvZHd-+ z3Oo1I;u8P&Vv`r~=aGuf18$Y!82sLRT4#bZZfa>^`m>jG8^JAr{*bN9=h5}dt7s4F zQhGG!b1cJ(3DY5E=7Y*x(wg&k=EVF`UV$ovI_A3!zVn7fM6{q*Pv0bJC~je6klbt* zTkQ4t0x#o*m=9Bo*cD|<)OKPbP4MmL)wJ8u*`JulJ^MJXQLOW9*>TWnSFVRs zx_9S;^_o)7u$INUTAS9b4&n2@AB4(Fdl%JxgCeBnKSc;1#(sY$%tI;eLL z7AcR{fWu!hi9U>zIai1*nD0+`o?Uy@JtBk>gfg9H!h*vo=>E#B9@wF znS43(r9>}ktCUrk9!FcmAGBtI(VrI5Ngp`NW~*f~pX33$28B2;jE_I+`!OUiD2}j# zRy#a?TRO_)`TlXa);Y1m={!lAYluQdla1ERfi{Uep}8K3BI9YI%DU9DH@l~Zv9KDR zH=#qzt5)lc&zcs>MfaXx^0#l_6qE1&ECRJ$of6*%BAK-B?8DdMZ}Vkril#D)U1qMn zoTfaUL;Z=w3zh4|gg=|4oZk_jlFtCxS_1gA;spC>@{mmRVQ6Ms-htT?C?Wl=Oxtl< z(H5#N+AfhXg3@jm1}0Lagw&m6p99R^U^JnZS;Zpu7uo-cyyR^u+FM^8$88kiaXuF` z#CG1*r!7}p%otX(j90ww9iQo)iWIVICJ*5K6P7(sh4&0B(10t~=wN7G=y6D6(|Ovr zhF(jxes-QXT>Jb(f`ZLCq;5&+?7;HE4@7M!VL}{xldCNIXSyTQpTEXbb3dFRX!Whe z$3Bmg+nP937c5@3HeCQ5kvXN3F56*nMvm{mAs-uJDYQ5&llFzMxTK7!B(< z)rV7e1Lhwe9_|s+J7%rT=9eO$8nr0ra-zC?UiCsG597I?oF{lt{i7OdhPA5)(ApKf zB&|vs)*Q`)uw)asL{Zlu&(*pSE0+NP}g zJZ?Ge->mxL$tx&nh7XxnD}fKo&k4B0%sic+7R30#Zs|1?t_-%p7zcv>eKv@Vjm>Z1 zf<%uVGwyA_sCO0H#wg|=TyE`7t-MC86X6nzFF3NQEf< zGf~k9DglF=YlSo|A1s+&x}pkl81InhlU$-LN4A;Up8?ai#0D z7s6CdcO8E0rF2I5XE=LX&HZM;%NR>Opo4C!6TB~KKQ8<3sp_ig&%Z>NjE|qyn?K4UJvXrY z8dDq-LH7enG$&hg-qjfg_2!!K&$F89?cIWmwx4X8@BHeBR;#-K5KRa7s3C>-#32Qd zHzv9+6!R|>E;V@=bgXX^^t06+Qgmt74B`&z-Xx70&$$7lIgq1v9?qe5G&Q7N`07qC zF`mOS=Upmk`o_Ce1c6(lob6`!dgc9-kY}S5%iw@0w2gT#^pyZ<2oX$gY35TzzHnr7ecXOd#s~6R9UC+ zWp=;~?}qZ1)_NtE`2u9#djpH$xdmHcT3zj~*nX?F_1THGG^>*0!gnCcKfiE2(0^kN zQ8pC>%-2&X3GN(2G$QvTm$qbQqpi*%IjLE@m(sW(<3vun@fyd|%>OxwT^LAsFKJN; zuOU{M+3HZAB=NpUKWQjUr0ghqOy>cD{H~`MwQ7J8s6cjvR%6MNl})7hdTyRaJc87I?A%R{g(Agj&5xy)-}1+j?gzq8g{;q z-H7G6UT+{*@-#}%&KNVRy6Xh;5LFdjvUxJgvJR1%q3 z{+yA+dg$R{z6`!hM?iwx*&(9bH|K6t)Vf8mzU2&8lFXY4F_#A(^LtS6zzummWUt7{ z;IlxHAUN*^ZK2{Rysfq^opP>2~Ha z);-pNnsKbkqxwZdmc4rOW0*z6&JP|}L}l(U=;9>PuIx{Hv=hdnDO|Y_&UPW}uJ=8+sn1HMQv zqoA$To%g-{Hs|!4?xe86C7%J~Q26^y&SkBMZLHXlGb~kjF=1VVP?!kMPWS3r#r?^j z?FQ3>LzRjjkz^&i($7(@JmrF|?(KT(V+5EoxgDMPsonf1;fXXbi3jGKkcwABX<8)n ztH&fBrW|UuVV*ZvQJw$}VG%_p_Grl-YEXXZV&lzcy7W(bT| zVpKvW?|~)09s@27{I0M3_zeVBi!c>gLnTg=?el@lA{9}Fz72?IE9YY?Gg_vYU!*C< zGStdkD?Kjqvz&jt4D=Xa4)c(v?nV$m59I-e=KPs3zh z6sv~qVq~lDaF&NctQi6<@zl{{U`3LIjq$4^p(1Qic!i?omAhm6@A$0P7zAiH)!yHv zKQ@o3`{)fgQ$7nl($d>l9ta8dq9Q6iCk?wZi(NR%4SAD20$RApg!b74${XjJ{Odbt z-eQ3P88yD^$#~>){Os9}^Pv8}@dePH|EiRLWWjsV%_qfkEdwzxy?PFXBQ^aHFNJY! z=Cp*;52A=&84HtG!fYSbtHZwu`%Y8=zdD!Wb%`OCn>3Y^g0RB#KIw=jC}HOY@X(!n z8F$)uy!JqoVgChk;TtfDr>4PRZ71(F-f1~0Ew1=`48mo>+>&up`rB1;G=SYD2C7XC zH}z|VrcI!jSsypz6Hh`0xxjs2!p_2MWjASdmc7qukk}K9`tf~B$u%MJAPi_~a7s5~ z-FA8qN_SGAOL+GF9Ir8!YDehGHE863Ey>J zH*CL8%`1?Y5rEW5XHMxXNO8%3fzxW)Bj_D0drx0|2K;)(mgcm-<@oh5 zaBHtsBb7ejggoPvNP9TN``DMQLu6J7U!z@4B~b+U=CN#vhXb z^Y|H`+@*@}{D9XHeNdta`+9*?%?jp`KQ~;z!U|&)2IV>7l`#IhnTrq_m}5KQa2(KN zu#3#{u<5;r@BCdaBWCo~3EhqeP<6E0h~Xwr$oxF6E|W^R$ZxYsfdHoS0^)PgV67m} zW%>!=#{vB0NWYV$zoy&JmnR7szfsr>GnYBX$bueB9S6qkxnq9`=9)Z_Yi{ms&gd$I zdsfn#j1itvDBH&7u((oC8f#;Zi~&Z{w^fnR#+eIH=OfXr`Ihmr6z^4}gLl4)Sh|bv zEG@(7Y^oiFy7sTne3_pk;2;~WeMT;Y8g?V=TcSLk9HI(LqLznwiClC&#yQ6zE{o-d zV2GV3Zeb5P5u|iOl+t~$LQgv`GIGb9PM_H~v8=T+_IkOsymKMz7kHJj)bgf++vf8F zeksB&`(HJFJ)N;2I=^OKsb&Q(zb!rd4%;(1zx0+0PklGVujZfN3wg_*#~C5L6ExgdyzO!(LqA4wYPCr)2XI}Xt}BZr2%n{Vz+7+S0O0+xNp;$2 zUj2yZ2cYLpMVdI)Erq59$H3ctl@^LDmB)9!*2DxoSGPNc8{o2u{Z!F%iD?;kYLVAP z^l&=%s?xghy4G5?m=s%r+NYVq0w3;f!sx~eo1b>p&}v7^RI>u1Ad|_^f60#Tafj*i);;SAt&G1<)eP5kAW>xbmXE`vs|aI6aZHEIB~3TIk%^u^xVN z<}BbLwjv|!E&C2Mb8vM?_R$Uga(Z@~KJU8#dG>(Z2^!NFdw6iX{_-jrQRu#F;S|&o? zKp7+RNOCA5@taDjl4)`Wzw{FA?`~cS_q94#imZo?%=U;FlGBo2OIs~jGa;Yls$StC z#eH?SbGL>7hhJAX%qJMP-6pUKK(o`NP!9;pkz>bj>rvGMAa@Z zhM#iAZiZr~e1_S560}g$F+Ppncz>Qt0T0pxU@4UwzgFRx%IGiCU@bcW9z1|^H3 z2rSyX3*b}MBd_Wol$wB!nL=xbMw%$+W#x85w)gTkn6J57z14&Z^`t%Irg~P57Z}vS z&bNWue$efXHztOU%aC&+XK*7DB2|&t-szr&0ecjAk?alf+|}*cMfXr*i+JTHCh2Eb z@0pjxL6k*(ravH&X1UmiJp*mfBk;1KtRspeiWiJ&BqIy8MCsI;o+w2}c0Nl@c(-sT zQB!|~3Gz&biy^*7mhr>H735am0M-G8CqOC4RW;PBhp|KiHUIdGS47uWgqL%@_i#US z+Hhx+zr_Ot2JNB~5I}$B79M!Au1CTe=41?>ppPoG}PYSE;kmL{H<9N6iv#W!x$oQxw@ zVk9>b5Z?qrbrjLC_HAImaEm6iRHgT|G?4ch8y;b%grxiU&TIxPfwzJdUMGvR93z-4 zBP6agkBUI=LMD6;0zQV7JfTm+6_G5ogd(r9-P&s2{gD(H{ z9ZEYXCx}oSzT=VcHi*;ZPIBqI4geBMZ{i3a@q=p*&UZ) z#VIr$GP%xk9BZ_@;0MO!y+bo_6LQ;U9OW)2aB4{Wf}h?{YSO1xiG@{+^}#A|C7?YQE=d>$TCGm46V&^tKF|R}l5hvK zn7S-i;_TJTFdb38FS@If;$5n{s`OUxhNc+@Hk_&>N1&yZsz-uLJ4+itQ!}4w_Wn0- zus3xzAsR*dsBZDMnBbkaKpXu|jiq0Tcm5BATlKHYSTRRhxaf2Be>`x*XQjG2a#%!a zsZ{MoXL7eJH=uzDII(`w*bZg9v7wxE#%n*-)Dw4l^mlHl_yOA(8rWZ)m|>aXGMfM; z_o2xR!d5M==3q?g<8}y&h^9~YSYtwTBO(19Dz7U;KJ5!LbyB@7h4SN<( ze0QLlWw@2JWf!&oV|Ib?vKk=C*TVSNtK+u{BrT$s`nK#nidlLY0ZpO#2{rpneufV; zYA|-tp;dWBsy*M}Aj}IYt~GHno<08N6dVq}$|%ipP*enn5>Dh~opSy$mm-M9H4z6C zD|^n-H)j@Sm8(3AR~t1!**1&BaGdgY)O$jMDKCn5(j&NXHOrhs{Sw|5LDqV}8+i=pWH#dwfNe?^r5t$HP(JSC7-T65zKwP2Z@?(Yg zS7SL$iaU1Ef+K;3tb$p_!%;i{X??zRG?p{_b%f@9_qTuw?}v&-4;B?3u^OhWPSL_P zmAt5Yi9Jk36{!ZG+@S+J_Aw%e@F3WtM^9Pb`ns!!w`oN-=uI|2{dxa@;+M|2C}iJ* zIg_qPmsc^mhl7^estzmUh4#;#y+K5IR;ioS9(ff)x0dR2L*=l_*snV>m%Gc$A+zbH zs4Tfq))E8u@#k=n>vE&5xRv_k(Y0`I!khCpD5QpY-|X``gA#H=-DbTm>XMJWx`f%y z#4GScn4T9HH_LK3!ueLblQrT#rW^d+XfmK=JI3CNLm8APx7A6o+3Ui{t z`mFvUj?G5!#QbPwrlJx}xrk&o8CLIaQBh8 z^y*gGHede+8tHWRL6)o3eR@En7yj- zLVo$%v4QmonrnKtt29G~&aG17X0_^ZL!Un0KZEqR!Xam9rhzCDV?>XM{G48wDU-<> zvc64d%Q4G{6ZP5(Pg!B7qB3HxqlOuCNQ=?N)c`J%lbra<&@;VxrrbR~(1sc|oSxE3 z?m+1t4(aU%N0mXO_j%~%Ws4(NwnX;t_dM6By~V5469yC95k41=2_d-f$2V{mm`CMO z49D|GEzLUh=L#og3+v*v-OKl%q&fAiP7QJtoqI)h^evtwvTA8V*Hsz#bw`ZgV>`VW zW@*kHRdVs3d!QOqYEliH(|sR|a{xKs9xYex=5Q&|L7PPP5Fr~;*6(iWgvg%;c<1Qg&~wJub`wE* zfkdRpPOV%u%a90wKl*vRCdP-YY^)5%k~ynXToW?bTgF3w>3}-e&i=5WGi;p4!AB0@ z1Dsg%VQuYw@~J!;cN^+H)SpZ2Bfsg14bv-ne$!C)(slx>I;yf7LNfUn(Feh8n~Lhq8z9noVYmY~uwJz4(c~dzCSKL? zNzdJ$@Sp22pcCwwD?Qq9r*pAX1T|_E#Qz1cEr_z*)CGE+?rGh!IjARg`d%?Ip*5BM zDY@|OD_bGacFae{Os%M4g)*^@4XUT)YG;+}gm9c(qahnjdBfTts}!Z{93_?gQ{FA2 zEMvP_wijIz$>#@KfdWV%BRaxcxbI$!-Ks#JF`N21T*PRzyD|2N&q zz=h`MsS70)R#A3S3+t)#Ro~G%W@&x>*>2V=j^O71o6=<0Tso>}{Ezw9w36pqk3aA$ zD;@t1j9E;?Vfa5JtpImHOQ6#G0GWRmF{(7x9wk(iC@UM!fm5El>VUcCP{Bc05)Da-dEaAc()e_6#pMu}CdfB7%R1Pl+-<@_9ff`Zhiv@bv-&1;?S=1J)SLKt% z;aejdpYFnbo8IMi5vxD{~{`l-bt)$HJ*rMz>qQMq9>N7uoQ_HT1&l_P?b>zMmt zv))S27h5$JQN==R5KBbh{I|+@y_?dyu5bNQ#<)18GI4aSj=V-5SNhL09%D2VMHfCA z3A~%U9(-G6?0WgZYe+>!#_Hts9#A-bO&A_I0_cjj1Y6AU1#feZrJG-D476JScz(dj zvk|n_m{t8K!Z8%}IJM5xM{N0XVazKllRyg}!;9IP#byp#blt_>Y&==~>T*5w2SLcK zTh{O~=wmQ^bdtULSD@WzgJvRoMfG*R^{mkC8iyx$2*Bkr95@JN`dl|1jUhIOOwpZ@ zxuo5eSGAd;-Qfh0O3d+v*#_qIYEs1mI`kT%a7u zLbp%7tg0jRdofAhh{9pheQ2l!v=I!3Kx>*mC3>!j5<>X=_&d`4Q!EE#09F6F=B^AK z@U|4Tzmk{GUmHJfcS&aSB~i{OA<&6nyfgUd_C5P6Lhq^~rw{>jj{B?&?F^Bj9tm+* zGFgNW4-Msd8}^@IG>NazwAe?qPINe>*WEW+Tpm z=iAbJ>HPLhqrfH6scR6nX-^%8OEafN?V)wt9ea4!GayKlr@nU$H{xTypSsd~Ki%aO zrtRLHBl<_&$&+etGjwHnisJea=9fJx9#~(iIsCTe^5gEI>t*zSUg-;e(=((1h;N`b z!lNz{bxas=1@8H${0vFH6mY@1^+15J{54aO7tZMNq@+bp!y8a2?64&fAUCfs#{pIHy_E`(?w!8 z0XqY5ZO32i6glPibm0TExgoaEv3FGOJ69FSb#`ifc_pyr^l5tepz+6@J)h5{LN7{IGBBV+5>$*UTjBDW ztcS(sdmbw_h0pSL(WB2+y&4Z7YJ>ksP;UwH)~)|IaOHb-8s2+eVYhP;2F@j#Je|V; zdpceMvyrmsD{auTpyht8H$X1Ym`Eo)bf$YhcB4x$!_0U1ViuoIQKSr@__iH!IsxJ8 z2o6Pf3>67~LxC)5@iqKcgu6CVccIA4DEs!fZ`BbrXQ#M7d#=yPrM7d{)khmcy64^Q z>jfI6d@a|vSmSW2*eLiVecodcPXl~xL#Fv$$Frh%mn+YNt6}t2WPKajSxP=k#Hw+E7$ka?UN?{{9JkipIDLfS^ahph=L6VB-&rRITHq?G3-ydtgCkV ztmy3@CG||@Pv@q3hvhE{^}`oA3R8BE3$Uw=hi{MO_-JlvEoM3@gPY@ja1)7fbrA}g zy&ymz2ZWP&>?wWo5~{u3v;1U_$DDk~CiIf%B;c*wwzcdMc#D{07a3S-yP&VCCSET8 zoCa1n^MV#VQ}6>&G%E)|tX4g&UQR8-A=ke|Qx#dEn`Rcz0(58U-@GdnTI;IZe_AHTh>H{Bu4=JLY9V*XYR_3kXdgAN@a-Y*1hJ0v** z9e7vUQw(ZjYGt+N`zlTo6-CuYu1kyv8vI!+}FkNW0Cj4YCY(o9Q7~{#lxR z@>TC_fHZFq?rYmQODApYdZm?~Psto|O32#eK!g{${t(RLJ*jfpLDAb&pOyG#WA+8? z>jz`K$W83R`y^j=y`c%rG2a&FJq7|@k?>X??WL>5zm@;r9)*3MZl!cM=g z2UJu}N+7+9rm>wp0%&Pd_4|)H)hcnHx3E|7F$e=ie6g96`{aKt*@%L!MX^WE3U%xT z=N+eS)GcV)8rph+syMM}{~Ir!=ee2-CXc+T@s`Mzca-r=`^dhKE%8eGR=$9DSs`Yg z{KtR-T7BwD{1H$Iot;w6N$D+_-$M!u{A)Ukcc2%+jkFwJhd@=UIIr zG~l0IUk;76^Y}KEuWpN=q4F*HST-~b8Xt_!7i>=sM@XN0yaP(eyWdS@gU~MP=}Nh? z+1dVOVNdWkpE2Lc)#acvS^)hc@3s6VuOzoVx*8uU#SEno@-$hf} zGtMj%QsblZjJ4rM4^VyS1DK}s!W(J*ZB9Voy}k!o8}tW&i+uV8O#jjs2P!JxFno+C zl(4Z(xo-_vh$DNQtpI`8`8lWz&+hIt5M!x|#D6NQjeJb7Szsg^QI_}%^I1XP!L9k) zRyhJE71hM+>;C+-ae05Zq+Mfy&_dT1Mi6Bze z-?1LT{|dbJEn|cY+RXd5cvC-V-0uw7^$c(U0o(jqShPDhds%vl(Dx++8lz_>djMnJf7^{mTM;= zw2q+$#ajwK2QFd8KugahX3EujBZn2bg7%7Y@@$<1S2v?$7Gg+=%D1JNS=d+h3Nq)(P7h=*NKb;#qlVkUA)pFwd}p^!O`QF0Q{$1#b{@~2 zu-ld8U}L|$Us^&f_H9&Dcv;;39kKu#f69zJL?bcnuv?)nN*l z8k9`=FxtLycU#fB<{^cbtPk?q1t1PFtg723mf&W{`iQzCcHuQNM}zkLW`+wDmC_w> zQmHY^LszRhcEGV)*&VHV`VPTDG94oTcA`+885E(Z3Koa>WZQ9!pKR#vl6?`=3D_g~ z*a7hUS|!=pstyMRwD2)Vp&55Mz3X}qS*zM!!9TgJAbX=U;D)0l8u97)9Q}d#OAQg^ zoTILNXsz?scZdQUVLD-f@@Af|h6MVw{L%>UT^X;{fVgf|`fhjY2vb_T&W}%` z3sF@GP5w1HmLU8c1JJebL>0JsrgUGT7Ljevc+ty%Ry3`^Uohif)-k;Yx-T0Pg`S_o zL2c@fj@b|FwmsdSU^;_Wv81wQc4~;%DJrUWrv=T%+1c|#1h(%V8)xUr+fsnv2FF~Z z4OD_M;@ZInEcpFW*s|!+nJ?4ghb*_VY!iJ`kwgOyQ85N|jpGMdDzU-c?pVkfpCsS# zNXqjLx}-{oiHeHpjx_WUwfZI@!B8SD>of2csS2Q_f)u*(jY0uXZ1HE8)V{JmG25R% zA69K~i}jFl*SzLnWlUFePrbC>5p&($+n;UM%66CXD9CDs_kxyxs= zXkgC-^|Thth<`C__$F>Eb9B@DbDet`LVX3man+U8_JV2GI1`Wgj;|>aKa$vcn`amg z4Zn%ZyZuJf=R527*xg=Ai5()aJft;?`L*3>1>P$2m3P+FT6O0Fbv)SowzEKPYO({! z{=CMO%HliUxl{3GyyG=`Mb1d>x_d`XFt8xo+D-_m_-)35$JiZGdsXK~)P~rn%s1;c z&(95hdY4gUpS{N*dMO5>+gxol{`GA6&zCBSwuM6{RH&#z16yX7_0Q8reZ~5uH{Gcj zU$>S%Kt=Vzlwy7*(OG4Be-U^De$b&?dXBN*+OtVV!5OWP;byWj@Orv!X-(xzFk2+d z<+Rtrucx(afO%Z$KM2#)TiEf2LkiDVu?X)8ItO9gj)H;Phx&B)@ip0f8UGpxjbWg= zjB5z#j`zIoX{K(i8F?|Mc}C0q&}op0);lvp6sDZXJ5r#LnHJ3qdg^F*&+#nsY8%!< zV=Z&a%C}&);sKYbu)3=mMGhdFtYz|O4(`38@G4Z=46dCbX{N01+0=c8pSfQB7CpGAk zXEPGV#AlZwsi>tVa!6D`wkggXRoX5^3S0|mWpHI)5}^fGeb`!2pR6o z@J8z6jNtS=?Rccw@l4#zDP!9KR1|z~egJLo+=3wRzuIkw2Vp{I9!6x^N9ajrh9;^I zzEx~fOA)@6Z@;wziO1cE2RbLV#0TGI!8tMM3h*e!pCTABmJtw9PqhPCfgf27k168r z)*pA>u|Ssx4JBAa98?+={-{wRdlxR-SR11su=M@{mA2?3+bHw##v^=h7mZN`XQF=3 z?N-4_hymX3cN6KM-CpJxWX*RQZfKj^5h^tMwMk95XsqP?a;!HRl(bj;4o)(EXr6au z{?g22_<5rEP3B{eVo`sZ2d#r8C~{@wBt+*wgsi>KoM&-VJ&&1a%;L)pjtW-1=|1r+ zGbF-X$$R~py9wCVfPj&!JdNeNE9(84==ALMC?i9^^KdcX|NS})@PE~(|IyqFZ01}; zZLGd?;}L$H=|=`1bed$*0a_lR+z*da;+D)+SOuvp|FgWzIV-~ufz~e_1jVlx;g0)3 zK1o?g5PV%gY=r;rfK|-4UF>yvS6miXB=+-HJ|g}h=8aN4nqYX$h{FE4HVQak|)1ko98T5x5P zS7t3|f(-lZZM7GbYw&k>DZJfb{;5InK#6Z>=q)O$;Y5)~jN9EW%NDY*=}|ErYKY$9 z9A^-)?|15(3zJkIPW!HJmikg z2~dS-Q5!A2YSZxko;CJEWjgAihIzl;K%Lm%LyZVDq6JENhv zvh~?$aAN;4?gC%=r%5Q~^l721%!ZA!X#qL`s#Gh_w)t*&4`Cqc3UG)nbn(jClfk^w z2pS*Y;R+NpsycGN0isb=r1m+a2VvX*!=Oi)1w9G1?b*8B(0K{j?huV@lMbzVP`%7rrS4GHZ@aQI4B6|w3X-O(o5%N!InK85 zK8(_zYPx1HcH#GERI8XKI_E&wv&4~Eg*w}AAY_i;&3?QE7g9C4q)au^k&%cvy0Gfz> zW(@?a8>>&2k(L$H0fu1MbEJT|IRVzO{0z+V=H(+V8V{0&_4iKnVDu&mZtykrJZeeN zmhdAK@$~}LNdh6lJiT!~b9v?Lne4Td5fL+cP_Hq;d>Dx4Y8zm>E)Aoztm?Rc^-N>cE#G(Xz8Ty;LvxMBppiBcY%&)JFIgSTiVx8C*N)fuP zt5SbNKkl1qNvOH*mva99UCy{O?9DzLU8`&#-*Bo;2bNr5)bD;7GWqLPtbA&(>*p~+ z#_iX^fh%9^Ks-tQ@NH;%j`Gd-pQV8Pnmb-(%LLIp1ba1ffs-k4V(lAMorNS@!;~x5 z+Kc{|V*2N}Pva?c=<`#IlQMg}82=QjyG0&kPTNlWv0zw8TI*ZpHCSD!V@AXw&27!f z@q7M!gvzKz21172GO2x4M5?ZH@iu9v!}po*aS%}jEZu55bUCF>t2$i#_$85?Ea78o zil|?VM9qxgrf%Cdh`lQTx!gb5U8{Z*w0$~qD7nXmXd>wxk`B++dZ#sAwZ8Z3b z&Yt1P*hl^9GbJiLZK;h}o*fr3H!S1xj>y(8t1ogte>JK0jXiJq!GO3s<9J2XhUNgm zj}O?_Pa0hYbohHGbMWch=q&J+C!bUnPH*WSZI`suGDou>N3h1@^(ckV-y?CBh{I! zuvNzy>-X^!^CfWk_(D&?Y<4!?-L~3JVDcyr%C z-bz`OC1sd@l>VS=J*y+rJSARX=6tG4yq}B9ybGmW-gIXaJlyCIn18AB%tuMj%}ijS zdE-UGERb)7g!~9E!Fc7azeenuy?4a7UQ8iWSV($p+j^}NrhKpXZXW|vzr_bmaZjs( z%j|S@t;itIyQ;ajH>ChC1b!w>)d@hvDoOB>Tu zAjnc1w*Oa(H=yZS3$f`8QC zUHcdF?EjdYGpWVY%?;!rFic-J_5b-`11XorereP>M)YfBZ3lp5B<+WMaRY@2*zcxi zO-yNpRe2?l*3daQGc!|!6N<+1ujCR(Plk8&#kW+%-PSb&S{;?ri^5wwE_-9~U&<_C zMNU8rZo2>IzfVr@kD!5xEZX)QefZU0@lJ*#GIzGkA(cLrS)lbhmi(E$J92wZ^k)F6A z`L7mJI~u#tl%`}m4qA0$Vu(4tngh1x)Yk|X(@M03u7SKKENiM4N{co#*y}le?~AXG z1+a5_uMPug_a9lHjicGdz`Y451_2?ebX!cm%-diI+v z^s5CqL)UAQ=2CNh63|jy|K5w9ZUUxuBtD$x~<6t`5 z%Y|_vW$OUlk&_TvTk(9`{QM#@*KPo}u*R^qSR6J9uua|yoKJjN2l>u73et#GRY93^ zg1n;ZIRnyTr2A_-t=NA%m<0}A*BH^ZeJ&fc=$2b)t{h!IfdtdXjJPlpHAs;Ahey=6 zsX_h2WlH@>^2brGitD}DQsT>)Yx~np)%IM_{-fo@1316kFKm)9xGd}b(#eIv)5wd# zT)8ikB(^_)>y5ylHFIZe<#nM4w2rz;@V$>f8{>gsXi;0igZVaLFA>N3xzK}m;dl+s zoHgBk@52Kz4o?O??yke{In!1^yjT+^sE1i7B?3Xwny*c-EgFu|%5uI9)G|BG>=GgI z%;f7k4MC=Nr;(f|FLViEUVysItt*})NtLD6`=b7Q{(-_1fWB~U{Ukk5*f88wIdTOO ziZN6kv8IMiR9>e=FXukT24>rqXcx!yya>2cXv-c}33s!u1R{hf-81>r|GF~Yxz_ws zVqtFs-vP0|j>~wC;wRfD8P0q%Sc{@&`zDj5FvA;8hhC=owCVvk6Ua)n8jtajdU3t!;BfeK^p|;5Q{=RO^y3*nZEs?yMWK>_y?iw~ zoyr7sWnb!hcIZ5ybqqhwy?jY==D5~{@qMaDuLwt|A>__0tAObU#$2Rx?oFj)uBv~=U;>02_lxMsxiOjb-7{}VK?fW-@nr9 zR?9N_bg@Cy>I_*Em?G&bc}296-_NdV>44f^lD% zFRq$-oHkH1f98AfpM9Mxo)@Icg7Yh{_a%e) z-P^jpV1W~zH#K|sdT;{CpXPt#?f*4iAh!T@P6waD5`2A#B6(fWw4E>#2u2Gu1BR`4 zSJVEtkrWUY=<;>?9fUoc(hx*8@z5I@kj85Sj@|0y?^`hxfVC#o znu>%wwWDWR3o?KtoPE)sw1%mP<>(Wjo?4q89-Tu{8D-sY+=M9d+@1*e~Yhq!J(6w zULe3CikL3|2_rVVnD@_51gMfO8>Ig?cX*E&;GWbba@l@~@+nH|%s7{-^5|cG zkjwuaBp8$;tH~d2lX8QYVlnS~cE`$gyzUo++i#Ebj|D!AP^#&T7u%PCG3luFo3 zdalpX0jKpZzXme~*?&jjHBdx)7krtn@T28>(15wSA`5V?zmF@BKKzDW;;oAO-L4dw z?b_=K)CxyCaVwpd%X@Jr=ntR)k#6-w&%_1MCfj{cze}!$_)@zxP#;L%O;7lrD+f}9 zV>!Tp3oZZuQ-J-qF@igw6B?cky7p2Iim@DoV7?XC{1%^Qb=>4 z$SnA7*F#OS4)EQ{*rm1x&!5QQw-4Nbys*-ruY90lWN=d%-}!0DUYdu5+W*KHvc3B5_tzx(uP~a0(Ri{OZpfTj5ve`V&4`}C{JMc`YG#25?IF?p zFYw#qorS>=S;V}q`tdN>ZgqW!2xYrf{niqsT_Qtx@6!dcHsDe|{pV=?Kb4lhbEf%2FaWYW{kJ>;aA@0xruS3UWjDF=f9nDg zr$du*0kFTN68`MmKxV7$mjbZGyVn1}igtN|R=*U=*H^4l{~RcOV=pUfsaqk#I=W{-UHdz&YuGaaK0(w)=2>PzW#s-xU{+Jxe?vz z{Lq3Xa!!!VV|!K!`ts#1pU>mL23H?o(XT;&6=#tZq`nEm^o5$pt2;`U)ypq-3bV%D z`3sf#uU^Tj~OvH-YuhZlI zEAG9cn#{hiQO1s_jMDp9se&j{1E`2d4G?-qRHRD}p(%(+S7|B`R7woJcfz2CC`j)e z66pj89YVP$IDKG#Yu$Ul_4$WuoFwNx?>YPI^6cmA?G|}5=X-T9i_z=G0BgpU2Xm*w z9ZIC9#b#R#3h8N)d^PkvA7#3SqxDYwWI=X_*q^@V$p<&KjX^IQts{u1qa!rKO?N>L zE|K6Rn}e4v{7?_L-g)$Dy3K>8A@IO=T3)uQ17h@hZ4Qui7&%6_`}0-5WZ`#ejLEBy zRd4{!`l1z<>olU?5z}@&0jM%^zJHmmFB`Z%vgcSJgUWdcHjOF3ut% z>&ctT@XJ#X$8?_oYq!VVvOp3f+=RUwV4RT5I7%Y-oKEJ(*RX@a9yxao{c>Mi1aPcp zpaLZ<#Z{o3=v7X^nL?oJk-LjM$gw^Kcb)U+J|C0#mXoq-FtHSDW@+^5yTdH#Q*g3C z-&_*|ZP9@XyqRu&7#i@l_C)p(WY6wqy5|J4fjx3)VztbW8$NkU=(Z;RepVr>m(h>_ zgpPW&2?<#V4mO0 zfHurl7eMbZiN9WQ{+qH4&tA|47t#K~ANWmUQ|hc<*%OLR0MP!9uem#7)qfC*>-l5KZYlyCsb1hp?w{vUoUphCTau>zODyZV28 zQ+3W|)bB@a6Q#a>x1DQGI}YY8kIxdjTN_{;pBDE3^kYKx2Y+Q@$SNmaw+mBVX>G3% zudwUZJRY**1SDdistQU~=^g#fSah}_ad#O97O$**W-+xK6cs==4^7-FF1|7pBV}}C z&#^O(Aiukn-vGTi`UmQD5U*X)9m)qwT$cn!j+{IYdl`dR8`<@UL)9 z?JhhV2cc{;EudglN1IvF&(>OjzjOr03E1*xcku>XVz8^IC?*^_^@aJmc15FED0+lS zQTG>p{)jdN`FXKjMpP~P3L@W8ms2QXcNY?54USX#*|+6+Oa%ym@O6FK%UBUyIhRF{9`IgDEq7dd1MrCh(4fo%(3&dk*r125!HX_ndmnhq@dz>!`Qe}gsV>2?YofNDQb(4QONT0!PJkxqut}s$k=lL1N zBAd-i&(n^X%)d=-LOGV3ytDmz^&FA5H>;3VQEID%F8>$BsZdX8A((q#G&#a`cL@fx z?$UZe&>eE1k~}le@A*THN2_bVEi-Gz54Twge-;cf@jdlLD`u${M;4F)J^&&@L9bsMX7}4*Wu{+@70{WadyMr#1xNjxm&IXYFBx_fK@F4LApd&bWEh^ZWr}L1^;v)>R>i` z-FxEIjlfM2aZHC}+}%V={avLNbdu^R8JV%|6WLLko=4nI&oSGWpnldFuZ^1%74s}V zz~W!c)5RPuRug%cC%w1aq_nBRx90QSo0bZf@Z> z1MNh*4jYrS2%y}f|I5tDrk?oyPt8!5EN zH&2gvP@SStK9|89z+};L!vCa@QIP(L>rOTYAFRPeK%bn!uAlGwiDoh=nwOg!=axi( zMsl}ijs3lmd-#))4AA066Sv|Y@ow4?K>@Y^CeV4HP%g*MLPs~H=d?z`)|*4n!sXMf zkT4yqwd>ElA>i`d?)E()17NJyo$z1H^f@jtBsyqus7H|#1e=(vxXj5*%{cZhh$SlD8qW{+X2RJ0)mJaaf3%b)#xwIda{lehg&1synUC&}c%^P1A z+1kg7{abIITq<07XZ533nf3C(NeH$OG-dhARsqRB}>AxN^!cF*n4uK@h$u5@|(%;Z;^ncA;EeE&Tma!)KJ{-9j$db+ztimQgL zhoV4t5tmqMWRJ6ZFNgTUUyoComHnNY|Ci0)i2}iar~?kf9=YltE6-^Q@_)c@1P!>9 z_fS+EkQ8tQlhd{gT(lr6?)^P3NT%{!!F7PVf{UjW@w3bJx!(pF%u2l7JqzG-28Kw`$V_{_W36aZ>x z>T`oqf|j1eIrT^V0LZ5BxE^Fs_1?Xx?5B0TZ~|!^UOd5U;^Wb2$L*a`9c5n^F=*Yy z)v#;dE(#^Rk!0?KAb`#-6NbKCruEwRRo)+^c?70WWG&zPxjOQmjYXFm zFf`3>7PjJ7cHgaDexw?w%$N>kn5lEsFi!mKO2l9P|c)kvKL+HuJeMt<;K2o_wuH>$vugqYC&vk^1-IKT!Sdlifl!jY~4h#WUu3R69 z+gFPreboN(AOZT&a5(#O*uF$fDOR2}J2-(ktZEC+%_+AUOMGdeceLzb>Yi@rk_FpL z?Q0t#QE`W%F-e!s(>!?E+d6cf)(%J!s5EUXeEj*maC8r8-#KABp+TKv4U=J=eEd4$ z)jZH~kv&`pkhTkmjO}Z`(h2&72Q3_c(qtXbBYP|N3WWaDyXS5TCSoSDkeE@Ob1pr< zzzxh63`dmGlh$1rYaZF{ZY9C8=r$TT>q3p|!TC4y0QO(BY}V^b8p(ne;`DZwsfy|XQTkd?Ra6=l?ep6GN=rh_V;Ei5%!=23};ex z!@vViANFGRkb9^i`*Key`*{Njudu=sCOs>k8aG!l}Z8I;q|ZH0w@H&j+o?4l5hDUAj~|TSn9_ z_Y&4>F#$@lxDu@=(`BxMq2id>t)^|9q>VeBIe`?@#*=1ho5>xM}%Kox)ttP zYWyh(6gIMmTK0daUZZQDJ%MSPmL0tBJsXXC5o+G+%k@WA@1!5fLmkwZVOnVaNmV%h z>o>uzx^(}K>c5)4`yRVcxc_)AyXFJW;b8Re^1}?BYp`5XgMp*hLHR8^b~;`*&rCBJ zHD1GeaHFa4<~DIr)s+;t?dBDpZRC-G?L9mYu+kp&#%kx_*1a2kGHu7q=krFiuaZKx z@BIAYuz^mmT)O|0OV6Jj;>gX_IiNVQc`8hJY=p);rl`@}>;-+AzNfTSmjpwZCb}f=R<8+c2u2FxAd~ofu;Dnz;w%e?k3Z2 zt?IymK)Jea@qin1qfCpSw_5b$mwKqaS5zs08e@vR0$NTizxsA$}r7Xpxlsw7t)DS?#&x$8sYVUG5|}wGYdetbeE<`YLm%=2a#^ zy{Dr=IB3Rn9N5r);amIP&*_Qw$ClxEgx4#_;tIJ(g2}%hp`2%wyJY9#lb>sw&gbCq zRg0I#pSjjz>z-U!D6fuWd89|w!&P^QZVIzxilm(|I>mhycnHFbkO{|yA~DLKUm&9= zGiRxH_b~z07C!&7{5gQTiga>LGKLyR5Zd6RTWA@^(ta;b-D7M1%dmBZeh6AU1 zj{)YTTR-a3^Sp5X!c3Ad@9eBu(?~Gtvw?+3xVK5R%eOZ(%Ka91IR@L3t8Q$w-e>5g z+jZ%I&yye9hjj*CSDa}R6u4pc-}y&rguMHFoBD8CU6{_7V|C2@F9F7!JiY1|R?D;= z${AONOEwa;vzZodOb~%9WnQVd^ID)wI6Or|Cu1O%byJrkaHG)Nm_WX{`^FqYBFh|c z{iUv;V7}BPT0!do2l3e5?E^4!mE|ja{pFw^Dku?7vj=~i4brb@tS?(O^8>ND1d;;7 zdwMD5#SW!X#rB|E^5IjEixs;X3*fD}EVRhG+c|?Cswd<2bQp?71xw<_K)Ts+cg_}t z7c&sR50J@cU3$B3{8a!!yaW`gzt{8plP=WYhbm06`R`}}Fa;z)a)%Nu?2+~c-?$3u z1D1eP#@=K^chRgeRD&{zEBgNjTm_bAu&kBvl`lL8i3wB;9mS0_)Fmk zHaT&VeHqJpE(&h&VV^YVDIJ7>Hg@kXdZJi}9E<{Yk_+QL0}G^e^%N2pN5p|8h&oiDne zZxt<}KX;BmeX+ps3cR+)V5Yo;R(0TT{2pn+tMK&>^SOf21_1AW2h{ClzN88hCjLx; zdQl4foJ276y02rBHN*V(!WzFj6gx2zB~PX}4r=blcnq0mitu%tQ{4>^M-HdGD+M(0 zqPvFQGHgX}^@|oc>_wgfrKk|L&z0ud(vIJF4Y@h-J*K#J2yNsr;DhB36j@le-q7#ItI9K(_$4gE;MQ zfASyJ9Fr8G&$DN0y;e&bI&Y`Reazv#xzd0Fnk#*?Yguu<@LR7HKb$rE>M_jAyd-bH zeyb+c?@NDU&Jw;mx(cd208Js;N%N>JH{G@3SMG~K=ISC9EC-G7b4wMbYXOP!SHfK{y+4Y#X6yX6AtM$$VAnZ>)gY6zl0HkE?3Lt$l zg8rD(d#FP|T6A5Em%;|44uWih)b7NjAFsfu^Pj_bM1kt2jyHC9Zzxo739)~*mHt!h zE(5B5rrX$m=8l1OSG>XPfTaUi*B(hFkkMCTmm%nU7nPzUH~xN|{SV3?s22YTdpKz* z=s#%Q{R~jc{vbINh1;|T0|y{NtD#a`-xVp3+JjRBPKW1wl+^kvb+Oa(+#4xR(7mc~ zbfySgi@Nre(mX!DRw!-Fv1{O}iOtZ=^5h)z3Ag2Mmlvi1$|AU;x|c;iA?x#z!y}a9 zj{lm%d~O=>#KG07oqNt9wlskGt@fizXO#@}K3UUen;MA0k27~a0Qev{wGs;`sB~k{ zc?<-^DC3_*#MCOQJnb!W%6{R;&U@>>9on5eKw%X9@tPpA8hYE>zu`n{|(_EU8=F;1BDgLV;^_nkp!D^$pk}2&+8nTj>9N)a<%gNA`x);afcC`N()1S8u017Ro+(MzVIP#VK(ktODP+VK3gPFNS#gS) z`4O%WR=vABGUe5+itdYFfpP^TDFR~yhbeMKIK%%%2r&iufyJW)x4~CJH|mM6Q1T_^f{Pd6LFrxKAODQ z6H8!W51bcfDD=@5A9cvCil`5_^4xtcz^TgRhL#fo8+R<)xhHR~hdmXqA>MU+bo!~e z`c~nfPfJ!C$L-ahGwfLlt=ee5)u^9P##=0i>|;2tsN_BRSkKXu6L|oay5*>tA&$w- zJysm(>enP_-HvHHhI}(^k#EtnMtV6j+5q2PjP3)70B|9 z*+F|*0?bF@l|P@qFEI^54m;c1nnzv(ksfvo;vB5VSnDZS$^QBK-QHxc@z2$*TCZ*zCYl@$<4wYy*T~j$R5r0KMesOoFpkkNdASO`l#ry z4+l12;Q~eBQn>tf{N8`0#P$QL(C`F=7X_J%e`WzFyiz)FE}M$}qMm*RI23>Vz8pxa4{oOGQmh7rU-h@SfS;{%?Qq|J6F^O?fU23i(9?>fhAeU zG_+?epH7M(HRk+t5(l6QW}J|nOat4W-hGb>0Ho>vy-xN1nTMdjE&wzj_W(2j9QJ># znF#GEPz>%Or5@04@4CIcJcGo=Y-G``dLQ;V*muZbAHT}SG~KfTz5cg*Xq~>lifPKJ z&RRYca*+BdRY~*ZQ=NXN&HR4~dV58k+amV?(~VY}u;nvT@2PJe+izh-$8GVhXCXV# zd2(3SHLWZ?Z7P1tD@8-a{WSaw?>4(g=boc+mJc}f!!M0w(Gk6ilpS^gNqjAP3T#9?R)Ys9#6q0zV^66u`YC|v+g(F&6g*l-~ZFy+Y2PK2v4t`dqDCu`*eNjYo&55kB z$Jo{;$rdO4JuWHkdlIhGUG_#wi=3B=3k0!|J1_G^QUj9U_x9IuXCBe@+GiL%x~gJ4 z>ioU6Q+80_+{^FTc~`E~4>F6%kzBkyYYC^Ktd7(2A;UA0@~3mhlG&MLux^r??^hm` zrnvGVLC+rWr{n7xENn?mbUjC^CowsvhMCc!8572FLK>|t`kPy@9RRkoO2_QTAU)W+wGzmc2` zXXOF?fCP}W_p(hPVSU@wQy)@08x6N5Pe32F$6i^FFIb#iaobgZv?1C7nwiNTY7;u> zu2iPnyoxba>c=n}9|#jd`0dLu@_n-{9E{p5aBI#toblOuVECS3)EhhMk=~&pTZ7Fl zDLY!^+9uI`F<*O#Awav>s4p*ST-wau$~c&N=apZ$zK2U5EIgHz$;YJG{M^SO7N$*V z@yZ*Yb5V6izGp_8Of{5WQ9sa+8t=~L9*lMBOQMGcOzP>}vQwU7AE~>Da;5n+Bis<% zS)SNW@*capjmR-IjQ!_wF!CZX%Z1tZOgATWKV66MB8RMQ|8wn~8KGz!rG!X4^(%q% z2-;VM2C;a>9a*`XAfO5H9;Pw<^728GRxmf5^RuRY%nxBI9-dO@$9x&{b!4k>%R=I15?}rE#qw^Gz9+dUm(`mXMPXa9A=9Gl z&QI_`$NwehV6n*&J-kRpEe0N;;BAvi1V;qhd-xsyf4}TRaz%rQu`xYVveGBo*m&9p zgNUv?fjglN$-U0o?D=b7OBp?MM-82sx=C_TO3UNjwnwEsDXTT9JW&&qHtV1E9eTS^ z>6OR@6E#vU=2oe8gJGwjvq@E14-`1Z*{kSL^vyw2h8blWm059Y>*y{gff~&uxim=F zcR?^!lNZocjnuSjU1C}VZ8S;kd{5rDq?w%I2u5PwXIQS=_Xm2AX>#sgziOV?9skc2 z0^-i1jn>@0LCSkhjk#N4tl6#&J>VLgkfS9ze{eJml@n~$UM2;-cs!JY@5y>mk}*QH z*RtrszokV@e)S2|^qppmmiORxo6k!tl;Or9s__)QM55Ut*|JCG=cifND$7Lw;)4;4faMpDM-4=oK` z1&bGF=N!xDEo_!fp^B*x*GMjRr3fDDeGZA;;s0K_o{GE!tQ#+9?I$#&ZfE-P3cACc z(6Env7@pBm)$=f$0bm#eDra;d$L+?dUkQJ$Tz*~u?-PZ}WLwk7*D4bUiO%~@EhFge zde!JyN@qFr#KD7lrFOKu$P>NYe4+NH?4#M?*UP<><@E_AeU^#c!Mn_;#Qt5|S@`@1 zzB?_8N|<;j+k$UtB9dOV*;%C(?}vEnke*D?0BhNmx*2-Ae(#C!ARGtS&Hrm>e>ZjV z^(#Geu#$XuD0D~eVZS>NOjx=c>YW|@<9NxF4%ptHSUa)b4KqRm@>AS%in>+(-4`&S zhyHqDN8J8Otha?BT`tS{2osEP}NBoo}{g{wAj3aK0mu~m_k-WnO%PL3qyZilUV zm)!3Ak}^$eJ6D#AwB@)S8vH|0RSiB1Od(4yHL-Q2 ztJuM>TkmByk(w_Ui6Qt2D@BU>PyOBS3IW3li&p5w`g$tAKFkP}XAzmZ3tKzaHU!g6 zqCePa7E}}Yuean*(P`1bLI+_AKxS$kaY&Igay3n47%HlZk6__X^75!hLu#dJ53S@r?O1Wam1XA zAo>(M6q`XHXLIiS&`7_V-zADZ(zs3+eJLf75t@W4=j}>$;xKn)@Db7~FikP@Bv*N+ z8NSlS!YoZCdxh^M>MQ+o{}Y1KnyjMFwkv#*yw`G;2})X#izcw8v_;{q;JrO5T4d^6 z|7EAz!6ZAgtN#=ymowoEDhZcI-(g{kpEVWK&vEE0Xq;%LK~iI3Yss2}u}IW=D@{_t z;LIJimab%nH35E#B8>apFjw**)oy4+X<=_CFOc%VS=%qK-ur882yW_GOl1Im;?l*i zY@W9r(G+R1%ff?b_mSg!avE73axuB;8gKML)g+!$cTxe}MWH4^gp>cmt$;@048HN5 zOL7YwQQ=3v$xd05B-gxGLsP2Jn0W`I97@$zVLYJzs=66zICOzAPOtg`~HA2qF& zNNt;(D1Uoi*D5^vVZpS8TQE0>-=6XyW14j53S2PzC$D2+n)Ek@SJRAwi_l(~3y4Cl z>)ow}^G|vWV{V1L=M&7XVS<(q8j@Q!1^Hr9cOLo$17Bb7tU{h|ev3vTNNv1P>jiah zKNL`h#Gkd6*St5U_`%5wk%sPB-t?**>3;V;ZL}V>V(;MWbs60hjD%Yg$C_Hz1>{H| z{r~IFSh_GguNMa*UXw)ct-Xck0x-yC=QeT^G?(@e2Yxpl;si)&e)sW@9gY6EOgl3W!AnXLV8lr(_>A*b6KFY!TzJL>k=upyRQ7fv0j(h z{)#?hq1f2&d-Y38b4+d6%wk8>m`VlighkIO2rB> z@grwu?DJy7?o3@M&&njPr%E90$~-+1j5`_(d#w_17A z#zfh{@)G!q{-+ibuH-YaZbJ6{os+eWy4fbU?AZz*S67!~xCD2S3(x+KHzr0AeI?B^ z8W2ax&nq$|JXrbo*feXq*m0qvyR$^22Qx#qIN%m~^|-JD04EX+rE8N|~S& zicx7i4`hS#wqF?|_9d~mR%i_LKN^GPovUY?+aTz)udGkU_Ewr#p{1!|5(3%2YjVN& z7#Auk_%SvQwwtp>h^hL|fCjA+OO)h|g$;IisSLWC^xtzA!wP?haEKAkv{ODf=<4pV z=I&G&+sZ0-|67zdv%AXV7pj9qMFmd-5%0A%VOiiV#(R@oI-T>&x4X37 z=yaIaveAoqhM=V0ny-5xL0urbaGT7n?MBYq z=3c>tdJM@VcN*Z5lZuGMGs%r|5jHXyAL9441!JL)>%leatC*>?Wrqkr8ug=OA8Sb+ zCOWQ^4sf~6w9u)2!tJLTLTf@29^tJ}6N3aTZ;|X%7n9as>G7HM5YjbM9oFOPzC@pI zY$_3+vbKq+Q%(j^fth~3o#mw&qXb`4L7WcR9y$5c#dqP2EIJq5&{s(;+j!6OpsT8* zf@D8n)*0)*8oMz`m=c={z}VST77bz^7#P~A5P0)@mPe-2g!rWs7^7wAaG^bc7Pxcj z+dilU$uqRQshBh9+{{9|N&frcrd-WeyWEY7rnBnemIn>C3+|q3cXwm~dOjO0DV`bVeR*Yw`8~yw4mfqVKUrL{z#1e;B60|;t z8tOJ)_Dn^Mm>6>ezx%ZM>;4dwV=qfQ!Ra+qriD`j@+L{E>anW)ZQ?{UzQ(mS%*p&K z9_?dc9263;Uhm^RU|s&SMhyAgD(a@9H@Vj1FfMk|!fkGZjOwpw351qtKqsN|p`|1) zcGI+o32mYS!a8+%q$#??k(K?5E0vav`41rigO>tf5fKzJr!`GT~DtfmRBvOqB7Go8On}Ugg zlb)IaJRvt|1(4wmmfLHSrZpZ20K5#RiZDnJ<67+)ptwaQ8ajuz$ZBqn$$N68-WJFW z7O&tG(=BOfGSMMgK#p=w8-|1@9A8uZQOo&MZWa~VYv$nD@-W# z%WQ16gU~@!;nsbhPgHbxCdJ!l)WvlV2we`h$49OnD)ZgQx%HEich>-dT758L>&%&n zZd^jm{PICf=Z$*=3rF`gCOI*jOXus_Bs@);JE3>5yNy@8ChT<)EiPO!0->nc5Qkhx zV~&wWN9ro*<2>Ug3ACL(4b6C~vGFC1!G=lJX|<4Ib9ZC0l=9n5HbI+PcQIA)q(U9gN1X^=Z@a{v5A)EFXh>c{M20JQSE-@wWz zeCAVtGMW5DR0FaUBShEHF6bgzB^D-=s>}pcC|cn4P{P7C4;6b@^q4|Y;>K%aFstwp7gyyef|K9C9th)&&>>2Sx~ z>?LlC$?Vy1tdA5flvlMYPy?3?-Eyq5C%x=dbue|N?N22$K`pW(##uwN>)fd0woaVb zPBXUYO*NTy1}SCGn$90TaZbf^61}aA=BAf0c&G1HzG-LQ>TDsG_Hu2;Ok2VAADLO z1G-sIf;8YfN8EXQI*XQy>eP<+hH8!6Zrv0M2=vmWAN#rl`bq;pXK^XpS6cb~57g{m zzFz)qlGf(W$KNQC4nY0?!zWCF?-RXF@jxH?05ERAhfMt8YWksm`@f?VzG>?huymKY zyBVPFLiu%;jd_;9H=D%^yNY$Lby+qF=Eu5MPgz9Om0+k%X!gIt@QQX1^wG^=@i{0eMcOk62C}^ksFHOWtfI-DR^W;MCG@v?AEY_J^&ZDeY2A0 zU5H}9)=oqzM@oNyJ4x@SiU**qroAb}rEAPGsSGzA^w^x79Dj9vMAD@1Pm5(<}Cifj2(NgOS?|>3{fTlu59SlL49zU$Qq=$v^xxAl9;zgRhbQVMg zvk{Ru(Co4HACvItm5JE(`E;vHw)M#*1v|3G42-HR#C38Bvy6oRrHBo@e0{e>ai-vF!|P&rM`9Y zv+Pal@*0yyT4@<++)q@Gni=_!m=~Mt#n38v+O|6gHB_7iurMP&Z85Bzg{UD!e&lwk zYM7s$nb#~v``&dsWEwqlPsbgP{!QB~l#!eIKF07$8N2es5xRyh8{s95!nQ)bvXzx# z`#beYWcPz754^W}F$Y&EM~;chtVjq^QLzhXK{ip-D+Ak=51X_ij3I@-oOUWCdU}O+ z+-yq$KuFgbqt&YE87T>tkUN;=vfjEW+g=}!?0j8aY}bx+vd*mc1^DC5s$S&}thbSi z1LBA4LLA0pc|l3ke*R8vq4NkFEfb`E^F&NqmCaYdTSnd&UkFGO@*cwYERi``?f4WT1gUlpaaWOV6(jmVtEdU8YKEnpElsz zj4r-EQdUv|&`_CBVuLSF==;lQ8fT&xOe#vGL(_}aCat@<3x9bC0zfs#B*Xqo?hf~h z)gcU1Hq^m^n3lJt5mMfSBx1G|d&mbWt8^v?>0rAL;R^4{x6WomyJtj*Ur5$(^d748 z#SGj@>8qJ>@*}<`Yy{TvbTU}6M^JYz7~xPoMb&sZsz)-xC{FYvmMfW^U|P3MM^ykk zH)WoOCpdVGtc1cVqC!HLy6xF_9YFc}YR0_7C2ivOQzi?n` zl1(;+o(C7shrAUn+W#`Clw<$SRP0)WImLBf1ogHUW<>RN88@`yt-i0#s-%x9Pj(`5 zwsV27#>$AoRT72vxiSaDX1m8rbxAELe?1Z@`-rmY9B<7V^t`}Cl zmn}()Zx;rUIwp1fo6nXVYAHJuv`q6uejCQ>uo0?Lg<2$fFC#&3kt}!Pkx0#nB^e?f zU2d;8(8_~6Ay%xoVUSNXQO=T;Di(9H|GSVDBtUF<#0FQ4ZZb?e7;t^N%U{^y%w~Yx z#(ESH=@WXmLD#IdXmQ5UWx#2Zyg+$;hb}~W%33ASO}f#^D=im<=Z`$~Kfn=E1e!_ZzMs<&e(7oGS%q_q9QRJTInK|RmYYe)H{9~+CKFoTh}nJeF?6r9Vqlk-(5MGT-052v z5z{CFrv6x|_3)#xm^)}hQWGQr%O&5^uFxA`+ku2&MC07#{ZI@|tH(nz4# zfTC-XQCDNDl+QH@sKG6bFKq|NE?yk z4<}M|jEm|~&~LW;34YkhdFv;tSGNJG@f*gnD<1O~+xz3E0LN*F0MN<-3V`tI8U@3B zOM#liWw`-n`^AHMoou=@pqVrPH+z$nmQiU(jO9n3wX2>wY$m0<}czT$!%p178qu|9DCv4^mt#7zJDf${gsSz+g9o z;n4uv0sU(@v9J()kTVznnE&6N-?%m1n71qkCrEWF4cfs{bN=Dg0ZKE0zeGFTuVIv>*v&P&EF@z%hCWv1mXRC zq(|HUTi=;K-CQz7fi}N!dsy~v;u^845xH5jeeb&IT4cmLfg>T1 zy#75Bnm6maP3{il@_FSAI-XiwcNnPn8sYB3Ia9Z0*m!D8Xh&KWZ=b)-7w@4d<;V`Ytl5O3;TJbyXY6C7dxNf3A&Rd~fhd za=|2gr{Weiw0D+Kx&>DSnJCEO+8S@&K%>UJRH9{M7AH`NPp8aTCg3R4{r3yPAZW)( zG@9=0TGLquXmdSFof1wO43&aEV<7X}e@pmASY$2e{&+iei1Z0;s}&5AAiA@yO7zeO zz*y)3NRsN#=AXj064WW5Qocly-kYRF@tsd8Ujkdn-)&7=9PKa8vuqsr3IM|f04NqD zXpvmVYRl7^?)hTPHqfXYF*zS6fE=iZt6ZAaU+yS(z;`N?)(?0r>nzX2jThojaK1jw z0)S5&h~@^8E5w)Q7`Tb2E~}Vu2cw6GtSr5#RO6kil~9a8xA7u1(Ry)X zCjs1CupP&`)&?^<)X~^^+g!sa=8O0FVIO1v?8a@ejGYttl^{dXqCc{989jR||J8sX z>r>^lBu)}RfqVNi%!Egz5oU5*8z+KLLbJB=veYh=B$_ZPx6g*%Q{~r)$*aUqnETQs zR8@aCGAV&-FDu8k<~nOLJX16cD*3jiv$LY#H9}Ao72eJCg3r~8rD~B&PMi@z+kGqIOAlcvCDFQC|Y*AFzmVoD20=}xUQ+}&LjlA*lOnkw~Ae{$z|{-;)#R_V*c}5r&Y1W2xRUY$BB5l&aBZ3$jq>vG{3 ziy;p$@)i(@HIE1E*?5Oc<6{hjGGFBddMHV91th*rq1rc&Zy1kFA!lbzc4X?M0zYz| z?W;?^KCc5`uUIj0aB4)}lBKnNjg-LKPzC2Z8hVS=BpK^4&=(URXV(|yEJ>id1hXrJ zPa@-bY>1?4;cp?RaX44AbmykLh6aLTYb$Lqfny_?L%XfRJ zGsJEtaqJ777Tu1b)tP6;!W?05>@SmpQ9bpRIpMraR;5%QV4odrmyjDAD$QYoFzM^#u0BlQ) zD($7Tb?0}6P(*}sBaZ?GgS1$R|M{9{r|w<{2?0qJ&*JQFAHu$lO$$kyG(CMJ(=@7*=2y{Wa`=VCbLNt^562Ua)Ao@1@)~XKC zD;#2(;F@U*07(}}@IsqR%zmuqWv#hIWZckfk&&9n#flTwX;bOB$B9$lAOEKAYUrRT zYUqMiOt)QxRfUPPhK8W~-5?UP+Ex(iTGGas2=B_fJdLX9F5?jIEA#QZ$Vopu3hLuU zrim}f;9Ek*J=h#s%SuSfQ4e;>N*I##_~nNXaAw0Nk2(mZ$MsKI1=Sq4YHVd&%2fz0 z(>MK9f(g3D6oex5dgP^e)n>YaQUSLZp=*UL`dbK5ZAg2#zR!tT8_(d4*|!_z6Pt0b zv>?Rq1WULQx-Tm!p#8v(MUS>c!IjQ`E{JQx3374bZ9`Cq7biolAZt-fbj=EBeojg3 zhGLc{h1=bNQPfZ=j>vFQ6HI=|xs}(QOoI;G3TxOb0B{Y(OZggugd>z1a=~9kFo>Oz zwt9cQSFJKi0{O=JhmZ9yE1~iK-O#LkbJ+G?{=~H@ULj$@0<1AAp8?9{vueKlhaGIx zHWL4<)s)!|+)w3=s*H`I`7fQLGgi zudgGCL7!8?NpY+I+dQ(7X$ktK?kvTz+vmUNZq0di=WowCkRLuOYDimT_Yks5e*20<)coH_gGB9(Xsu#ZG3CoAaBTz0Ee533Z|6;dnuWk=Fr0g{o1(M z*GN2^qLAb@w)3I4rn{DRg&>$jrHwT`^ec3Gv2j|~Ef#ZRveSnc*Uh!r?Ad*o%j>x} zWqFh+G}z3@=!C*vItP zbM+$=)lkX!_UVTM?>$dE2$l@B3z2%?b~;6nckN_zX4VZezyAkzsWW8& literal 0 HcmV?d00001 From 4ed1166439faaed5bb21cabe764c63860b5d64b4 Mon Sep 17 00:00:00 2001 From: Changli Tang <84725343+TCL606@users.noreply.github.com> Date: Thu, 27 Apr 2023 19:53:38 +0800 Subject: [PATCH 069/105] Update run.sh --- dependency/shell/run.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dependency/shell/run.sh b/dependency/shell/run.sh index 80c60d6..6a30e94 100644 --- a/dependency/shell/run.sh +++ b/dependency/shell/run.sh @@ -4,10 +4,10 @@ python_dir=/usr/local/PlayerCode/CAPI/python/PyAPI playback_dir=/usr/local/playback if [ $EXPOSED -eq 1 ]; then - nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --resultFileName $playback_dir/result --gameTimeInSecond $TIME --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & + nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --resultFileName $playback_dir/result --gameTimeInSecond $TIME --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log 2>&1 & server_pid=$! else - nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --resultFileName $playback_dir/result --gameTimeInSecond $TIME --notAllowSpectator --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log & + nice -10 ./Server --port 8888 --studentCount 4 --trickerCount 1 --resultFileName $playback_dir/result --gameTimeInSecond $TIME --notAllowSpectator --url $URL --token $TOKEN --fileName $playback_dir/video --startLockFile $playback_dir/start.lock > $playback_dir/server.log 2>&1 & server_pid=$! fi sleep 5 @@ -20,9 +20,9 @@ do j=$((i - 1)) if [ -f "./player$i.py" ]; then cp -f ./player$i.py $python_dir/AI.py - nice -0 python3 $python_dir/main.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & + nice -0 python3 $python_dir/main.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log 2>&1 & elif [ -f "./capi$i" ]; then - nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & + nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log 2>&1 & else echo "ERROR. $i is not found." fi @@ -33,9 +33,9 @@ do j=$((i - 1)) if [ -f "./player$i.py" ]; then cp -f ./player$i.py $python_dir/AI.py - nice -0 python3 $python_dir/main.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & + nice -0 python3 $python_dir/main.py -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log 2>&1 & elif [ -f "./capi$i" ]; then - nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log & + nice -0 ./capi$i -I 127.0.0.1 -P 8888 -p $j > $playback_dir/team$k-player$j.log 2>&1 & else echo "ERROR. $i is not found." fi From 098db1e234370475525c5d7e791952e83aba97ae Mon Sep 17 00:00:00 2001 From: DragonAura Date: Thu, 27 Apr 2023 19:57:09 +0800 Subject: [PATCH 070/105] fix(CAPI): :bug: fix missing undef --- CAPI/cpp/proto/Services.grpc.pb.h | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 CAPI/cpp/proto/Services.grpc.pb.h diff --git a/CAPI/cpp/proto/Services.grpc.pb.h b/CAPI/cpp/proto/Services.grpc.pb.h old mode 100644 new mode 100755 index 7cf6d74..e99d5cc --- a/CAPI/cpp/proto/Services.grpc.pb.h +++ b/CAPI/cpp/proto/Services.grpc.pb.h @@ -25,6 +25,8 @@ #include #include +#undef SendMessage + namespace protobuf { From 9e5f599bd662f1f7117fbf12e22d050b723891e3 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Thu, 27 Apr 2023 20:04:45 +0800 Subject: [PATCH 071/105] fix: :bug: fix the bug about return value when using skill --- docs/CAPI接口(cpp).md | 2 +- docs/CAPI接口(python).md | 2 +- docs/GameRules.md | 1 + docs/QandA.md | 2 +- logic/GameClass/GameObj/Map/Map.cs | 32 +++++++++++++++---- logic/Gaming/SkillManager/SkillManager.cs | 39 ++++++++--------------- logic/Server/RpcServices.cs | 1 - 7 files changed, 42 insertions(+), 37 deletions(-) diff --git a/docs/CAPI接口(cpp).md b/docs/CAPI接口(cpp).md index b427644..bc7dac5 100644 --- a/docs/CAPI接口(cpp).md +++ b/docs/CAPI接口(cpp).md @@ -59,7 +59,7 @@ 下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 - `THUAI6::PlaceType GetPlaceType(int32_t cellX, int32_t cellY)` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - - 以下指令,若查询物品当前在视野内,则返回最新进度;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 + - 以下指令,若查询物品当前在视野内,则返回最新进度/状态;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度/状态;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 - `int32_t GetChestProgress(int32_t cellX, int32_t cellY) const`:查询特定位置箱子开启进度 - `int32_t GetGateProgress(int32_t cellX, int32_t cellY) const`:查询特定位置校门开启进度 - `int32_t GetClassroomProgress(int32_t cellX, int32_t cellY) const`:查询特定位置教室作业完成进度 diff --git a/docs/CAPI接口(python).md b/docs/CAPI接口(python).md index 500da59..a2f53e4 100644 --- a/docs/CAPI接口(python).md +++ b/docs/CAPI接口(python).md @@ -72,7 +72,7 @@ 下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 - `def GetPlaceType(self, cellX: int, cellY: int) -> THUAI6.PlaceType` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - - 以下指令,若查询物品当前在视野内,则返回最新进度;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 + - 以下指令,若查询物品当前在视野内,则返回最新进度/状态;若物品当前不在视野内、但曾经出现在视野内,则返回最后一次看到时的进度/状态;若物品从未出现在视野内,或查询位置没有对应的物品,则返回 -1。 - `def GetChestProgress(self, cellX: int, cellY: int) -> int`:查询特定位置箱子开启进度 - `def GetGateProgress(self, cellX: int, cellY: int) -> int`:查询特定位置校门开启进度 - `def GetClassroomProgress(self, cellX: int, cellY: int) -> int`:查询特定位置教室作业完成进度 diff --git a/docs/GameRules.md b/docs/GameRules.md index c88870f..6bcc9c1 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -364,6 +364,7 @@ $$ ### 技能 - CD冷却计时是在开始使用技能的瞬间开始的 - Klee的小炸弹有碰撞体积 +- 除了切换攻击类型的技能,在不能执行指令的状态下(包括翻窗)均不能使用技能 ### 职业 - 学生职业可以重复选择 \ No newline at end of file diff --git a/docs/QandA.md b/docs/QandA.md index 6995cec..a190c91 100644 --- a/docs/QandA.md +++ b/docs/QandA.md @@ -80,4 +80,4 @@ A:初赛结束会调数值及机制,增加新角色 Q:初赛后会修改什么呢? -A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业;规范Debug信息;提供不同格式的信息传递;增加职业;优化游戏结束条件 \ No newline at end of file +A:技能冷却时间等属性设为不可见;出生点随机性或可选性;增强教师等职业,削弱职业;规范Debug信息;提供不同格式的信息传递;增加职业;优化游戏结束条件;角色毅力值清空不在使捣蛋鬼产生BGM \ No newline at end of file diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 427c76d..96b0f15 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -13,29 +13,47 @@ namespace GameClass.GameObj private readonly Dictionary birthPointList; // 出生点列表 public Dictionary BirthPointList => birthPointList; - private object lockForNum = new(); + private readonly object lockForNum = new(); private void WhenStudentNumChange() { if (numOfDeceasedStudent + numOfEscapedStudent == GameData.numOfStudent) { Timer.IsGaming = false; + return; } - if (GameData.numOfStudent - NumOfDeceasedStudent - NumOfEscapedStudent == 1) + if (GameData.numOfStudent - numOfDeceasedStudent - numOfEscapedStudent == 1) { - GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); + GameObjLockDict[GameObjType.Character].EnterReadLock(); try { - foreach (EmergencyExit emergencyExit in GameObjDict[GameObjType.EmergencyExit]) - if (emergencyExit.CanOpen) + foreach (Character player in GameObjDict[GameObjType.Character]) + if (player.PlayerState==PlayerStateType.Addicted) { - emergencyExit.IsOpen = true; + Timer.IsGaming = false; break; } } finally { - GameObjLockDict[GameObjType.EmergencyExit].ExitWriteLock(); + GameObjLockDict[GameObjType.Character].ExitReadLock(); + } + if (!Timer.IsGaming) + { + GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); + try + { + foreach (EmergencyExit emergencyExit in GameObjDict[GameObjType.EmergencyExit]) + if (emergencyExit.CanOpen) + { + emergencyExit.IsOpen = true; + break; + } + } + finally + { + GameObjLockDict[GameObjType.EmergencyExit].ExitWriteLock(); + } } } } diff --git a/logic/Gaming/SkillManager/SkillManager.cs b/logic/Gaming/SkillManager/SkillManager.cs index 9cf6f09..59fc7e3 100644 --- a/logic/Gaming/SkillManager/SkillManager.cs +++ b/logic/Gaming/SkillManager/SkillManager.cs @@ -17,44 +17,31 @@ namespace Gaming switch (activeSkillType) { case ActiveSkillType.BecomeInvisible: - BecomeInvisible(character); - break; + return BecomeInvisible(character); case ActiveSkillType.UseKnife: - UseKnife(character); - break; + return UseKnife(character); case ActiveSkillType.Howl: - Howl(character); - break; + return Howl(character); case ActiveSkillType.CanBeginToCharge: - CanBeginToCharge(character); - break; + return CanBeginToCharge(character); case ActiveSkillType.Inspire: - Inspire(character); - break; + return Inspire(character); case ActiveSkillType.Encourage: - Encourage(character); - break; + return Encourage(character); case ActiveSkillType.Punish: - Punish(character); - break; + return Punish(character); case ActiveSkillType.JumpyBomb: - JumpyBomb(character); - break; + return JumpyBomb(character); case ActiveSkillType.WriteAnswers: - WriteAnswers(character); - break; + return WriteAnswers(character); case ActiveSkillType.SummonGolem: - SummonGolem(character); - break; + return SummonGolem(character); case ActiveSkillType.UseRobot: - UseRobot(character); - break; + return UseRobot(character); case ActiveSkillType.Rouse: - Rouse(character); - break; + return Rouse(character); case ActiveSkillType.ShowTime: - ShowTime(character); - break; + return ShowTime(character); default: return false; } diff --git a/logic/Server/RpcServices.cs b/logic/Server/RpcServices.cs index cac7984..f8f3fe4 100644 --- a/logic/Server/RpcServices.cs +++ b/logic/Server/RpcServices.cs @@ -1,7 +1,6 @@ using Grpc.Core; using Protobuf; using System.Threading; -using Timothy.FrameRateTask; using System; using System.Net.Http.Headers; using Gaming; From 13ee3dab31c906b3d4c03305b170f838a7cea6d0 Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Thu, 27 Apr 2023 21:52:32 +0800 Subject: [PATCH 072/105] style: :art: fix the problem --- docs/GameRules.md | 3 ++- logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs | 1 - logic/GameClass/GameObj/Map/Map.cs | 5 ++--- logic/GameEngine/CollisionChecker.cs | 1 - logic/Gaming/AttackManager.cs | 1 - 5 files changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/GameRules.md b/docs/GameRules.md index 6bcc9c1..80cb1f1 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -64,7 +64,7 @@ CellX=\frac{x}{1000},CellY=\frac{y}{1000} $$ - 格子有对应区域类型:陆地、墙、草地、教室、校门、隐藏校门、门、窗、箱子 -- 隐藏校门刷新点的区域类型始终为隐藏校门 +- 任何格子的区域类型(PlaceType)始终不变,所有隐藏校门刷新点的区域类型均为隐藏校门 ### 人物 - 人物直径为800 @@ -360,6 +360,7 @@ $$ ### 信息相关 - Bgm在没有符合条件的情况下,值为0。 + - 不能给自己发信息 ### 技能 - CD冷却计时是在开始使用技能的瞬间开始的 diff --git a/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs b/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs index 672e40f..2b3df5c 100644 --- a/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs +++ b/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs @@ -1,6 +1,5 @@ using Preparation.Interface; using Preparation.Utility; -using System; namespace GameClass.GameObj { diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 96b0f15..953ddb3 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -3,7 +3,6 @@ using System.Threading; using Preparation.Interface; using Preparation.Utility; using System; -using GameClass.GameObj; namespace GameClass.GameObj { @@ -28,7 +27,7 @@ namespace GameClass.GameObj try { foreach (Character player in GameObjDict[GameObjType.Character]) - if (player.PlayerState==PlayerStateType.Addicted) + if (player.PlayerState == PlayerStateType.Addicted) { Timer.IsGaming = false; break; @@ -38,7 +37,7 @@ namespace GameClass.GameObj { GameObjLockDict[GameObjType.Character].ExitReadLock(); } - if (!Timer.IsGaming) + if (Timer.IsGaming) { GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); try diff --git a/logic/GameEngine/CollisionChecker.cs b/logic/GameEngine/CollisionChecker.cs index 046d5bc..1a7a2e3 100644 --- a/logic/GameEngine/CollisionChecker.cs +++ b/logic/GameEngine/CollisionChecker.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Numerics; using System.Threading; using Preparation.Interface; using Preparation.Utility; diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index e86e429..0db4748 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -6,7 +6,6 @@ using Preparation.Utility; using GameEngine; using Preparation.Interface; using Timothy.FrameRateTask; -using System.Numerics; namespace Gaming { From 4ecaefd567879455a5274367008652876040b5fa Mon Sep 17 00:00:00 2001 From: Shawqeem <1004837646@qq.com> Date: Thu, 27 Apr 2023 22:14:19 +0800 Subject: [PATCH 073/105] fix: :bug: fix the bug that map is not refreshed at the start and that map is always flickering fix the bug that map is not refreshed at the start and that map is always flickering --- logic/Client/MainWindow.xaml | 3 +- logic/Client/MainWindow.xaml.cs | 118 +++++++++++++------------------- logic/cmd/PlaybackServer.cmd | 6 +- 3 files changed, 51 insertions(+), 76 deletions(-) diff --git a/logic/Client/MainWindow.xaml b/logic/Client/MainWindow.xaml index beacab5..e1326a7 100644 --- a/logic/Client/MainWindow.xaml +++ b/logic/Client/MainWindow.xaml @@ -5,7 +5,8 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Client" mc:Ignorable="d" - Title="ClientVI" Height="738" Width="850" KeyDown="KeyBoardControl" Background="White" ResizeMode="CanResizeWithGrip" WindowStyle="None" MouseLeftButtonDown="DragWindow" MouseDoubleClick="Attack" MinHeight="738" MinWidth="1100"> + Title="ClientVI" Height="738" Width="850" KeyDown="KeyBoardControl" Background="White" ResizeMode="CanResizeWithGrip" WindowStyle="None" MouseLeftButtonDown="DragWindow" MouseDoubleClick="Attack" MinHeight="738" MinWidth="1100" + SizeChanged="ZoomMap"> diff --git a/logic/Client/MainWindow.xaml.cs b/logic/Client/MainWindow.xaml.cs index 4ab6665..340fbd4 100644 --- a/logic/Client/MainWindow.xaml.cs +++ b/logic/Client/MainWindow.xaml.cs @@ -34,8 +34,6 @@ namespace Client { public MainWindow() { - unitHeight = unitWidth = unit = 13; - bonusflag = true; timer = new DispatcherTimer { Interval = new TimeSpan(50000) // 每50ms刷新一次 @@ -60,6 +58,10 @@ namespace Client listOfGate = new List(); listOfHiddenGate = new List(); WindowStartupLocation = WindowStartupLocation.CenterScreen; + unit = Math.Sqrt(UpperLayerOfMap.ActualHeight * UpperLayerOfMap.ActualWidth) / 50; + unitFontsize = unit / 13; + unitHeight = UpperLayerOfMap.ActualHeight / 50; + unitWidth = UpperLayerOfMap.ActualWidth / 50; ReactToCommandline(); } @@ -194,6 +196,7 @@ namespace Client 0 => PlayerType.NullPlayerType, 1 => PlayerType.StudentPlayer, 2 => PlayerType.TrickerPlayer, + _ => PlayerType.NullPlayerType }; playerMsg.PlayerType = playerType; if (Convert.ToInt64(comInfo[3]) == 1) @@ -268,9 +271,9 @@ namespace Client { TextBox icon = new() { - FontSize = 10, - Width = 20, - Height = 20, + FontSize = 7 * unitFontsize, + Width = unitWidth, + Height = unitHeight, Text = text, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, @@ -282,37 +285,23 @@ namespace Client UpperLayerOfMap.Children.Add(icon); } - private void ZoomMap() - { - for (int i = 0; i < 50; i++) - { - for (int j = 0; j < 50; j++) - { - if (mapPatches[i, j] != null && (mapPatches[i, j].Width != UpperLayerOfMap.ActualWidth / 50 || mapPatches[i, j].Height != UpperLayerOfMap.ActualHeight / 50)) - { - mapPatches[i, j].Width = UpperLayerOfMap.ActualWidth / 50; - mapPatches[i, j].Height = UpperLayerOfMap.ActualHeight / 50; - mapPatches[i, j].HorizontalAlignment = HorizontalAlignment.Left; - mapPatches[i, j].VerticalAlignment = VerticalAlignment.Top; - mapPatches[i, j].Margin = new Thickness(UpperLayerOfMap.ActualWidth / 50 * j, UpperLayerOfMap.ActualHeight / 50 * i, 0, 0); - } - } - } - } - - private void ZoomMapAtFirst() + private void ZoomMap(object sender, SizeChangedEventArgs e) { + unit = Math.Sqrt(UpperLayerOfMap.ActualHeight * UpperLayerOfMap.ActualWidth) / 50; + unitFontsize = unit / 13; + unitHeight = UpperLayerOfMap.ActualHeight / 50; + unitWidth = UpperLayerOfMap.ActualWidth / 50; for (int i = 0; i < 50; i++) { for (int j = 0; j < 50; j++) { if (mapPatches[i, j] != null) { - mapPatches[i, j].Width = UpperLayerOfMap.ActualWidth / 50; - mapPatches[i, j].Height = UpperLayerOfMap.ActualHeight / 50; + mapPatches[i, j].Width = unitWidth; + mapPatches[i, j].Height = unitHeight; mapPatches[i, j].HorizontalAlignment = HorizontalAlignment.Left; mapPatches[i, j].VerticalAlignment = VerticalAlignment.Top; - mapPatches[i, j].Margin = new Thickness(UpperLayerOfMap.ActualWidth / 50 * j, UpperLayerOfMap.ActualHeight / 50 * i, 0, 0); + mapPatches[i, j].Margin = new Thickness(unitWidth * j, unitHeight * i, 0, 0); } } } @@ -330,7 +319,7 @@ namespace Client Height = unitHeight, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, - Margin = new Thickness(Width * (j), Height * (i), 0, 0) + Margin = new Thickness(unitWidth * j, unitHeight * i, 0, 0)//unitWidth cannot be replaced by Width }; switch (defaultMap[i, j]) { @@ -697,7 +686,7 @@ namespace Client MaxButton.Content = "🗖"; foreach (var obj in listOfHuman) { - if (obj.PlayerId < GameData.numOfStudent && obj.StudentType != StudentType.Robot) + if (!isDataFixed[obj.PlayerId] && obj.PlayerId < GameData.numOfStudent && obj.StudentType != StudentType.Robot) { IStudentType occupation = (IStudentType)OccupationFactory.FindIOccupation(Transformation.ToStudentType(obj.StudentType)); totalLife[obj.PlayerId] = occupation.MaxHp; @@ -709,60 +698,52 @@ namespace Client coolTime[i, obj.PlayerId] = iActiveSkill.SkillCD; ++i; } + isDataFixed[obj.PlayerId] = true; } } foreach (var obj in listOfButcher) { - IGhostType occupation1 = (IGhostType)OccupationFactory.FindIOccupation(Transformation.ToTrickerType(obj.TrickerType)); - int j = 0; - foreach (var skill in occupation1.ListOfIActiveSkill) + if (!isDataFixed[obj.PlayerId]) { - var iActiveSkill = SkillFactory.FindIActiveSkill(skill); - coolTime[j, GameData.numOfStudent] = iActiveSkill.SkillCD; - ++j; + IGhostType occupation1 = (IGhostType)OccupationFactory.FindIOccupation(Transformation.ToTrickerType(obj.TrickerType)); + int j = 0; + foreach (var skill in occupation1.ListOfIActiveSkill) + { + var iActiveSkill = SkillFactory.FindIActiveSkill(skill); + coolTime[j, GameData.numOfStudent] = iActiveSkill.SkillCD; + ++j; + } + isDataFixed[obj.PlayerId] = true; } } if (StatusBarsOfSurvivor != null) { for (int i = 0; i < GameData.numOfStudent; i++) { - StatusBarsOfSurvivor[i].SetFontSize(12 * UpperLayerOfMap.ActualHeight / 650); StatusBarsOfSurvivor[i].NewData(totalLife, totalDeath, coolTime); } } if (StatusBarsOfHunter != null) { - StatusBarsOfHunter.SetFontSize(12 * UpperLayerOfMap.ActualHeight / 650); StatusBarsOfHunter.NewData(totalLife, totalDeath, coolTime); } - if (StatusBarsOfCircumstance != null) - StatusBarsOfCircumstance.SetFontSize(12 * UpperLayerOfMap.ActualHeight / 650); // 完成窗口信息更新 + if (StatusBarsOfSurvivor != null) + { + for (int i = 0; i < GameData.numOfStudent; i++) + { + StatusBarsOfSurvivor[i].SetFontSize(12 * unitFontsize); + } + } + if (StatusBarsOfHunter != null) + StatusBarsOfHunter.SetFontSize(12 * unitFontsize); + if (StatusBarsOfCircumstance != null) + StatusBarsOfCircumstance.SetFontSize(12 * unitFontsize); if (!isClientStocked) { - unit = Math.Sqrt(UpperLayerOfMap.ActualHeight * UpperLayerOfMap.ActualWidth) / 50; - unitHeight = UpperLayerOfMap.ActualHeight / 50; - unitWidth = UpperLayerOfMap.ActualWidth / 50; try { - // if (log != null) - //{ - // string temp = ""; - // for (int i = 0; i < dataDict[GameObjType.Character].Count; i++) - // { - // temp += Convert.ToString(dataDict[GameObjType.Character][i].MessageOfCharacter.TeamID) + "\n"; - // } - // log.Content = temp; - // } UpperLayerOfMap.Children.Clear(); - // if ((communicator == null || !communicator.Client.IsConnected) && !isPlaybackMode) - //{ - // UnderLayerOfMap.Children.Clear(); - // throw new Exception("Client is unconnected."); - // } - // else - //{ - foreach (var data in listOfAll) { StatusBarsOfCircumstance.SetValue(data, gateOpened, isEmergencyDrawed, isEmergencyOpened, playerID, isPlaybackMode); @@ -770,7 +751,6 @@ namespace Client if (!hasDrawed && mapFlag) { DrawMap(); - ZoomMapAtFirst(); } foreach (var data in listOfHuman) { @@ -791,7 +771,7 @@ namespace Client icon.Fill = Brushes.Gray; TextBox num = new() { - FontSize = 7 * UpperLayerOfMap.ActualHeight / 650, + FontSize = 7 * unitFontsize, Width = 2 * radiusTimes * unitWidth, Height = 2 * radiusTimes * unitHeight, Text = Convert.ToString(data.PlayerId), @@ -943,7 +923,7 @@ namespace Client int deg = (int)(100.0 * data.Progress / Preparation.Utility.GameData.degreeOfFixedGenerator); TextBox icon = new() { - FontSize = 8 * UpperLayerOfMap.ActualHeight / 650, + FontSize = 8 * unitFontsize, Width = unitWidth, Height = unitHeight, Text = Convert.ToString(deg), @@ -965,7 +945,7 @@ namespace Client int deg = (int)(100.0 * data.Progress / Preparation.Utility.GameData.degreeOfOpenedChest); TextBox icon = new() { - FontSize = 8 * UpperLayerOfMap.ActualHeight / 650, + FontSize = 8 * unitFontsize, Width = unitWidth, Height = unitHeight, Text = Convert.ToString(deg), @@ -987,7 +967,7 @@ namespace Client int deg = (int)(100.0 * data.Progress / Preparation.Utility.GameData.degreeOfOpenedDoorway); TextBox icon = new() { - FontSize = 8 * UpperLayerOfMap.ActualHeight / 650, + FontSize = 8 * unitFontsize, Width = unitWidth, Height = unitHeight, Text = Convert.ToString(deg), @@ -1009,7 +989,7 @@ namespace Client { TextBox icon = new() { - FontSize = 9 * UpperLayerOfMap.ActualHeight / 650, + FontSize = 9 * unitFontsize, Width = unitWidth, Height = unitHeight, HorizontalAlignment = HorizontalAlignment.Left, @@ -1042,7 +1022,7 @@ namespace Client isEmergencyOpened = true; TextBox icon = new() { - FontSize = 9 * UpperLayerOfMap.ActualHeight / 650, + FontSize = 9 * unitFontsize, Width = unitWidth, Height = unitHeight, Text = Convert.ToString("🔓"), @@ -1056,8 +1036,6 @@ namespace Client UpperLayerOfMap.Children.Add(icon); } } - //} - ZoomMap(); } catch (Exception exc) { @@ -1440,7 +1418,6 @@ namespace Client private MessageOfTricker? butcher = null; private bool humanOrButcher;//true for human - private bool bonusflag; private bool mapFlag = false; private bool hasDrawed = false; public int[,] defaultMap = new int[,] { @@ -1502,7 +1479,8 @@ namespace Client bool isSpectatorMode = false; bool isEmergencyOpened = false; bool isEmergencyDrawed = false; - bool isDataFixed = false; + bool[] isDataFixed = new bool[5] { false, false, false, false, false }; + double unitFontsize = 10; const double radiusTimes = 1.0 * Preparation.Utility.GameData.characterRadius / Preparation.Utility.GameData.numOfPosGridPerCell; const double bulletRadiusTimes = 1.0 * GameData.bulletRadius / Preparation.Utility.GameData.numOfPosGridPerCell; private int[] totalLife = new int[4] { 100, 100, 100, 100 }, totalDeath = new int[4] { 100, 100, 100, 100 }; diff --git a/logic/cmd/PlaybackServer.cmd b/logic/cmd/PlaybackServer.cmd index c3dd0bb..916c9ea 100644 --- a/logic/cmd/PlaybackServer.cmd +++ b/logic/cmd/PlaybackServer.cmd @@ -1,6 +1,2 @@ @echo off -::start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName test --playback true - -ping -n 2 127.0.0.1 > NUL - -start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 2030 \ No newline at end of file +start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --port 8888 --fileName .\ladder1.thuaipb --playback --playbackSpeed 4.0 From 645373ae4d4cc174f67f03de81541675f2707770 Mon Sep 17 00:00:00 2001 From: gsy1519 <614054460@qq.com> Date: Thu, 27 Apr 2023 22:20:29 +0800 Subject: [PATCH 074/105] fix: :bug: spectator now can get mapMsg when isgaming --- logic/Server/PlaybackServer.cs | 72 ++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/logic/Server/PlaybackServer.cs b/logic/Server/PlaybackServer.cs index 1506b97..449c1ed 100644 --- a/logic/Server/PlaybackServer.cs +++ b/logic/Server/PlaybackServer.cs @@ -5,6 +5,7 @@ using System.Threading; using Timothy.FrameRateTask; using Gaming; using Grpc.Core; +using System.Collections.Concurrent; namespace Server { @@ -12,13 +13,31 @@ namespace Server { protected readonly ArgumentOptions options; private int[,] teamScore; - private Dictionary semaDict = new(); + private ConcurrentDictionary semaDict = new(); private object semaDictLock = new(); private MessageToClient? currentGameInfo = new(); + private MessageOfObj currentMapMsg = new(); private uint spectatorMinPlayerID = 2023; private List spectatorList = new List(); public int TeamCount => options.TeamCount; private MessageWriter? mwr = null; + private object spetatorJoinLock = new(); + protected object spectatorLock = new object(); + protected bool isSpectatorJoin = false; + protected bool IsSpectatorJoin + { + get + { + lock (spectatorLock) + return isSpectatorJoin; + } + + set + { + lock (spectatorLock) + isSpectatorJoin = value; + } + } private bool IsGaming { get; set; } private int[] finalScore; public int[] FinalScore @@ -38,18 +57,20 @@ namespace Server public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter responseStream, ServerCallContext context) { - if (request.PlayerId >= spectatorMinPlayerID) + if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) { // 观战模式 - uint tp = (uint)request.PlayerId; - if (!spectatorList.Contains(tp)) + lock (spetatorJoinLock) // 具体原因见另一个上锁的地方 { - spectatorList.Add(tp); - Console.WriteLine("A new spectator comes to watch this game."); - var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)); - lock (semaDictLock) + if (semaDict.TryAdd(request.PlayerId, (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)))) + { + Console.WriteLine("A new spectator comes to watch this game."); + IsSpectatorJoin = true; + } + else { - semaDict.Add(request.PlayerId, temp); + Console.WriteLine($"Duplicated Spectator ID {request.PlayerId}"); + return; } } do @@ -63,15 +84,32 @@ namespace Server //Console.WriteLine("Send!"); } } + catch (InvalidOperationException) + { + if (semaDict.TryRemove(request.PlayerId, out var semas)) + { + try + { + semas.Item1.Release(); + semas.Item2.Release(); + } + catch { } + Console.WriteLine($"The spectator {request.PlayerId} exited"); + } + } catch (Exception) { - //Console.WriteLine(ex); + // Console.WriteLine(ex); } finally { - semaDict[request.PlayerId].Item2.Release(); + try + { + semaDict[request.PlayerId].Item2.Release(); + } + catch { } } - } while (IsGaming == true); + } while (IsGaming); return; } } @@ -79,6 +117,16 @@ namespace Server public void ReportGame(MessageToClient? msg) { currentGameInfo = msg; + if (currentGameInfo != null && currentGameInfo.GameState == GameState.GameStart) + { + currentMapMsg = currentGameInfo.ObjMessage[0]; + } + + if (currentGameInfo != null && IsSpectatorJoin) + { + currentGameInfo.ObjMessage.Add(currentMapMsg); + IsSpectatorJoin = false; + } foreach (var kvp in semaDict) { From d5165044295aaf5fd1919f9eff665e48f16ee650 Mon Sep 17 00:00:00 2001 From: TCL <1620508360@qq.com> Date: Thu, 27 Apr 2023 23:19:29 +0800 Subject: [PATCH 075/105] chore: add lock even before starting --- logic/Server/Properties/launchSettings.json | 2 +- logic/Server/RpcServices.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/logic/Server/Properties/launchSettings.json b/logic/Server/Properties/launchSettings.json index 6d2873f..308724a 100644 --- a/logic/Server/Properties/launchSettings.json +++ b/logic/Server/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Server": { "commandName": "Project", - "commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --resultFileName result --gameTimeInSecond 1 --fileName video" + "commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --resultFileName result --gameTimeInSecond 551 --fileName video" } } } \ No newline at end of file diff --git a/logic/Server/RpcServices.cs b/logic/Server/RpcServices.cs index cac7984..1507269 100644 --- a/logic/Server/RpcServices.cs +++ b/logic/Server/RpcServices.cs @@ -136,7 +136,7 @@ namespace Server var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)); bool start = false; Console.WriteLine($"Id: {request.PlayerId} joins."); - // lock (semaDictLock) + lock (spetatorJoinLock) // 为了保证绝对安全,还是加上这个锁吧 { if (semaDict.TryAdd(request.PlayerId, temp)) { From 34638fd8a666550f51933241e6071213f335bee7 Mon Sep 17 00:00:00 2001 From: Timothy Liu Date: Fri, 28 Apr 2023 01:35:54 +0800 Subject: [PATCH 076/105] chore(icon): add enlarged icons --- resource/eesast_software_trans_enlarged.png | Bin 0 -> 115422 bytes .../eesast_software_trans_enlarged_256x256.png | Bin 0 -> 13456 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 resource/eesast_software_trans_enlarged.png create mode 100644 resource/eesast_software_trans_enlarged_256x256.png diff --git a/resource/eesast_software_trans_enlarged.png b/resource/eesast_software_trans_enlarged.png new file mode 100644 index 0000000000000000000000000000000000000000..088700cce6ab3663866889b3e8da450f2b91c88d GIT binary patch literal 115422 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%0D3o9KkM1cf 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 z

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