diff --git a/CAPI/CAPI接口.md b/CAPI/CAPI接口(cpp).md similarity index 90% rename from CAPI/CAPI接口.md rename to CAPI/CAPI接口(cpp).md index f9888d9..16ea50e 100644 --- a/CAPI/CAPI接口.md +++ b/CAPI/CAPI接口(cpp).md @@ -1,22 +1,6 @@ -- [CAPI接口](#capi接口) - - [接口解释](#接口解释) - - [主动指令](#主动指令) - - [移动](#移动) - - [使用技能](#使用技能) - - [人物](#人物) - - [攻击](#攻击) - - [学习与毕业](#学习与毕业) - - [勉励与唤醒](#勉励与唤醒) - - [地图互动](#地图互动) - - [道具](#道具) - - [信息获取](#信息获取) - - [队内信息](#队内信息) - - [查询可视范围内的信息](#查询可视范围内的信息) - - [查询特定位置物体的信息,下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。](#查询特定位置物体的信息下面的-cellx-和-celly-指的是地图格数而非绝对坐标) - - [其他](#其他) - - [辅助函数](#辅助函数) - - [接口一览](#接口一览) -# CAPI接口 +[toc] + +# CAPI接口(cpp) ## 接口解释 ### 主动指令 @@ -66,7 +50,10 @@ - `std::vector> GetProps() const` :返回所有可视道具的信息。 - `std::vector> GetBullets() const` :返回所有可视子弹(攻击)的信息。 -#### 查询特定位置物体的信息,下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 +#### 查询特定位置物体的信息 + +下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 + - `THUAI6::PlaceType GetPlaceType(int32_t cellX, int32_t cellY)` :返回某一位置场地种类信息。场地种类详见 structure.h 。 - `bool IsDoorOpen(int32_t cellX, int32_t cellY) const`:查询特定位置门是否开启 - `int32_t GetChestProgress(int32_t cellX, int32_t cellY) const`:查询特定位置箱子开启进度 @@ -88,7 +75,7 @@ `static inline int GridToCell(int grid) noexcept`:将绝对坐标 grid 转换为地图格数cell。 下面为用于DEBUG的输出函数,选手仅在开启Debug模式的情况下可以使用 -~~~c +~~~c++ void Print(std::string str) const; void PrintStudent() const; void PrintTricker() const; @@ -97,7 +84,7 @@ ~~~ ## 接口一览 -~~~csharp +~~~c++ // 指挥本角色进行移动,`timeInMilliseconds` 为移动时间,单位为毫秒;`angleInRadian` 表示移动的方向,单位是弧度,使用极坐标——竖直向下方向为 x 轴,水平向右方向为 y 轴 virtual std::future Move(int64_t timeInMilliseconds, double angleInRadian) = 0; diff --git a/CAPI/CAPI接口(python).md b/CAPI/CAPI接口(python).md new file mode 100644 index 0000000..71302c2 --- /dev/null +++ b/CAPI/CAPI接口(python).md @@ -0,0 +1,318 @@ +[toc] + +# CAPI接口(python) + +## 接口解释 + +### 主动指令 + +#### 移动 + +- `def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为x轴,水平向右方向为y轴** +- `def MoveRight(self, timeInMilliseconds: int) -> Future[bool]`即向右移动,`MoveLeft`、`MoveDown`、`MoveUp`同理 + +#### 使用技能 + +- `def UseSkill(self, skillID: int) -> Future[bool]`:使用对应序号的主动技能 + +#### 人物 + +- `def EndAllAction(self) -> Future[bool]`:可以使不处在不可行动状态中的玩家终止当前行动 + +#### 攻击 + +- `def Attack(self, angle: float) -> Future[bool]`:`angleInRadian`为攻击方向 + +#### 学习与毕业 + +- `def StartLearning(self) -> Future[bool]`:在教室里开始做作业 +- `def StartOpenGate(self) -> Future[bool]`:开始开启校门 +- `def Graduate(self) -> Future[bool]`:从开启的校门或隐藏校门毕业。 + +#### 勉励与唤醒 + +- `def StartEncourageMate(self, mateID: int) -> Future[bool]`:勉励对应玩家ID的学生。 +- `def StartRouseMate(self, mateID: int) -> Future[bool]`:唤醒对应玩家ID的沉迷的学生。 + +#### 地图互动 + +- `def OpenDoor(self) -> Future[bool]`:开门 +- `def CloseDoor(self) -> Future[bool]`:关门 +- `def SkipWindow(self) -> Future[bool]`:翻窗 +- `def StartOpenChest(self) -> Future[bool]`:开箱 + +#### 道具 + +- `def PickProp(self, propType: THUAI6.PropType) -> Future[bool]`捡起与自己处于同一个格子(cell)的道具。 +- `def UseProp(self, propType: THUAI6.PropType) -> Future[bool]`使用对应类型的道具 +- `def ThrowProp(self, propType: THUAI6.PropType) -> Future[bool]`将对应类型的道具扔在原地 + +### 信息获取 + +#### 队内信息 + + - `std::future SendMessage(int64_t, std::string)`:给同队的队友发送消息。第一个参数指定发送的对象,第二个参数指定发送的内容,不得超过256字节。 + - `bool HaveMessage()`:是否有队友发来的尚未接收的信息。 + - `std::pair GetMessage()`:从玩家ID为第一个参数的队友获取信息。 + +#### 查询可视范围内的信息 + + - `std::vector> GetStudents() const` :返回所有可视学生的信息。 + - `std::vector> GetTrickers() const` :返回所有可视捣蛋鬼的信息。 + - `std::vector> GetProps() const` :返回所有可视道具的信息。 + - `std::vector> GetBullets() const` :返回所有可视子弹(攻击)的信息。 + +#### 查询特定位置物体的信息 + +下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。 + + - `def GetPlaceType(self, cellX: int, cellY: int) -> THUAI6.PlaceType` :返回某一位置场地种类信息。场地种类详见 structure.h 。 + - `def IsDoorOpen(self, cellX: int, cellY: int) -> bool`:查询特定位置门是否开启 + - `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 GetHiddenGateState(self, cellX: int, cellY: int) -> THUAI6.HiddenGateState`::查询特定位置隐藏校门状态 + - `def GetDoorProgress(self, cellX: int, cellY: int) -> int`:查询特定位置门开启状态 + +#### 其他 + + - `def GetGameInfo(self) -> THUAI6.GameInfo`:查询当前游戏状态\ + - `def GetPlayerGUIDs(self) -> List[int]`:获取所有玩家的GUID\ + - `def GetFrameCount(self) -> int`:获取目前所进行的帧数\ + - `def GetSelfInfo(self) -> Union[THUAI6.Student, THUAI6.Tricker]`:获取自己的信息 + - `def GetFullMap(self) -> List[List[THUAI6.PlaceType]]`:返回整张地图的地形信息。 + +### 辅助函数 + +`def CellToGrid(cell: int) -> int`:将地图格数 cell 转换为绝对坐标grid。 + +`def GridToCell(grid: int) -> int`:将绝对坐标 grid 转换为地图格数cell。 + +下面为用于DEBUG的输出函数,选手仅在开启Debug模式的情况下可以使用 + +~~~python + def Print(self, cont: str) -> None: + def PrintStudent(self) -> None: + def PrintTricker(self) -> None: + def PrintProp(self) -> None: + def PrintSelfInfo(self) -> None: +~~~ + +## 接口一览 + +~~~python +class IAPI(metaclass=ABCMeta): + + # 选手可执行的操作 + # 指挥本角色进行移动,`timeInMilliseconds` 为移动时间,单位为毫秒;`angleInRadian` 表示移动的方向,单位是弧度,使用极坐标——竖直向下方向为 x 轴,水平向右方向为 y 轴 + + @abstractmethod + def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]: + pass + + # 向特定方向移动 + + @abstractmethod + def MoveRight(self, timeInMilliseconds: int) -> Future[bool]: + pass + + @abstractmethod + def MoveLeft(self, timeInMilliseconds: int) -> Future[bool]: + pass + + @abstractmethod + def MoveUp(self, timeInMilliseconds: int) -> Future[bool]: + pass + + @abstractmethod + def MoveDown(self, timeInMilliseconds: int) -> Future[bool]: + pass + + # 道具和技能相关 + + @abstractmethod + def PickProp(self, propType: THUAI6.PropType) -> Future[bool]: + pass + + @abstractmethod + def UseProp(self, propType: THUAI6.PropType) -> Future[bool]: + pass + + @abstractmethod + def ThrowProp(self, propType: THUAI6.PropType) -> Future[bool]: + pass + + @abstractmethod + def UseSkill(self, skillID: int) -> Future[bool]: + pass + + @abstractmethod + def Attack(self, angle: float) -> Future[bool]: + pass + + @abstractmethod + def OpenDoor(self) -> Future[bool]: + pass + + @abstractmethod + def CloseDoor(self) -> Future[bool]: + pass + + @abstractmethod + def SkipWindow(self) -> Future[bool]: + pass + + @abstractmethod + def StartOpenGate(self) -> Future[bool]: + pass + + @abstractmethod + def StartOpenChest(self) -> Future[bool]: + pass + + @abstractmethod + def EndAllAction(self) -> Future[bool]: + pass + + # 消息相关,接收消息时无消息则返回(-1, '') + + @abstractmethod + def SendMessage(self, toID: int, message: str) -> Future[bool]: + pass + + @abstractmethod + def HaveMessage(self) -> bool: + pass + + @abstractmethod + def GetMessage(self) -> Tuple[int, str]: + pass + + # 等待下一帧 + + @abstractmethod + def Wait(self) -> Future[bool]: + pass + + # 获取各类游戏中的消息 + + @abstractmethod + def GetFrameCount(self) -> int: + pass + + @abstractmethod + def GetPlayerGUIDs(self) -> List[int]: + pass + + @abstractmethod + def GetTrickers(self) -> List[THUAI6.Tricker]: + pass + + @abstractmethod + def GetStudents(self) -> List[THUAI6.Student]: + pass + + @abstractmethod + def GetProps(self) -> List[THUAI6.Prop]: + pass + + @abstractmethod + def GetBullets(self) -> List[THUAI6.Bullet]: + pass + + @abstractmethod + def GetSelfInfo(self) -> Union[THUAI6.Student, THUAI6.Tricker]: + pass + + @abstractmethod + def GetFullMap(self) -> List[List[THUAI6.PlaceType]]: + pass + + @abstractmethod + def GetPlaceType(self, cellX: int, cellY: int) -> THUAI6.PlaceType: + pass + + @abstractmethod + def IsDoorOpen(self, cellX: int, cellY: int) -> bool: + pass + + @abstractmethod + def GetChestProgress(self, cellX: int, cellY: int) -> int: + pass + + @abstractmethod + def GetGateProgress(self, cellX: int, cellY: int) -> int: + pass + + @abstractmethod + def GetClassroomProgress(self, cellX: int, cellY: int) -> int: + pass + + @abstractmethod + def GetDoorProgress(self, cellX: int, cellY: int) -> int: + pass + + @abstractmethod + def GetHiddenGateState(self, cellX: int, cellY: int) -> THUAI6.HiddenGateState: + pass + + @abstractmethod + def GetGameInfo(self) -> THUAI6.GameInfo: + pass + + # 用于DEBUG的输出函数,仅在DEBUG模式下有效 + + @abstractmethod + def Print(self, cont: str) -> None: + pass + + @abstractmethod + def PrintStudent(self) -> None: + pass + + @abstractmethod + def PrintTricker(self) -> None: + pass + + @abstractmethod + def PrintProp(self) -> None: + pass + + @abstractmethod + def PrintSelfInfo(self) -> None: + pass + + +class IStudentAPI(IAPI, metaclass=ABCMeta): + + # 人类阵营的特殊函数 + + @abstractmethod + def Graduate(self) -> Future[bool]: + pass + + @abstractmethod + def StartLearning(self) -> Future[bool]: + pass + + @abstractmethod + def StartEncourageMate(self, mateID: int) -> Future[bool]: + pass + + @abstractmethod + def StartRouseMate(self, mateID: int) -> Future[bool]: + pass + + @abstractmethod + def GetSelfInfo(self) -> THUAI6.Student: + pass + + +class ITrickerAPI(IAPI, metaclass=ABCMeta): + + # 屠夫阵营的特殊函数 + + @abstractmethod + def GetSelfInfo(self) -> THUAI6.Tricker: + pass +~~~ \ No newline at end of file diff --git a/CAPI/Tool_tutorial.md b/CAPI/Tool_tutorial.md index 0cd3ec2..8e57020 100644 --- a/CAPI/Tool_tutorial.md +++ b/CAPI/Tool_tutorial.md @@ -4,11 +4,15 @@ ## Visual Studio使用说明 -待更新... +选手开始编写代码之前,要先编译好服务器(logic)。具体方法是进入logic文件夹,分别编译`logic.sln`和client文件夹里的`client.sln`,然后就可以开始编写自己的代码。需要注意,选手需要分别在Debug和Release模式下编译,然后才可以分别运行`gameServer_dbg.cmd`和`gameServer_rls.cmd` + +## Python使用说明 + +选手编写Python代码之前需要安装必要的Python包,具体方法为:Windows下运行(需要在有Python环境的情况下运行)`generate_proto.cmd`,Linux下运行`generate_proto.sh`,然后可以开始进行代码编写。 ## cmd脚本的参数修改 -待更新... +右键点击`.cmd`或`.bat`文件之后,选择编辑就可以开始修改文件。通过在一行的开头加上`::`,可以注释掉该行。 ## C++接口必看 diff --git a/CAPI/cpp/API/include/logic.h b/CAPI/cpp/API/include/logic.h index 3e33682..a496a2d 100644 --- a/CAPI/cpp/API/include/logic.h +++ b/CAPI/cpp/API/include/logic.h @@ -42,12 +42,12 @@ private: std::unique_ptr pComm; // ID、阵营记录 - int64_t playerID; THUAI6::PlayerType playerType; + int64_t playerID; // 类型记录 - THUAI6::StudentType studentType; THUAI6::TrickerType trickerType; + THUAI6::StudentType studentType; // GUID信息 std::vector playerGUIDs; diff --git a/CAPI/cpp/API/include/state.h b/CAPI/cpp/API/include/state.h index 1440a2d..02f5543 100644 --- a/CAPI/cpp/API/include/state.h +++ b/CAPI/cpp/API/include/state.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "structures.h" diff --git a/CAPI/cpp/API/include/structures.h b/CAPI/cpp/API/include/structures.h index 88fd26c..d92a5d2 100644 --- a/CAPI/cpp/API/include/structures.h +++ b/CAPI/cpp/API/include/structures.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include namespace THUAI6 { @@ -85,6 +87,7 @@ namespace THUAI6 StraightAStudent = 3, Robot = 4, TechOtaku = 5, + Sunshine = 6, }; // 捣蛋鬼类型 @@ -174,7 +177,7 @@ namespace THUAI6 int32_t viewRange; // 视野范围 int64_t playerID; // 玩家ID int64_t guid; // 全局唯一ID - int16_t radius; // 圆形物体的半径或正方形物体的内切圆半径 + int32_t radius; // 圆形物体的半径或正方形物体的内切圆半径 int32_t score; // 分数 double facingDirection; // 朝向 @@ -285,6 +288,7 @@ namespace THUAI6 {StudentType::StraightAStudent, "StraightAStudent"}, {StudentType::Robot, "Robot"}, {StudentType::TechOtaku, "TechOtaku"}, + {StudentType::Sunshine, "Sunshine"}, }; inline std::map trickerTypeDict{ diff --git a/CAPI/cpp/API/include/utils.hpp b/CAPI/cpp/API/include/utils.hpp index dd550c7..e4f9260 100644 --- a/CAPI/cpp/API/include/utils.hpp +++ b/CAPI/cpp/API/include/utils.hpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include "Message2Clients.pb.h" #include "Message2Server.pb.h" #include "MessageType.pb.h" @@ -21,6 +23,11 @@ namespace AssistFunction return grid / numOfGridPerCell; } + [[nodiscard]] constexpr inline int GridToCell(double grid) noexcept + { + return int(grid) / numOfGridPerCell; + } + inline bool HaveView(int viewRange, int x, int y, int newX, int newY, std::vector>& map) { int deltaX = newX - x; @@ -112,6 +119,7 @@ namespace Proto2THUAI6 {protobuf::StudentType::STRAIGHT_A_STUDENT, THUAI6::StudentType::StraightAStudent}, {protobuf::StudentType::ROBOT, THUAI6::StudentType::Robot}, {protobuf::StudentType::TECH_OTAKU, THUAI6::StudentType::TechOtaku}, + {protobuf::StudentType::SUNSHINE, THUAI6::StudentType::Sunshine}, }; inline std::map trickerTypeDict{ @@ -370,6 +378,7 @@ namespace THUAI62Proto {THUAI6::StudentType::StraightAStudent, protobuf::StudentType::STRAIGHT_A_STUDENT}, {THUAI6::StudentType::Robot, protobuf::StudentType::ROBOT}, {THUAI6::StudentType::TechOtaku, protobuf::StudentType::TECH_OTAKU}, + {THUAI6::StudentType::Sunshine, protobuf::StudentType::SUNSHINE}, }; // inline std::map studentBuffTypeDict{ @@ -415,7 +424,7 @@ namespace THUAI62Proto return playerMsg; } - inline protobuf::IDMsg THUAI62ProtobufID(int playerID) + inline protobuf::IDMsg THUAI62ProtobufID(int64_t playerID) { protobuf::IDMsg idMsg; idMsg.set_player_id(playerID); diff --git a/CAPI/cpp/API/src/logic.cpp b/CAPI/cpp/API/src/logic.cpp index 799b281..abb4440 100644 --- a/CAPI/cpp/API/src/logic.cpp +++ b/CAPI/cpp/API/src/logic.cpp @@ -84,7 +84,7 @@ std::vector> Logic::GetFullMap() const THUAI6::PlaceType Logic::GetPlaceType(int32_t cellX, int32_t cellY) const { std::unique_lock lock(mtxState); - if (cellX < 0 || cellX >= currentState->gameMap.size() || cellY < 0 || cellY >= currentState->gameMap[0].size()) + if (cellX < 0 || uint64_t(cellX) >= currentState->gameMap.size() || cellY < 0 || uint64_t(cellY) >= currentState->gameMap[0].size()) { logger->warn("Invalid position!"); return THUAI6::PlaceType::NullPlaceType; diff --git a/CAPI/cpp/proto/MessageType.pb.cc b/CAPI/cpp/proto/MessageType.pb.cc index e0ba93e..7b2e493 100644 --- a/CAPI/cpp/proto/MessageType.pb.cc +++ b/CAPI/cpp/proto/MessageType.pb.cc @@ -55,19 +55,20 @@ const char descriptor_table_protodef_MessageType_2eproto[] PROTOBUF_SECTION_VARI "SPEAR\020\002\022\n\n\006ADD_AP\020\003\022\021\n\rCLAIRAUDIENCE\020\004\022\025" "\n\021TRICKER_INVISIBLE\020\005*J\n\nPlayerType\022\024\n\020N" "ULL_PLAYER_TYPE\020\000\022\022\n\016STUDENT_PLAYER\020\001\022\022\n" - "\016TRICKER_PLAYER\020\002*q\n\013StudentType\022\025\n\021NULL" + "\016TRICKER_PLAYER\020\002*\177\n\013StudentType\022\025\n\021NULL" "_STUDENT_TYPE\020\000\022\013\n\007ATHLETE\020\001\022\013\n\007TEACHER\020" "\002\022\026\n\022STRAIGHT_A_STUDENT\020\003\022\t\n\005ROBOT\020\004\022\016\n\n" - "TECH_OTAKU\020\005*Z\n\013TrickerType\022\025\n\021NULL_TRIC" - "KER_TYPE\020\000\022\014\n\010ASSASSIN\020\001\022\010\n\004KLEE\020\002\022\022\n\016A_" - "NOISY_PERSON\020\003\022\010\n\004IDOL\020\004*P\n\tGameState\022\023\n" - "\017NULL_GAME_STATE\020\000\022\016\n\nGAME_START\020\001\022\020\n\014GA" - "ME_RUNNING\020\002\022\014\n\010GAME_END\020\003b\006proto3"; -static ::PROTOBUF_NAMESPACE_ID::internal::once_flag descriptor_table_MessageType_2eproto_once; -const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_MessageType_2eproto = { + "TECH_OTAKU\020\005\022\014\n\010SUNSHINE\020\006*Z\n\013TrickerTyp" + "e\022\025\n\021NULL_TRICKER_TYPE\020\000\022\014\n\010ASSASSIN\020\001\022\010" + "\n\004KLEE\020\002\022\022\n\016A_NOISY_PERSON\020\003\022\010\n\004IDOL\020\004*P" + "\n\tGameState\022\023\n\017NULL_GAME_STATE\020\000\022\016\n\nGAME" + "_START\020\001\022\020\n\014GAME_RUNNING\020\002\022\014\n\010GAME_END\020\003" + "b\006proto3"; +static ::_pbi::once_flag descriptor_table_MessageType_2eproto_once; +const ::_pbi::DescriptorTable descriptor_table_MessageType_2eproto = { false, false, - 1474, + 1488, descriptor_table_protodef_MessageType_2eproto, "MessageType.proto", &descriptor_table_MessageType_2eproto_once, @@ -288,6 +289,7 @@ namespace protobuf case 3: case 4: case 5: + case 6: return true; default: return false; diff --git a/CAPI/cpp/proto/MessageType.pb.h b/CAPI/cpp/proto/MessageType.pb.h index e374be5..6dc5305 100644 --- a/CAPI/cpp/proto/MessageType.pb.h +++ b/CAPI/cpp/proto/MessageType.pb.h @@ -343,12 +343,13 @@ namespace protobuf STRAIGHT_A_STUDENT = 3, ROBOT = 4, TECH_OTAKU = 5, + SUNSHINE = 6, StudentType_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits::min(), StudentType_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits::max() }; bool StudentType_IsValid(int value); constexpr StudentType StudentType_MIN = NULL_STUDENT_TYPE; - constexpr StudentType StudentType_MAX = TECH_OTAKU; + constexpr StudentType StudentType_MAX = SUNSHINE; constexpr int StudentType_ARRAYSIZE = StudentType_MAX + 1; const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* StudentType_descriptor(); diff --git a/CAPI/python/PyAPI/structures.py b/CAPI/python/PyAPI/structures.py index dbd83fe..012f7ab 100644 --- a/CAPI/python/PyAPI/structures.py +++ b/CAPI/python/PyAPI/structures.py @@ -70,6 +70,7 @@ class StudentType(Enum): StraightAStudent = 3 Robot = 4 TechOtaku = 5 + Sunshine = 6 class TrickerType(Enum): diff --git a/CAPI/python/PyAPI/utils.py b/CAPI/python/PyAPI/utils.py index c1e31e2..2e1c181 100644 --- a/CAPI/python/PyAPI/utils.py +++ b/CAPI/python/PyAPI/utils.py @@ -105,7 +105,8 @@ class Proto2THUAI6(NoInstance): MessageType.TEACHER: THUAI6.StudentType.Teacher, MessageType.STRAIGHT_A_STUDENT: THUAI6.StudentType.StraightAStudent, MessageType.ROBOT: THUAI6.StudentType.Robot, - MessageType.TECH_OTAKU: THUAI6.StudentType.TechOtaku, } + MessageType.TECH_OTAKU: THUAI6.StudentType.TechOtaku, + MessageType.SUNSHINE: THUAI6.StudentType.Sunshine, } trickerTypeDict: Final[dict] = { MessageType.NULL_TRICKER_TYPE: THUAI6.TrickerType.NullTrickerType, @@ -309,7 +310,8 @@ class THUAI62Proto(NoInstance): THUAI6.StudentType.Teacher: MessageType.TEACHER, THUAI6.StudentType.StraightAStudent: MessageType.STRAIGHT_A_STUDENT, THUAI6.StudentType.Robot: MessageType.ROBOT, - THUAI6.StudentType.TechOtaku: MessageType.TECH_OTAKU, } + THUAI6.StudentType.TechOtaku: MessageType.TECH_OTAKU, + THUAI6.StudentType.Sunshine: MessageType.SUNSHINE, } trickerTypeDict: Final[dict] = { THUAI6.TrickerType.NullTrickerType: MessageType.NULL_TRICKER_TYPE, diff --git a/CAPI/python/generate_proto.sh b/CAPI/python/generate_proto.sh index 8b917c4..25e4cb7 100755 --- a/CAPI/python/generate_proto.sh +++ b/CAPI/python/generate_proto.sh @@ -8,5 +8,3 @@ python3 -m grpc_tools.protoc -I../../dependency/proto/ --python_out=./proto --py python3 -m grpc_tools.protoc -I../../dependency/proto/ --python_out=./proto --pyi_out=./proto Message2Clients.proto python3 -m grpc_tools.protoc -I../../dependency/proto/ --python_out=./proto --pyi_out=./proto Message2Server.proto python3 -m grpc_tools.protoc -I../../dependency/proto/ --python_out=./proto --pyi_out=./proto --grpc_python_out=./proto Services.proto - - diff --git a/dependency/proto/MessageType.proto b/dependency/proto/MessageType.proto index 5cc801e..9acbccb 100755 --- a/dependency/proto/MessageType.proto +++ b/dependency/proto/MessageType.proto @@ -110,6 +110,7 @@ enum StudentType STRAIGHT_A_STUDENT = 3; ROBOT = 4; TECH_OTAKU =5; + SUNSHINE = 6; } enum TrickerType diff --git a/logic/Client/MainWindow.xaml.cs b/logic/Client/MainWindow.xaml.cs index 714fea1..7999ed6 100644 --- a/logic/Client/MainWindow.xaml.cs +++ b/logic/Client/MainWindow.xaml.cs @@ -221,6 +221,9 @@ namespace Client case 5: playerMsg.StudentType = StudentType.TechOtaku; break; + case 6: + playerMsg.StudentType = StudentType.Sunshine; + break; case 0: default: playerMsg.StudentType = StudentType.NullStudentType; @@ -560,7 +563,7 @@ namespace Client { if (msg.PlayerState == PlayerState.Quit || msg.PlayerState == PlayerState.Graduated) return false; - if (isSpectatorMode) + if (isSpectatorMode || isPlaybackMode) return true; if (humanOrButcher && human != null) { @@ -579,7 +582,7 @@ namespace Client private bool CanSee(MessageOfTricker msg) { - if (isSpectatorMode) + if (isSpectatorMode || isPlaybackMode) return true; if (!humanOrButcher && butcher != null) { @@ -606,7 +609,7 @@ namespace Client private bool CanSee(MessageOfProp msg) { - if (isSpectatorMode) + if (isSpectatorMode || isPlaybackMode) return true; if (humanOrButcher && human != null) { @@ -625,7 +628,7 @@ namespace Client private bool CanSee(MessageOfBullet msg) { - if (isSpectatorMode) + if (isSpectatorMode || isPlaybackMode) return true; if (humanOrButcher && human != null) { @@ -644,7 +647,7 @@ namespace Client private bool CanSee(MessageOfBombedBullet msg) { - if (isSpectatorMode) + if (isSpectatorMode || isPlaybackMode) return true; //if (humanOrButcher && human != null) //{ diff --git a/logic/Client/PlaybackClient.cs b/logic/Client/PlaybackClient.cs index 5290b37..11acdc5 100644 --- a/logic/Client/PlaybackClient.cs +++ b/logic/Client/PlaybackClient.cs @@ -82,7 +82,6 @@ namespace Client }; new Thread(() => { - int i = 0; try { new FrameRateTaskExecutor @@ -91,10 +90,8 @@ namespace Client () => { var content = Reader.ReadOne(); - i++; if (content == null) { - MessageBox.Show($"End! {i}"); endFile = true; } else diff --git a/logic/Client/Properties/launchSettings.json b/logic/Client/Properties/launchSettings.json index a671030..a747e32 100644 --- a/logic/Client/Properties/launchSettings.json +++ b/logic/Client/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "Client": { "commandName": "Project", - "commandLineArgs": "--cl --port 8888 --characterID 2031" + "commandLineArgs": "--cl --playbackFile .\\video.thuaipb" } } } \ No newline at end of file diff --git a/logic/Client/StatusBarOfSurvivor.xaml.cs b/logic/Client/StatusBarOfSurvivor.xaml.cs index fa7ca3e..75011d8 100644 --- a/logic/Client/StatusBarOfSurvivor.xaml.cs +++ b/logic/Client/StatusBarOfSurvivor.xaml.cs @@ -53,6 +53,9 @@ namespace Client case StudentType.TechOtaku: serial.Text = "👥" + Convert.ToString(2) + "🧓" + Convert.ToString(obj.PlayerId) + "\nTechOtaku"; break; + case StudentType.Sunshine: + serial.Text = "👥" + Convert.ToString(2) + "🧓" + Convert.ToString(obj.PlayerId) + "\nSunshine"; + break; case StudentType.NullStudentType: serial.Text = "👥" + Convert.ToString(2) + "🧓" + Convert.ToString(obj.PlayerId) + "\nNullStudentType"; break; diff --git a/logic/Preparation/Utility/Transformation.cs b/logic/Preparation/Utility/Transformation.cs index 62fb05d..22b3464 100644 --- a/logic/Preparation/Utility/Transformation.cs +++ b/logic/Preparation/Utility/Transformation.cs @@ -200,6 +200,8 @@ namespace Preparation.Utility return Protobuf.StudentType.Robot; case Preparation.Utility.CharacterType.TechOtaku: return Protobuf.StudentType.TechOtaku; + case Preparation.Utility.CharacterType.Sunshine: + return Protobuf.StudentType.Sunshine; default: return Protobuf.StudentType.NullStudentType; } @@ -218,6 +220,8 @@ namespace Preparation.Utility return Preparation.Utility.CharacterType.Robot; case Protobuf.StudentType.TechOtaku: return Preparation.Utility.CharacterType.TechOtaku; + case Protobuf.StudentType.Sunshine: + return Preparation.Utility.CharacterType.Sunshine; default: return Preparation.Utility.CharacterType.Null; } diff --git a/logic/cmd/gameServer.cmd b/logic/cmd/gameServer.cmd index 3d9e370..22cac6c 100644 --- a/logic/cmd/gameServer.cmd +++ b/logic/cmd/gameServer.cmd @@ -1,12 +1,12 @@ @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 +start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName video ping -n 2 127.0.0.1 > NUL -start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 4 --type 2 --occupation 1 +start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 4 --type 2 --occupation 4 -start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 0 --type 1 --occupation 1 +start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 0 --type 1 --occupation 6 start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 1 --type 1 --occupation 2 diff --git a/logic/cmd/playback.cmd b/logic/cmd/playback.cmd index 32156c7..8e413d5 100644 --- a/logic/cmd/playback.cmd +++ b/logic/cmd/playback.cmd @@ -1,5 +1,5 @@ @echo off -start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --playbackFile .\test.thuaipb --playbackSpeed 1 +start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --playbackFile .\video.thuaipb --playbackSpeed 1 ping -n 2 127.0.0.1 > NUL \ No newline at end of file diff --git a/resource/client.png b/resource/client.png new file mode 100644 index 0000000..f63b284 Binary files /dev/null and b/resource/client.png differ diff --git a/使用文档.md b/使用文档.md new file mode 100644 index 0000000..92e23ba --- /dev/null +++ b/使用文档.md @@ -0,0 +1,167 @@ +# 使用文档 + +本文档仅供Windows选手参考,Linux选手仿照本文档即可 + +## 路径 + +Windows选手使用脚本位于Win文件夹下,Linux选手使用脚本位于Linux文件夹下 + +## 游戏启动方式(For Debug) + +1. 首先启动Server:`RunServerForDebug.cmd` +2. 再启动Client:Python使用`RunPython.cmd`,C++使用`RunCpp.cmd` + +## 实机体验游戏(ServerForPlay) + +启动游戏:ServerForPlay.cmd,其内部参数可自主设定,设定方式:右键-编辑 + +Server脚本中参数格式一般如下: + +```shell +--ip 0.0.0.0 --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName video +``` + +`--ip`是服务器ipv4地址 + +- 在不同电脑间体验游戏时需要修改`--ip`这一参数,默认值为0.0.0.0 +- 对于windows选手,在连接同一wifi(如Tsinghua-Secure)的情况下,打开终端输入`ipconfig`,找到IPv4地址即可 + +`--port`是服务器端口 + +- 自己规定,默认值为8888 + +`--studentCount`为本局学生个数 + +- 取值为0,1,2,3,4,默认值为4 + +`--trickerCount`为本局捣蛋鬼个数 + +- 取值为0,1,默认值为1 + +`--gameTimeInSecond`为本局最大游戏时长 + +- 可自主设定,默认值为600(秒) + +`--fileName`为回放文件的保存名称 + +此外,Server中还可以默认打开一个/多个WPF客户端,一般格式如下: + +```shell +--port 8888 --characterID 4 --type 2 --occupation 1 +``` + +`--ip`是服务器ipv4地址 + +- 默认值为127.0.0.1,其余内容与Server相同,在不同电脑间连接时ip应相同 + +`-port`是服务器端口 + +- 默认值为8888,其余内容与Server相同,在不同电脑间连接时port应相同 + +`--characterID`为玩家id + +- 学生取值为0,1,2,3,捣蛋鬼取值为4 + +`--type`为玩家类型 + +- 学生取值为1,捣蛋鬼取值为2 + +`--occupation`为职业选择,参考下表 + +### 职业对应表: + +* 学生 + + | 参数 | 职业类型 | + | ---- | ------------------------------- | + | 1 | Athlete | + | 2 | Teacher | + | 3 | StraightAStudent | + | 4 | Robot(目前未实现所有功能) | + | 5 | TechOtaku(目前未实现所有功能) | + | 6 | Sunshine | + +* 捣蛋鬼 + + | 参数 | 职业类型 | + | ---- | ------------ | + | 1 | Assassin | + | 2 | Klee | + | 3 | ANoisyPerson | + | 4 | Idol | + +此处只介绍职业的对应关系,详细的职业表请参考游戏规则部分。 + +## Client + +### C++接口 + +选手用Visual Studio打开CAPI.sln,编写AI.cpp,建议用Debug模式生成以方便自己调试,然后可以使用`RunCpp.cmd`启动。 + +`RunCpp.cmd`的脚本参数格式如下: + +```shell +-I 127.0.0.1 -P 8888 -p 0 -d -o -w +``` + +`-I`为服务器IP,一般本地为`127.0.0.1`,联机的话是服务器的IP + +`-P`为服务器端口,一般为8888 + +`-p`为玩家id,一般学生为0~3,捣蛋鬼为4 + +`-d`为保存Debug日志文件(在`/logs/`下) + +`-o`为将日志输出到屏幕上 + +`-w`只在开启`-o`的情况下生效,此时屏幕上只输出警告或报错(而日志文件依然完整保存)。 + +## WPF观看回放 + +使用`RunPlayback.cmd`,默认观看当前目录下的 video.thuaipb。 + +> 可以通过更改脚本中FileName参数,来观看不同的回放文件 + +## cmd脚本的参数修改 + +右键点击`.cmd`或`.bat`文件之后,选择编辑就可以开始修改文件。通过在一行的开头加上`::`,可以注释掉该行。 + +## WPF简易调试界面 + +![client](D:\2_autumn\thuai6\THUAI6\resource\client.png) + +### 界面介绍 + +* 固定方块:红色方块代表墙,绿色方块代表草,灰色方块代表窗户,黄色带锁标志的方块代表门 +* 动态方块:蓝色方块代表大门,橙色方块代表箱子,粉色方块代表教室,上面的数字均代表进度 +* 物件:橙色圆代表捣蛋鬼,紫色圆代表学生,且上面的编号对应学生的ID +* UI:左侧为UI,表示游戏内各类信息 + +### 实机体验之键鼠操作 + +仅当启动ServerForPlay.cmd时可以使用,观看回放时不能使用 + +| 键位 | 效果 | +| ------------ | ---------------------------------------------- | +| W/NumPad8 | (Both)向上移动 | +| S/NumPad2 | (Both)向下移动 | +| D/NumPad6 | (Both)向右移动 | +| A/NumPad4 | (Both)向左移动 | +| J | (Tri)攻击,方向向上 | +| 鼠标双击某点 | (Tri)攻击,方向与从Tricker指向该点的向量相同 | +| K | (Stu)开始学习 | +| R | (Stu)开始唤醒(陷入沉迷状态的同伴) | +| T | (Stu)开始勉励(学习毅力下降的同伴) | +| G | (Stu)发出毕业请求 | +| H | (Stu)申请毕业(或称为开校门) | +| O | (Both)开(教学楼)门 | +| P | (Both)关(教学楼)门 | +| U | (Both)翻窗 | +| I | (Both)翻箱子 | +| E | (Both)结束当前行动,回到Idle状态 | +| F | (Both)随机捡起一个在周围的道具 | +| C | (Both)随机扔下一个已经持有的道具 | +| V | (Both)随机使用一个已经持有的道具 | +| B | (Both)使用0号技能 | +| N | (Both)使用1号技能 | +| M | (Both)使用2号技能 | \ No newline at end of file