diff --git a/experimental/CAPI/README.md b/experimental/CAPI/README.md new file mode 100644 index 0000000..975735e --- /dev/null +++ b/experimental/CAPI/README.md @@ -0,0 +1,5 @@ +# experimental/CAPI + +## 简介 + +实验性选手接口 diff --git a/experimental/CAPI/go/.gitignore b/experimental/CAPI/go/.gitignore new file mode 100644 index 0000000..f00e123 --- /dev/null +++ b/experimental/CAPI/go/.gitignore @@ -0,0 +1,28 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# Protocol Buffers generated code directory +/API/proto/ + +# Executables +/API/API +/API/API.exe diff --git a/experimental/CAPI/go/API/ai.go b/experimental/CAPI/go/API/ai.go new file mode 100644 index 0000000..5cc86c6 --- /dev/null +++ b/experimental/CAPI/go/API/ai.go @@ -0,0 +1,15 @@ +package main + +import ( + thuai6 "API/thuai6" +) + +const Asynchronous = false + +func GetStudentType() []thuai6.StudentType { + return []thuai6.StudentType{thuai6.Athlete, thuai6.Teacher, thuai6.StraightAStudent, thuai6.Sunshine} +} + +func GetTrickerType() thuai6.TrickerType { + return thuai6.Assassin +} diff --git a/experimental/CAPI/go/API/core/api.go b/experimental/CAPI/go/API/core/api.go new file mode 100644 index 0000000..fd725e3 --- /dev/null +++ b/experimental/CAPI/go/API/core/api.go @@ -0,0 +1,80 @@ +package core + +import ( + thuai6 "API/thuai6" +) + +type ILogic interface { + Move(time int64, angle float64) bool + TryConnection() bool + GetStudentSelfInfo() *thuai6.Student + GetTrickerSelfInfo() *thuai6.Tricker +} + +type StudentAPI struct { + logic ILogic +} + +type TrickerAPI struct { + logic ILogic +} + +func NewStudentAPI(logic ILogic) *StudentAPI { + return &StudentAPI{ + logic: logic, + } +} + +func NewTrickerAPI(logic ILogic) *TrickerAPI { + return &TrickerAPI{ + logic: logic, + } +} + +func (api *StudentAPI) Move(timeInMilliseconds int64, angleInRadian float64) <-chan bool { + res := make(chan bool, 1) + go func() { + res <- api.logic.Move(timeInMilliseconds, angleInRadian) + }() + return res +} + +func (api *StudentAPI) GetSelfInfo() *thuai6.Student { + return api.logic.GetStudentSelfInfo() +} + +func (api *StudentAPI) StartTimer() { + // Nothing +} + +func (api *StudentAPI) EndTimer() { + // Nothing +} + +func (api *StudentAPI) Play(ai thuai6.IAI) { + ai.StudentPlay(api) +} + +func (api *TrickerAPI) Move(timeInMilliseconds int64, angleInRadian float64) <-chan bool { + res := make(chan bool, 1) + go func() { + res <- api.logic.Move(timeInMilliseconds, angleInRadian) + }() + return res +} + +func (api *TrickerAPI) GetSelfInfo() *thuai6.Tricker { + return api.logic.GetTrickerSelfInfo() +} + +func (api *TrickerAPI) StartTimer() { + // Nothing +} + +func (api *TrickerAPI) EndTimer() { + // Nothing +} + +func (api *TrickerAPI) Play(ai thuai6.IAI) { + ai.TrickerPlay(api) +} diff --git a/experimental/CAPI/go/API/core/communication.go b/experimental/CAPI/go/API/core/communication.go new file mode 100644 index 0000000..7e4a198 --- /dev/null +++ b/experimental/CAPI/go/API/core/communication.go @@ -0,0 +1,97 @@ +package core + +import ( + pb "API/proto" + thuai6 "API/thuai6" + "context" + "sync" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +type Communication struct { + stub pb.AvailableServiceClient + messageToClient *pb.MessageToClient + haveNewMessage bool + mtxMessage sync.Mutex + cvMessage *sync.Cond +} + +func NewCommunication(ip string, port string) (*Communication, error) { + addr := ip + ":" + port + conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return nil, err + } + stub := pb.NewAvailableServiceClient(conn) + comm := &Communication{stub: stub, messageToClient: nil, haveNewMessage: false, mtxMessage: sync.Mutex{}} + comm.cvMessage = sync.NewCond(&comm.mtxMessage) + return comm, nil +} + +func (self *Communication) TryConnection(playerID int64) bool { + res, err := self.stub.TryConnection(context.Background(), &pb.IDMsg{PlayerId: playerID}) + if err != nil { + // TODO: do loggings + return false + } + return res.GetActSuccess() +} + +func (self *Communication) AddPlayer(playerID int64, playerType thuai6.PlayerType, studentType thuai6.StudentType, trickerType thuai6.TrickerType) { + var playerMsg pb.PlayerMsg + playerMsg.PlayerId = playerID + playerMsg.PlayerType = thuai6.PlayerTypeToProto[playerType] + if playerType == thuai6.StudentPlayer { + playerMsg.JobType = &pb.PlayerMsg_StudentType{StudentType: thuai6.StudentTypeToProto[studentType]} + } else if playerType == thuai6.TrickerPlayer { + playerMsg.JobType = &pb.PlayerMsg_TrickerType{TrickerType: thuai6.TrickerTypeToProto[trickerType]} + } else { + // TODO: Report ERROR + } + + go func() { + msgReader, err := self.stub.AddPlayer(context.Background(), &playerMsg) + if err != nil { + // TODO: Report ERROR + } + for { + msg, err := msgReader.Recv() + if err != nil { + break + } + + func() { + self.mtxMessage.Lock() + defer self.mtxMessage.Unlock() + self.messageToClient = msg + self.haveNewMessage = true + self.cvMessage.Signal() + }() + } + }() +} + +func (self *Communication) Move(time int64, angle float64, playerID int64) bool { + res, err := self.stub.Move(context.Background(), &pb.MoveMsg{ + TimeInMilliseconds: time, + Angle: angle, + PlayerId: playerID, + }) + if err != nil { + // TODO: do loggings + return false + } + return res.GetActSuccess() +} + +func (self *Communication) GetMessageToClient() pb.MessageToClient { + self.mtxMessage.Lock() + defer self.mtxMessage.Unlock() + for !self.haveNewMessage { + self.cvMessage.Wait() + } + self.haveNewMessage = false + return *self.messageToClient +} diff --git a/experimental/CAPI/go/API/core/logic.go b/experimental/CAPI/go/API/core/logic.go new file mode 100644 index 0000000..803332a --- /dev/null +++ b/experimental/CAPI/go/API/core/logic.go @@ -0,0 +1,202 @@ +package core + +import ( + "errors" + "sync" + "sync/atomic" + + main "API" + pb "API/proto" + thuai6 "API/thuai6" +) + +type Logic struct { + communication *Communication + playerType thuai6.PlayerType + playerID int64 + studentType thuai6.StudentType + trickerType thuai6.TrickerType + timer thuai6.IGameTimer + mtxAI sync.Mutex + mtxState sync.Mutex + mtxBuffer sync.Mutex + cvBuffer *sync.Cond + cvAI *sync.Cond + state [2]thuai6.State + currentState *thuai6.State + bufferState *thuai6.State + counterState int32 + counterBuffer int32 + gameState thuai6.GameState + aiStart bool + bufferUpdated bool + aiLoop int32 + freshed int32 +} + +func NewLogic(playerType thuai6.PlayerType, id int64, tricker thuai6.TrickerType, student thuai6.StudentType) *Logic { + logic := &Logic{ + communication: nil, + playerType: playerType, + playerID: id, + studentType: student, + trickerType: tricker, + timer: nil, + mtxAI: sync.Mutex{}, + mtxState: sync.Mutex{}, + mtxBuffer: sync.Mutex{}, + cvBuffer: nil, + cvAI: nil, + state: [2]thuai6.State{}, + counterState: 0, + counterBuffer: 0, + gameState: thuai6.NullGameState, + aiStart: false, + bufferUpdated: true, + aiLoop: 1, + freshed: 0, + } + logic.currentState = &logic.state[0] + logic.bufferState = &logic.state[1] + logic.cvBuffer = sync.NewCond(&logic.mtxBuffer) + logic.cvAI = sync.NewCond(&logic.mtxAI) + return logic +} + +func (logic *Logic) GetStudentSelfInfo() *thuai6.Student { + logic.mtxState.Lock() + defer logic.mtxState.Unlock() + return logic.currentState.StudentSelf +} + +func (logic *Logic) GetTrickerSelfInfo() *thuai6.Tricker { + logic.mtxState.Lock() + defer logic.mtxState.Unlock() + return logic.currentState.TrickerSelf +} + +func (logic *Logic) Move(time int64, angle float64) bool { + return logic.communication.Move(time, angle, logic.playerID) +} + +func (logic *Logic) TryConnection() bool { + return logic.communication.TryConnection(logic.playerID) +} + +func (logic *Logic) Wait() { + atomic.StoreInt32(&logic.freshed, 0) + logic.mtxBuffer.Lock() + defer logic.mtxBuffer.Unlock() + for atomic.LoadInt32(&logic.freshed) == 0 { + logic.cvBuffer.Wait() + } +} + +func (logic *Logic) Update() { + if main.Asynchronous == false { + logic.mtxBuffer.Lock() + defer logic.mtxBuffer.Unlock() + for logic.bufferUpdated == false { + logic.cvBuffer.Wait() + } + // Go 的 defer 是函数推出时执行而非 block 退出时执行,故包装一层 func + func() { + logic.mtxState.Lock() + defer logic.mtxState.Unlock() + var tmpState = logic.currentState + logic.currentState = logic.bufferState + logic.bufferState = tmpState + logic.counterState = logic.counterBuffer + }() + logic.bufferUpdated = false + } +} + +func (logic *Logic) ProcessMessage() <-chan int { + endChan := make(chan int, 1) + go func() { + logic.communication.AddPlayer(logic.playerID, logic.playerType, logic.studentType, logic.trickerType) + for logic.gameState != thuai6.GameEnd { + clientMsg := logic.communication.GetMessageToClient() + logic.gameState = thuai6.GameStateToTHUAI6[clientMsg.GameState] + switch logic.gameState { + case thuai6.GameStart: + playerGUIDs := make([]int64, 0) + for _, obj := range clientMsg.ObjMessage { + switch obj.MessageOfObj.(type) { + case *(pb.MessageOfObj_StudentMessage): + playerGUIDs = append(playerGUIDs, obj.GetStudentMessage().GetGuid()) + } + } + for _, obj := range clientMsg.ObjMessage { + switch obj.MessageOfObj.(type) { + case *(pb.MessageOfObj_TrickerMessage): + playerGUIDs = append(playerGUIDs, obj.GetTrickerMessage().GetGuid()) + } + } + logic.currentState.Guids = playerGUIDs + logic.bufferState.Guids = playerGUIDs + // TODO: LoadBuffer + break + case thuai6.GameEnd: + + } + } + // TODO: ProcessMessage + endChan <- 0 + }() + return endChan +} + +func (logic *Logic) Main(createAI thuai6.CreateAIFunc, ip string, port string) error { + comm, err := NewCommunication(ip, port) + if err != nil { + return err + } + logic.communication = comm + + if logic.playerType == thuai6.StudentPlayer { + logic.timer = NewStudentAPI(logic) + } else if logic.playerType == thuai6.TrickerPlayer { + logic.timer = NewTrickerAPI(logic) + } else { + return errors.New("Invalid player type") + } + + aiThread := func() { + // Go 的 defer 是函数推出时执行而非 block 退出时执行,故包装一层 func + func() { + logic.mtxAI.Lock() + defer logic.mtxAI.Unlock() + for logic.aiStart == false { + logic.cvAI.Wait() + } + }() + ai := createAI(logic.playerID) + + for atomic.LoadInt32(&logic.aiLoop) != 0 { + if main.Asynchronous { + logic.Wait() + } else { + logic.Update() + } + logic.timer.StartTimer() + logic.timer.Play(ai) + logic.timer.EndTimer() + } + } + + if logic.TryConnection() == false { + atomic.StoreInt32(&logic.aiLoop, 0) + return errors.New("Connection failed.") + } + + aiEnd := make(chan int, 1) + go func() { + aiThread() + aiEnd <- 1 + }() + <-logic.ProcessMessage() + <-aiEnd + return nil +} diff --git a/experimental/CAPI/go/API/go.mod b/experimental/CAPI/go/API/go.mod new file mode 100644 index 0000000..a742248 --- /dev/null +++ b/experimental/CAPI/go/API/go.mod @@ -0,0 +1,13 @@ +module API + +go 1.18 + +require ( + github.com/golang/protobuf v1.5.2 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + golang.org/x/text v0.8.0 // indirect + google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect + google.golang.org/grpc v1.54.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect +) diff --git a/experimental/CAPI/go/API/go.sum b/experimental/CAPI/go/API/go.sum new file mode 100644 index 0000000..7f9e44e --- /dev/null +++ b/experimental/CAPI/go/API/go.sum @@ -0,0 +1,19 @@ +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/experimental/CAPI/go/API/main.go b/experimental/CAPI/go/API/main.go new file mode 100644 index 0000000..2f14bfd --- /dev/null +++ b/experimental/CAPI/go/API/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + "log" +) + +var ch = make(chan int, 1) + +func Func() { + log.Println(0) + ch <- 1 + log.Fatalln(1) +} + +func main() { + fmt.Println("THUAI6") +} diff --git a/experimental/CAPI/go/API/shell/init.sh b/experimental/CAPI/go/API/shell/init.sh new file mode 100755 index 0000000..cdd0c2e --- /dev/null +++ b/experimental/CAPI/go/API/shell/init.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +../../../dependency/proto/go_output.sh && go get diff --git a/experimental/CAPI/go/API/thuai6/iai.go b/experimental/CAPI/go/API/thuai6/iai.go new file mode 100644 index 0000000..cdaaa6d --- /dev/null +++ b/experimental/CAPI/go/API/thuai6/iai.go @@ -0,0 +1,14 @@ +package thuai6 + +type IGameTimer interface { + StartTimer() + EndTimer() + Play(ai IAI) +} + +type IAI interface { + StudentPlay(api IStudentAPI) + TrickerPlay(api ITrickerAPI) +} + +type CreateAIFunc = func(playerID int64) IAI diff --git a/experimental/CAPI/go/API/thuai6/iapi.go b/experimental/CAPI/go/API/thuai6/iapi.go new file mode 100644 index 0000000..5ee97f6 --- /dev/null +++ b/experimental/CAPI/go/API/thuai6/iapi.go @@ -0,0 +1,15 @@ +package thuai6 + +type IAPI interface { + Move(timeInMilliseconds int64, angleInRadian float64) <-chan bool +} + +type IStudentAPI interface { + IAPI + GetSelfInfo() *Student +} + +type ITrickerAPI interface { + IAPI + GetSelfInfo() *Tricker +} diff --git a/experimental/CAPI/go/API/thuai6/state.go b/experimental/CAPI/go/API/thuai6/state.go new file mode 100644 index 0000000..16fc3b8 --- /dev/null +++ b/experimental/CAPI/go/API/thuai6/state.go @@ -0,0 +1,7 @@ +package thuai6 + +type State struct { + StudentSelf *Student + TrickerSelf *Tricker + Guids []int64 +} diff --git a/experimental/CAPI/go/API/thuai6/structures.go b/experimental/CAPI/go/API/thuai6/structures.go new file mode 100644 index 0000000..22f0a10 --- /dev/null +++ b/experimental/CAPI/go/API/thuai6/structures.go @@ -0,0 +1,55 @@ +package thuai6 + +type GameState int8 + +const ( + NullGameState GameState = 0 + GameStart GameState = 1 + GameRunning GameState = 2 + GameEnd GameState = 3 +) + +type PlayerType int8 + +const ( + NullPlayerType PlayerType = 0 + StudentPlayer PlayerType = 1 + TrickerPlayer PlayerType = 2 +) + +type StudentType int8 + +const ( + NullStudentType StudentType = 0 + Athlete StudentType = 1 + Teacher StudentType = 2 + StraightAStudent StudentType = 3 + Robot StudentType = 4 + TechOtaku StudentType = 5 + Sunshine StudentType = 6 +) + +type TrickerType int8 + +const ( + NullTrickerType TrickerType = 0 + Assassin TrickerType = 1 + Klee TrickerType = 2 + ANoisyPerson TrickerType = 3 + Idol TrickerType = 4 +) + +type Player struct { + x int32 + y int32 +} + +type Student struct { + Player + determination int32 +} + +type Tricker struct { + Player + trickDesire float64 +} diff --git a/experimental/CAPI/go/API/thuai6/utils.go b/experimental/CAPI/go/API/thuai6/utils.go new file mode 100644 index 0000000..4be60c0 --- /dev/null +++ b/experimental/CAPI/go/API/thuai6/utils.go @@ -0,0 +1,38 @@ +package thuai6 + +import ( + pb "API/proto" +) + +var ( + PlayerTypeToProto map[PlayerType]pb.PlayerType = map[PlayerType]pb.PlayerType{ + NullPlayerType: pb.PlayerType_NULL_PLAYER_TYPE, + StudentPlayer: pb.PlayerType_STUDENT_PLAYER, + TrickerPlayer: pb.PlayerType_TRICKER_PLAYER, + } + + StudentTypeToProto map[StudentType]pb.StudentType = map[StudentType]pb.StudentType{ + NullStudentType: pb.StudentType_NULL_STUDENT_TYPE, + Athlete: pb.StudentType_ATHLETE, + Teacher: pb.StudentType_TEACHER, + StraightAStudent: pb.StudentType_STRAIGHT_A_STUDENT, + Robot: pb.StudentType_ROBOT, + TechOtaku: pb.StudentType_TECH_OTAKU, + Sunshine: pb.StudentType_SUNSHINE, + } + + TrickerTypeToProto map[TrickerType]pb.TrickerType = map[TrickerType]pb.TrickerType{ + NullTrickerType: pb.TrickerType_NULL_TRICKER_TYPE, + Assassin: pb.TrickerType_ASSASSIN, + Klee: pb.TrickerType_KLEE, + ANoisyPerson: pb.TrickerType_A_NOISY_PERSON, + Idol: pb.TrickerType_IDOL, + } + + GameStateToTHUAI6 map[pb.GameState]GameState = map[pb.GameState]GameState{ + pb.GameState_NULL_GAME_STATE: NullGameState, + pb.GameState_GAME_START: GameStart, + pb.GameState_GAME_RUNNING: GameRunning, + pb.GameState_GAME_END: GameEnd, + } +) diff --git a/experimental/CAPI/go/README.md b/experimental/CAPI/go/README.md new file mode 100644 index 0000000..4b2bfad --- /dev/null +++ b/experimental/CAPI/go/README.md @@ -0,0 +1,15 @@ +# experimental/CAPI/go + +## 简介 + +实验性选手 Go 接口 + +## 运行方法 + +**注意事项**:Visual Studio Code 的 Go 语言提示**必须**以 `main` package 所在的目录为根目录,否则可能无法进行正确的代码提示。因此以下操作的根目录均为 `/CPI/go/API/` + +```bash +$ ./shell/init.sh +$ go build +$ ./API +``` diff --git a/experimental/README.md b/experimental/README.md new file mode 100644 index 0000000..c83b7e5 --- /dev/null +++ b/experimental/README.md @@ -0,0 +1,9 @@ +# experimental + +## 简介 + +进行实验性功能的探索 + +## 注意事项 + +本文件夹内的文件采用某历史版本,与新近版本未必一致。 diff --git a/experimental/dependency/README.md b/experimental/dependency/README.md new file mode 100644 index 0000000..eb5db0c --- /dev/null +++ b/experimental/dependency/README.md @@ -0,0 +1,3 @@ +# experimental/dependency + +实验性依赖文件 diff --git a/experimental/dependency/proto/Message2Clients.proto b/experimental/dependency/proto/Message2Clients.proto new file mode 100755 index 0000000..fe5b97b --- /dev/null +++ b/experimental/dependency/proto/Message2Clients.proto @@ -0,0 +1,204 @@ +// Message2Client +syntax = "proto3"; +package protobuf; + +import "MessageType.proto"; + +message MessageOfStudent +{ + int32 x = 1; + int32 y = 2; + int32 speed = 3; + int32 determination = 4; // 剩余的学习毅力,相当于血量 + int32 addiction = 5; // 沉迷程度,相当于淘汰进度 + repeated double time_until_skill_available = 6; + PlaceType place = 7; + repeated PropType prop = 8; + PlayerState player_state = 9; + int64 guid = 10; + BulletType bullet_type = 12; + int32 learning_speed = 13; // 修理电机的速度 + int32 treat_speed = 14; // 治疗的速度 + int64 player_id = 15; + int32 view_range = 16; // 视野距离 + int32 radius = 17; // 半径 + double danger_alert = 19; // 危险警报,在捣蛋鬼靠近时会有预警 + int32 score = 20; + int32 treat_progress = 21; // 治疗进度 + int32 rescue_progress = 22; // 救援进度 + StudentType student_type = 23; + double facing_direction = 24; + repeated StudentBuffType buff = 25; +} + +message MessageOfTricker +{ + int32 x = 1; + int32 y = 2; + int32 speed = 3; + repeated double time_until_skill_available = 5; + PlaceType place = 6; + repeated PropType prop = 7; + TrickerType tricker_type = 8; + int64 guid = 9; + int32 score = 10; + int64 player_id = 11; + int32 view_range = 12; // 视野距离 + int32 radius = 13; // 半径 + PlayerState player_state = 14; + double trick_desire = 15;//bgm + double class_volume = 16;//bgm + double facing_direction = 17; + BulletType bullet_type = 18; + repeated TrickerBuffType buff = 19; +} + +message MessageOfBullet +{ + BulletType type = 1; + int32 x = 2; + int32 y = 3; + double facing_direction = 4; + int64 guid = 5; + PlayerType team = 6; + PlaceType place = 7; + double bomb_range = 8; + int32 speed = 9; +} + +message MessageOfBombedBullet //for Unity,直接继承自THUAI5 +{ + BulletType type = 1; + int32 x = 2; + int32 y = 3; + double facing_direction = 4; + int64 mapping_id = 5; + double bomb_range = 6; +} + +message MessageOfProp // 可拾取道具的信息 +{ + PropType type = 1; + int32 x = 2; + int32 y = 3; + double facing_direction = 4; + int64 guid = 5; + PlaceType place = 6; +} + + +message MessageOfPickedProp //for Unity,直接继承自THUAI5 +{ + PropType type = 1; + int32 x = 2; + int32 y = 3; + double facing_direction = 4; + int64 mapping_id = 5; +} + +message MessageOfClassroom +{ + int32 x = 1; + int32 y = 2; + int32 progress = 3; +} + +message MessageOfGate +{ + int32 x = 1; + int32 y = 2; + int32 progress = 3; +} + +message MessageOfHiddenGate +{ + int32 x = 1; + int32 y = 2; + bool opened = 3; +} + +message MessageOfDoor +{ + int32 x = 1; + int32 y = 2; + bool is_open = 3; + int32 progress = 4; +} + +message MessageOfChest +{ + int32 x = 1; + int32 y = 2; + int32 progress = 3; +} + +message MessageOfMap +{ + message Row + { + repeated PlaceType col = 1; + } + repeated Row row = 2; +} + +message MessageOfNews +{ + string news = 1; + int64 from_id = 2; + int64 to_id = 3; +} + +message MessageOfObj +{ + oneof message_of_obj + { + MessageOfStudent student_message = 1; + MessageOfTricker tricker_message = 2; + MessageOfProp prop_message = 3; + MessageOfBullet bullet_message = 4; + MessageOfBombedBullet bombed_bullet_message = 5; + MessageOfClassroom classroom_message = 6; + MessageOfDoor door_message = 7; + MessageOfGate gate_message = 8; + MessageOfChest chest_message = 9; + MessageOfHiddenGate hidden_gate_message = 10; + MessageOfNews news_message = 11; + MessageOfMap map_message = 12; + } +} + +message MessageOfAll +{ + int32 game_time = 1; + int32 subject_finished = 2; // 完成的科目数 + int32 student_graduated = 3; // 已经毕业的学生数 + int32 student_quited = 4; // 已经退学的学生数 + int32 student_score = 5; + int32 tricker_score = 6; +} + +message MessageToClient +{ + repeated MessageOfObj obj_message = 1; + GameState game_state = 2; + MessageOfAll all_message = 3; +} + +message MoveRes // 如果打算设计撞墙保留平行速度分量,且需要返回值则可用这个(大概没啥用) +{ + int64 actual_speed = 1; + double actual_angle = 2; + bool act_success = 3; +} + +message BoolRes // 用于只需要判断执行操作是否成功的行为,如捡起道具、使用道具 +{ + bool act_success = 1; +} + +// message MsgRes // 用于获取队友发来的消息 +// { +// bool have_message = 1; // 是否有待接收的消息 +// int64 from_player_id = 2; +// string message_received = 3; +// } diff --git a/experimental/dependency/proto/Message2Server.proto b/experimental/dependency/proto/Message2Server.proto new file mode 100755 index 0000000..d14b3cd --- /dev/null +++ b/experimental/dependency/proto/Message2Server.proto @@ -0,0 +1,74 @@ +// Message2Server +syntax = "proto3"; +package protobuf; + +import "MessageType.proto"; + +message PlayerMsg +{ + int64 player_id = 1; + oneof job_type + { + StudentType student_type = 2; + TrickerType tricker_type = 3; + } + PlayerType player_type = 4; +} + +message MoveMsg +{ + int64 player_id = 1; + double angle = 2; + int64 time_in_milliseconds = 3; +} + +message PropMsg +{ + int64 player_id = 1; + PropType prop_type = 2; +} + +message SendMsg +{ + int64 player_id = 1; + int64 to_player_id = 2; + string message = 3; +} + +message AttackMsg // 相当于攻击 +{ + int64 player_id = 1; + double angle = 2; +} + +message IDMsg +{ + int64 player_id = 1; +} + +message TreatAndRescueMsg +{ + int64 player_id = 1; + int64 to_player_id = 2; +} + +message SkillMsg +{ + int64 player_id = 1; + int32 skill_id = 2; +} + +// 基本继承于THUAI5,为了使发送的信息尽可能不被浪费,暂定不发这类大包。 +// message MessageToServer +// { +// MessageType messageType = 1; +// int64 playerID = 2; // 消息发送者的playerID +// PlayerType playerType = 3; +// HumanType humanType= 4; +// TrickerType trickerType = 5; +// double angle = 6; // messageType为Move, Attack时的角度 +// PropType propType = 7; // messageType为PickProp时要捡起的道具类型,防止多个道具堆叠时出现问题 +// int64 timeInMilliseconds = 8;//时间参数 +// int64 ToPlayerID = 9; // messageType为Send时要发送的对象的ID +// string message = 10; // messageType为Send时发送的消息内容 +// } \ No newline at end of file diff --git a/experimental/dependency/proto/MessageType.proto b/experimental/dependency/proto/MessageType.proto new file mode 100755 index 0000000..9acbccb --- /dev/null +++ b/experimental/dependency/proto/MessageType.proto @@ -0,0 +1,132 @@ +// MessageType +syntax = "proto3"; +package protobuf; + +enum BulletType +{ + NULL_BULLET_TYPE = 0; + FLYING_KNIFE = 1; + COMMON_ATTACK_OF_TRICKER = 2; + BOMB_BOMB = 3; + JUMPY_DUMPTY = 4; + ATOM_BOMB = 5; +} + +enum PlaceType // 地图中的所有物件类型 +{ + NULL_PLACE_TYPE = 0; + + // 地图情况,其中Gate是总体的大门,HiddenGate是地窖 + LAND = 1; + WALL = 2; + GRASS = 3; + CLASSROOM = 4; + GATE = 5; + HIDDEN_GATE = 6; + WINDOW = 7; + DOOR3 = 8; + DOOR5 = 9; + DOOR6 = 10; + CHEST = 11; + // 待补充有特殊效果的地形 +} + +enum ShapeType // 形状类型 +{ + NULL_SHAPE_TYPE = 0; + CIRCLE = 1; // 人类、屠夫、可拾取道具等为圆形 + SQUARE = 2; // 地形均为方形 +} + +enum PropType // 地图中的可拾取道具类型 +{ + NULL_PROP_TYPE = 0; + ADD_SPEED = 1; + ADD_LIFE_OR_CLAIRAUDIENCE = 2; + ADD_HP_OR_AP = 3; + SHIELD_OR_SPEAR = 4; + KEY3 = 5; + KEY5 = 6; + KEY6 = 7; + RECOVERY_FROM_DIZZINESS = 8; +} + +enum StudentBuffType // 人类可用的增益效果类型 +{ + NULL_SBUFF_TYPE = 0; + STUDENT_ADD_SPEED = 1; + ADD_LIFE = 2; + SHIELD = 3; + STUDENT_INVISIBLE = 4; +} + +enum PlayerState +{ + NULL_STATUS = 0; + IDLE = 1; // 正常状态 + LEARNING = 2; // 学习状态,相当于在修机器 + ADDICTED = 3; // 血条归零后原地沉迷游戏 + QUIT = 4; // 退学状态,相当于寄了 + GRADUATED = 5; // 毕业状态,相当于逃脱了 + TREATED = 6; + RESCUED = 7; + STUNNED = 8; + TREATING = 9; + RESCUING = 10; + SWINGING = 11; // 后摇 + ATTACKING = 12; // 前摇 + LOCKING = 13; + RUMMAGING = 14; + CLIMBING = 15; // 翻窗 + OPENING_A_CHEST =16; + USING_SPECIAL_SKILL = 17; + OPENING_A_GATE =18; +} + +enum TrickerBuffType // 屠夫可用的增益效果类型 +{ + NULL_TBUFF_TYPE = 0; + TRICKER_ADD_SPEED = 1; + SPEAR = 2; + ADD_AP = 3; + CLAIRAUDIENCE = 4; + TRICKER_INVISIBLE = 5; +} + +// 特别说明:由于Student阵营和Tricker阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和CharacterType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。 + +enum PlayerType +{ + NULL_PLAYER_TYPE = 0; + STUDENT_PLAYER = 1; + TRICKER_PLAYER = 2; +} + +enum StudentType +{ + NULL_STUDENT_TYPE = 0; + ATHLETE = 1; + TEACHER = 2; + STRAIGHT_A_STUDENT = 3; + ROBOT = 4; + TECH_OTAKU =5; + SUNSHINE = 6; +} + +enum TrickerType +{ + NULL_TRICKER_TYPE = 0; + ASSASSIN = 1; + KLEE = 2; + A_NOISY_PERSON = 3; + IDOL = 4; +} + +// 游戏进行状态 +enum GameState +{ + NULL_GAME_STATE = 0; + GAME_START = 1; + GAME_RUNNING = 2; + GAME_END = 3; +} diff --git a/experimental/dependency/proto/Services.proto b/experimental/dependency/proto/Services.proto new file mode 100755 index 0000000..92d4e59 --- /dev/null +++ b/experimental/dependency/proto/Services.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; +package protobuf; + +import "Message2Clients.proto"; +import "Message2Server.proto"; + +service AvailableService +{ + rpc TryConnection (IDMsg) returns(BoolRes); + + // 游戏开局调用一次的服务 + rpc AddPlayer (PlayerMsg) returns(stream MessageToClient); // 连接上后等待游戏开始,server会定时通过该服务向所有client发送消息。 + + // 游戏过程中玩家执行操作的服务 + rpc Move (MoveMsg) returns (MoveRes); + rpc PickProp (PropMsg) returns (BoolRes); + rpc UseProp (PropMsg) returns (BoolRes); + rpc ThrowProp (PropMsg) returns (BoolRes); + rpc UseSkill (SkillMsg) returns (BoolRes); + rpc SendMessage (SendMsg) returns (BoolRes); + // rpc GetMessage (IDMsg) returns (stream MsgRes); + rpc StartLearning (IDMsg) returns (BoolRes); // 开始修理机器 + rpc StartRescueMate (TreatAndRescueMsg) returns (BoolRes); // 开始救人 + rpc StartTreatMate (TreatAndRescueMsg) returns (BoolRes); // 开始治疗 + rpc Attack (AttackMsg) returns (BoolRes); // 攻击 + rpc Graduate (IDMsg) returns (BoolRes); // 相当于逃跑 + rpc OpenDoor (IDMsg) returns (BoolRes); // 开门 + rpc CloseDoor (IDMsg) returns (BoolRes); // 关门 + rpc SkipWindow (IDMsg) returns (BoolRes); // 窗户 + rpc StartOpenGate (IDMsg) returns (BoolRes); // 开闸门 + rpc StartOpenChest (IDMsg) returns (BoolRes); + rpc EndAllAction (IDMsg) returns (BoolRes); // 结束所有动作 +} diff --git a/experimental/dependency/proto/buf.gen.tag.yaml b/experimental/dependency/proto/buf.gen.tag.yaml new file mode 100644 index 0000000..25be191 --- /dev/null +++ b/experimental/dependency/proto/buf.gen.tag.yaml @@ -0,0 +1,10 @@ +version: v1 +managed: + enabled: true + go_package_prefix: + default: proto +plugins: + - name: gotag + out: . + opt: + - auto=bson diff --git a/experimental/dependency/proto/buf.gen.yaml b/experimental/dependency/proto/buf.gen.yaml new file mode 100644 index 0000000..4693eba --- /dev/null +++ b/experimental/dependency/proto/buf.gen.yaml @@ -0,0 +1,14 @@ +version: v1 +managed: + enabled: true + go_package_prefix: + default: job-API/proto +plugins: + - name: go + out: proto + opt: paths=source_relative + - name: go-grpc + out: proto + opt: + - paths=source_relative + - require_unimplemented_servers=false diff --git a/experimental/dependency/proto/go_output.sh b/experimental/dependency/proto/go_output.sh new file mode 100755 index 0000000..bd859e1 --- /dev/null +++ b/experimental/dependency/proto/go_output.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e + +PROTO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" +pushd "${PROTO_DIR}" +buf generate +rm -rf ../../CAPI/go/API/proto +mv -f proto ../../CAPI/go/API +popd