Browse Source

Merge branch 'dev' into dev

tags/0.1.0
sendssf GitHub 3 years ago
parent
commit
fa71045692
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 558 additions and 56 deletions
  1. +9
    -22
      CAPI/CAPI接口(cpp).md
  2. +318
    -0
      CAPI/CAPI接口(python).md
  3. +6
    -2
      CAPI/Tool_tutorial.md
  4. +2
    -2
      CAPI/cpp/API/include/logic.h
  5. +1
    -0
      CAPI/cpp/API/include/state.h
  6. +5
    -1
      CAPI/cpp/API/include/structures.h
  7. +10
    -1
      CAPI/cpp/API/include/utils.hpp
  8. +1
    -1
      CAPI/cpp/API/src/logic.cpp
  9. +11
    -9
      CAPI/cpp/proto/MessageType.pb.cc
  10. +2
    -1
      CAPI/cpp/proto/MessageType.pb.h
  11. +1
    -0
      CAPI/python/PyAPI/structures.py
  12. +4
    -2
      CAPI/python/PyAPI/utils.py
  13. +0
    -2
      CAPI/python/generate_proto.sh
  14. +1
    -0
      dependency/proto/MessageType.proto
  15. +8
    -5
      logic/Client/MainWindow.xaml.cs
  16. +0
    -3
      logic/Client/PlaybackClient.cs
  17. +1
    -1
      logic/Client/Properties/launchSettings.json
  18. +3
    -0
      logic/Client/StatusBarOfSurvivor.xaml.cs
  19. +4
    -0
      logic/Preparation/Utility/Transformation.cs
  20. +3
    -3
      logic/cmd/gameServer.cmd
  21. +1
    -1
      logic/cmd/playback.cmd
  22. BIN
      resource/client.png
  23. +167
    -0
      使用文档.md

CAPI/CAPI接口.md → CAPI/CAPI接口(cpp).md View File

@@ -1,22 +1,6 @@
- [CAPI接口](#capi接口)
- [接口解释](#接口解释)
- [主动指令](#主动指令)
- [移动](#移动)
- [使用技能](#使用技能)
- [人物](#人物)
- [攻击](#攻击)
- [学习与毕业](#学习与毕业)
- [勉励与唤醒](#勉励与唤醒)
- [地图互动](#地图互动)
- [道具](#道具)
- [信息获取](#信息获取)
- [队内信息](#队内信息)
- [查询可视范围内的信息](#查询可视范围内的信息)
- [查询特定位置物体的信息,下面的 CellX 和 CellY 指的是地图格数,而非绝对坐标。](#查询特定位置物体的信息下面的-cellx-和-celly-指的是地图格数而非绝对坐标)
- [其他](#其他)
- [辅助函数](#辅助函数)
- [接口一览](#接口一览)
# CAPI接口
[toc]

# CAPI接口(cpp)
## 接口解释

### 主动指令
@@ -66,7 +50,10 @@
- `std::vector<std::shared_ptr<const THUAI6::Prop>> GetProps() const` :返回所有可视道具的信息。
- `std::vector<std::shared_ptr<const THUAI6::Bullet>> 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<bool> Move(int64_t timeInMilliseconds, double angleInRadian) = 0;


+ 318
- 0
CAPI/CAPI接口(python).md View File

@@ -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<bool> SendMessage(int64_t, std::string)`:给同队的队友发送消息。第一个参数指定发送的对象,第二个参数指定发送的内容,不得超过256字节。
- `bool HaveMessage()`:是否有队友发来的尚未接收的信息。
- `std::pair<int64_t, std::string> GetMessage()`:从玩家ID为第一个参数的队友获取信息。

#### 查询可视范围内的信息

- `std::vector<std::shared_ptr<const THUAI6::Student>> GetStudents() const` :返回所有可视学生的信息。
- `std::vector<std::shared_ptr<const THUAI6::Tricker>> GetTrickers() const` :返回所有可视捣蛋鬼的信息。
- `std::vector<std::shared_ptr<const THUAI6::Prop>> GetProps() const` :返回所有可视道具的信息。
- `std::vector<std::shared_ptr<const THUAI6::Bullet>> 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
~~~

+ 6
- 2
CAPI/Tool_tutorial.md View File

@@ -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++接口必看



+ 2
- 2
CAPI/cpp/API/include/logic.h View File

@@ -42,12 +42,12 @@ private:
std::unique_ptr<Communication> pComm;

// ID、阵营记录
int64_t playerID;
THUAI6::PlayerType playerType;
int64_t playerID;

// 类型记录
THUAI6::StudentType studentType;
THUAI6::TrickerType trickerType;
THUAI6::StudentType studentType;

// GUID信息
std::vector<int64_t> playerGUIDs;


+ 1
- 0
CAPI/cpp/API/include/state.h View File

@@ -5,6 +5,7 @@
#include <vector>
#include <array>
#include <map>
#include <memory>

#include "structures.h"



+ 5
- 1
CAPI/cpp/API/include/structures.h View File

@@ -5,6 +5,8 @@
#include <cstdint>
#include <array>
#include <map>
#include <vector>
#include <string>

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<TrickerType, std::string> trickerTypeDict{


+ 10
- 1
CAPI/cpp/API/include/utils.hpp View File

@@ -5,6 +5,8 @@

#include <cstdint>
#include <cmath>
#include <map>
#include <vector>
#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<std::vector<THUAI6::PlaceType>>& 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<protobuf::TrickerType, THUAI6::TrickerType> 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<THUAI6::StudentBuffType, protobuf::StudentBuffType> 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);


+ 1
- 1
CAPI/cpp/API/src/logic.cpp View File

@@ -84,7 +84,7 @@ std::vector<std::vector<THUAI6::PlaceType>> Logic::GetFullMap() const
THUAI6::PlaceType Logic::GetPlaceType(int32_t cellX, int32_t cellY) const
{
std::unique_lock<std::mutex> 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;


+ 11
- 9
CAPI/cpp/proto/MessageType.pb.cc View File

@@ -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;


+ 2
- 1
CAPI/cpp/proto/MessageType.pb.h View File

@@ -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<int32_t>::min(),
StudentType_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::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();


+ 1
- 0
CAPI/python/PyAPI/structures.py View File

@@ -70,6 +70,7 @@ class StudentType(Enum):
StraightAStudent = 3
Robot = 4
TechOtaku = 5
Sunshine = 6


class TrickerType(Enum):


+ 4
- 2
CAPI/python/PyAPI/utils.py View File

@@ -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,


+ 0
- 2
CAPI/python/generate_proto.sh View File

@@ -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



+ 1
- 0
dependency/proto/MessageType.proto View File

@@ -110,6 +110,7 @@ enum StudentType
STRAIGHT_A_STUDENT = 3;
ROBOT = 4;
TECH_OTAKU =5;
SUNSHINE = 6;
}

enum TrickerType


+ 8
- 5
logic/Client/MainWindow.xaml.cs View File

@@ -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)
//{


+ 0
- 3
logic/Client/PlaybackClient.cs View File

@@ -82,7 +82,6 @@ namespace Client
};
new Thread(() =>
{
int i = 0;
try
{
new FrameRateTaskExecutor<int>
@@ -91,10 +90,8 @@ namespace Client
() =>
{
var content = Reader.ReadOne();
i++;
if (content == null)
{
MessageBox.Show($"End! {i}");
endFile = true;
}
else


+ 1
- 1
logic/Client/Properties/launchSettings.json View File

@@ -2,7 +2,7 @@
"profiles": {
"Client": {
"commandName": "Project",
"commandLineArgs": "--cl --port 8888 --characterID 2031"
"commandLineArgs": "--cl --playbackFile .\\video.thuaipb"
}
}
}

+ 3
- 0
logic/Client/StatusBarOfSurvivor.xaml.cs View File

@@ -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;


+ 4
- 0
logic/Preparation/Utility/Transformation.cs View File

@@ -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;
}


+ 3
- 3
logic/cmd/gameServer.cmd View File

@@ -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



+ 1
- 1
logic/cmd/playback.cmd View File

@@ -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

BIN
resource/client.png View File

Before After
Width: 1622  |  Height: 1092  |  Size: 135 kB

+ 167
- 0
使用文档.md View File

@@ -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号技能 |

Loading…
Cancel
Save