| @@ -13,7 +13,7 @@ message MessageOfStudent | |||
| int32 fail_num = 5; // 挂科的科目数 | |||
| double time_until_skill_available = 6; | |||
| PlaceType place = 7; | |||
| PropType prop = 8; | |||
| repeated PropType prop = 8; | |||
| StudentType student_type = 9; | |||
| int64 guid = 10; | |||
| StudentState state = 11; | |||
| @@ -34,7 +34,7 @@ message MessageOfTricker | |||
| int32 damage = 4; // 对学生造成的心理伤害 | |||
| double time_until_skill_available = 5; | |||
| PlaceType place = 6; | |||
| PropType prop = 7; | |||
| repeated PropType prop = 7; | |||
| TrickerType tricker_type = 8; | |||
| int64 guid = 9; | |||
| bool movable = 10; // 是否进入了攻击后摇 | |||
| @@ -78,6 +78,7 @@ message MessageOfProp // 可拾取道具的信息 | |||
| bool is_moving = 8; | |||
| } | |||
| message MessageOfPickedProp //for Unity,直接继承自THUAI5 | |||
| { | |||
| PropType type = 1; | |||
| @@ -87,6 +88,37 @@ message MessageOfPickedProp //for Unity,直接继承自THUAI5 | |||
| 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 MessageOfDoor | |||
| { | |||
| int32 x = 1; | |||
| int32 y = 2; | |||
| bool is_open = 3; | |||
| } | |||
| message MessageOfMapObj | |||
| { | |||
| oneof message_of_map_obj | |||
| { | |||
| MessageOfClassroom classroom_message = 1; | |||
| MessageOfDoor door_message = 2; | |||
| MessageOfGate gate_message = 3; | |||
| } | |||
| } | |||
| message MessageOfMap | |||
| { | |||
| message Row | |||
| @@ -94,17 +126,27 @@ message MessageOfMap | |||
| repeated PlaceType col = 1; | |||
| } | |||
| repeated Row row = 2; | |||
| repeated MessageOfMapObj map_obj_message = 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; | |||
| } | |||
| } | |||
| message MessageToClient | |||
| { | |||
| repeated MessageOfStudent student_message = 1; | |||
| repeated MessageOfTricker tricker_message = 2; // 是否真正repeated待定 | |||
| repeated MessageOfProp prop_message = 3; | |||
| repeated MessageOfBullet bullet_message = 4; | |||
| repeated MessageOfBombedBullet bombed_bullet_message = 5; | |||
| MessageOfMap map_message = 6; | |||
| GameState game_state = 7; | |||
| repeated MessageOfObj obj_message = 1; | |||
| MessageOfMap map_message = 2; | |||
| GameState game_state = 3; | |||
| int32 finished_num = 4; // 完成的科目数 | |||
| } | |||
| message MoveRes // 如果打算设计撞墙保留平行速度分量,且需要返回值则可用这个(大概没啥用) | |||
| @@ -22,7 +22,7 @@ message MoveMsg | |||
| int64 time_in_milliseconds = 3; | |||
| } | |||
| message PickMsg | |||
| message PropMsg | |||
| { | |||
| int64 player_id = 1; | |||
| PropType prop_type = 2; | |||
| @@ -23,6 +23,8 @@ enum PlaceType // 地图中的所有物件类型 | |||
| CLASSROOM = 4; | |||
| GATE = 5; | |||
| HIDDEN_GATE = 6; | |||
| WINDOW = 7; | |||
| DOOR = 8; | |||
| // 待补充有特殊效果的地形 | |||
| } | |||
| @@ -109,6 +111,7 @@ enum GameState | |||
| { | |||
| NULL_GAME_STATE = 0; | |||
| GAME_START = 1; | |||
| GAME_RUNNING = 2; | |||
| GAME_END = 3; | |||
| STAGE_1 = 2; // 第一阶段:大门没有开 | |||
| STAGE_2 = 3; // 第二阶段:大门已经开了 | |||
| GAME_END = 4; | |||
| } | |||
| @@ -13,7 +13,7 @@ service AvailableService | |||
| // 游戏过程中玩家执行操作的服务 | |||
| rpc Move (MoveMsg) returns (MoveRes); | |||
| rpc PickProp (PickMsg) returns (BoolRes); | |||
| rpc PickProp (PropMsg) returns (BoolRes); | |||
| rpc UseProp (IDMsg) returns (BoolRes); | |||
| rpc UseSkill (IDMsg) returns (BoolRes); | |||
| rpc SendMessage (SendMsg) returns (BoolRes); | |||
| @@ -23,5 +23,9 @@ service AvailableService | |||
| rpc StartHealMate (IDMsg) returns (BoolRes); | |||
| rpc Trick (TrickMsg) 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 EndAllAction (IDMsg) returns (BoolRes); // 结束所有动作 | |||
| } | |||
| @@ -7,27 +7,29 @@ namespace ClientTest | |||
| { | |||
| public static async Task Main(string[] args) | |||
| { | |||
| Channel channel = new Channel("0.0.0.0:8888", ChannelCredentials.Insecure); | |||
| Thread.Sleep(3000); | |||
| Channel channel = new Channel("127.0.0.1:8888", ChannelCredentials.Insecure); | |||
| var client = new AvailableService.AvailableServiceClient(channel); | |||
| PlayerMsg playerInfo = new(); | |||
| playerInfo.PlayerId = Convert.ToInt32(args[0]); | |||
| playerInfo.PlayerType = (PlayerType)Convert.ToInt32(args[1]); | |||
| playerInfo.PlayerId = 0; | |||
| playerInfo.PlayerType = PlayerType.StudentPlayer; | |||
| playerInfo.StudentType = StudentType.NullStudentType; | |||
| var call = client.AddPlayer(playerInfo); | |||
| while (await call.ResponseStream.MoveNext()) | |||
| { | |||
| var currentGameInfo = call.ResponseStream.Current; | |||
| if (playerInfo.PlayerType == PlayerType.HumanPlayer) | |||
| if (playerInfo.PlayerType == PlayerType.StudentPlayer) | |||
| { | |||
| for (int i = 0; i < currentGameInfo.HumanMessage.Count; i++) | |||
| for (int i = 0; i < currentGameInfo.StudentMessage.Count; i++) | |||
| { | |||
| Console.WriteLine($"Human is at ({currentGameInfo.HumanMessage[i].X}, {currentGameInfo.HumanMessage[i].Y})"); | |||
| Console.WriteLine($"Human is at ({currentGameInfo.StudentMessage[i].X}, {currentGameInfo.StudentMessage[i].Y})"); | |||
| } | |||
| } | |||
| if (playerInfo.PlayerType == PlayerType.ButcherPlayer) | |||
| if (playerInfo.PlayerType == PlayerType.TrickerPlayer) | |||
| { | |||
| for (int i = 0; i < currentGameInfo.ButcherMessage.Count; i++) | |||
| for (int i = 0; i < currentGameInfo.TrickerMessage.Count; i++) | |||
| { | |||
| Console.WriteLine($"Butcher is at ({currentGameInfo.ButcherMessage[i].X}, {currentGameInfo.ButcherMessage[i].Y})"); | |||
| Console.WriteLine($"Butcher is at ({currentGameInfo.TrickerMessage[i].X}, {currentGameInfo.TrickerMessage[i].Y})"); | |||
| } | |||
| } | |||
| } | |||
| @@ -100,4 +100,4 @@ namespace GameClass.GameObj | |||
| Debugger.Output(this, "constructed!"); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -100,4 +100,4 @@ namespace GameClass.GameObj | |||
| this.fixSpeed = ((IStudent)Occupation).FixSpeed; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -39,6 +39,7 @@ namespace Gaming | |||
| XY pos = gameMap.BirthPointList[playerInitInfo.birthPointIndex]; | |||
| // Console.WriteLine($"x,y: {pos.x},{pos.y}"); | |||
| Character newPlayer = (GameData.IsGhost(playerInitInfo.characterType)) ? new Ghost(pos, GameData.characterRadius, gameMap.GetPlaceType(pos), playerInitInfo.characterType) : new Student(pos, GameData.characterRadius, gameMap.GetPlaceType(pos), playerInitInfo.characterType); | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterWriteLock(); | |||
| try | |||
| @@ -1,187 +1,366 @@ | |||
| using Protobuf; | |||
| using System.Collections.Generic; | |||
| using GameClass.GameObj; | |||
| /* | |||
| namespace Server | |||
| { | |||
| public static class CopyInfo | |||
| { | |||
| public static MessageToClient.Types.GameObjMessage? Auto(GameObj gameObj) | |||
| // 下面赋值为0的大概率是还没写完 2023-03-03 | |||
| private static MessageOfStudent Human(Character player) | |||
| { | |||
| if (gameObj.Type == Preparation.Utility.GameObjType.Character) | |||
| return Player((Character)gameObj); | |||
| else if (gameObj.Type == Preparation.Utility.GameObjType.Bullet) | |||
| return Bullet((Bullet)gameObj); | |||
| else if (gameObj.Type == Preparation.Utility.GameObjType.Prop) | |||
| return Prop((Prop)gameObj); | |||
| else if (gameObj.Type == Preparation.Utility.GameObjType.BombedBullet) | |||
| return BombedBullet((BombedBullet)gameObj); | |||
| else if (gameObj.Type == Preparation.Utility.GameObjType.PickedProp) | |||
| return PickedProp((PickedProp)gameObj); | |||
| else return null; //先写着防报错 | |||
| MessageOfStudent msg = new MessageOfStudent(); | |||
| if (player.IsGhost()) return null; | |||
| msg.X = player.Position.x; | |||
| msg.Y = player.Position.y; | |||
| msg.Speed = player.MoveSpeed; | |||
| msg.Determination = player.HP; | |||
| msg.FailNum = 0; | |||
| msg.TimeUntilSkillAvailable = 0; | |||
| //msg.Place = 0; 下面写了 | |||
| msg.StudentType = StudentType.NullStudentType; // 下面写 | |||
| msg.Guid = 0; | |||
| msg.State = StudentState.NullStatus; | |||
| msg.FailTime = 0; | |||
| msg.EmoTime = 0; | |||
| msg.PlayerId = 0; | |||
| msg.ViewRange = 0; | |||
| msg.Radius = 0; | |||
| //msg.Buff[0] = StudentBuffType.NullSbuffType; 下面写了 | |||
| /* THUAI5中的内容 | |||
| msg.BulletNum = player.BulletNum; | |||
| msg.CanMove = player.CanMove; | |||
| msg.CD = player.CD; | |||
| msg.GemNum = player.GemNum; | |||
| msg.Guid = player.ID; | |||
| msg.IsResetting = player.IsResetting; | |||
| msg.LifeNum = player.DeathCount + 1; | |||
| msg.Radius = player.Radius; | |||
| msg.TimeUntilCommonSkillAvailable = player.TimeUntilCommonSkillAvailable; | |||
| msg.TeamID = player.TeamID; | |||
| msg.PlayerID = player.PlayerID; | |||
| msg.IsInvisible = player.IsInvisible; | |||
| msg.FacingDirection = player.FacingDirection; | |||
| //应该要发队伍分数,这里先发个人分数 | |||
| msg.MessageOfHuman.Score = player.Score; | |||
| //这条暂时没啥用 | |||
| msg.MessageOfHuman.TimeUntilUltimateSkillAvailable = 0; | |||
| msg.MessageOfHuman.Vampire = player.Vampire;*/ | |||
| foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff) | |||
| { | |||
| if (kvp.Value) | |||
| { | |||
| switch (kvp.Key) // StudentBuffType具体内容待定 | |||
| { | |||
| case Preparation.Utility.BuffType.Spear: | |||
| msg.Buff.Add(StudentBuffType.NullSbuffType); | |||
| break; | |||
| case Preparation.Utility.BuffType.AddLIFE: | |||
| msg.Buff.Add(StudentBuffType.NullSbuffType); | |||
| break; | |||
| case Preparation.Utility.BuffType.Shield: | |||
| msg.Buff.Add(StudentBuffType.NullSbuffType); | |||
| break; | |||
| case Preparation.Utility.BuffType.AddSpeed: | |||
| msg.Buff.Add(StudentBuffType.NullSbuffType); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| /*switch (player.Place) | |||
| { | |||
| case Preparation.Utility.PlaceType.Land: | |||
| msg.Place = PlaceType.Land; | |||
| break; | |||
| case Preparation.Utility.PlaceType.Grass1: | |||
| msg.Place = PlaceType.Grass; | |||
| break; | |||
| case Preparation.Utility.PlaceType.Grass2: | |||
| msg.Place = PlaceType.Grass; | |||
| break; | |||
| case Preparation.Utility.PlaceType.Grass3: | |||
| msg.Place = PlaceType.Grass; | |||
| break; | |||
| // case Preparation.Utility.PlaceType.Invisible: | |||
| // msg.MessageOfHuman.Place = Communication.Proto.PlaceType.Invisible; | |||
| // break; | |||
| default: | |||
| msg.Place = PlaceType.NullPlaceType; | |||
| break; | |||
| }*/ | |||
| //Character的储存方式可能得改,用enum type存道具和子弹,不应该用对象 | |||
| //现在懒得改了,有时间再重整一波 | |||
| /*if (player.PropInventory == null) | |||
| msg.Prop = PropType.NullPropType; | |||
| else | |||
| { | |||
| switch (player.PropInventory.GetPropType()) | |||
| { | |||
| case Preparation.Utility.PropType.Gem: | |||
| msg.Prop = PropType.NullPropType; | |||
| break; | |||
| case Preparation.Utility.PropType.addLIFE: | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddLife; | |||
| break; | |||
| case Preparation.Utility.PropType.addSpeed: | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddSpeed; | |||
| break; | |||
| case Preparation.Utility.PropType.Shield: | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.Shield; | |||
| break; | |||
| case Preparation.Utility.PropType.Spear: | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.Spear; | |||
| break; | |||
| default: | |||
| msg.Prop = PropType.NullPropType; | |||
| break; | |||
| } | |||
| }*/ | |||
| /*switch (player.PassiveSkillType) 需要对接一下,proto里似乎没有这个 | |||
| { | |||
| case Preparation.Utility.PassiveSkillType.RecoverAfterBattle: | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.RecoverAfterBattle; | |||
| break; | |||
| case Preparation.Utility.PassiveSkillType.SpeedUpWhenLeavingGrass: | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.SpeedUpWhenLeavingGrass; | |||
| break; | |||
| case Preparation.Utility.PassiveSkillType.Vampire: | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.Vampire; | |||
| break; | |||
| default: | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.NullPassiveSkillType; | |||
| break; | |||
| } | |||
| switch (player.CommonSkillType) | |||
| { | |||
| case Preparation.Utility.ActiveSkillType.BecomeAssassin: | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.BecomeAssassin; | |||
| break; | |||
| case Preparation.Utility.ActiveSkillType.BecomeVampire: | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.BecomeVampire; | |||
| break; | |||
| case Preparation.Utility.ActiveSkillType.NuclearWeapon: | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.NuclearWeapon; | |||
| break; | |||
| case Preparation.Utility.ActiveSkillType.SuperFast: | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.SuperFast; | |||
| break; | |||
| default: | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.NullActiveSkillType; | |||
| break; | |||
| } | |||
| switch (player.BulletOfPlayer) | |||
| { | |||
| case Preparation.Utility.BulletType.AtomBomb: | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.AtomBomb; | |||
| break; | |||
| case Preparation.Utility.BulletType.OrdinaryBullet: | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.OrdinaryBullet; | |||
| break; | |||
| case Preparation.Utility.BulletType.FastBullet: | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.FastBullet; | |||
| break; | |||
| case Preparation.Utility.BulletType.LineBullet: | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.LineBullet; | |||
| break; | |||
| default: | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.NullBulletType; | |||
| break; | |||
| }*/ | |||
| return msg; | |||
| } | |||
| private static MessageToClient.Types.GameObjMessage Player(Character player) | |||
| private static MessageOfTricker Butcher(Character player) | |||
| { | |||
| MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage(); | |||
| msg.MessageOfCharacter = new MessageOfCharacter(); | |||
| MessageOfTricker msg = new MessageOfTricker(); | |||
| if (!player.IsGhost()) return null; | |||
| msg.X = player.Position.x; | |||
| msg.Y = player.Position.y; | |||
| msg.Speed = player.MoveSpeed; | |||
| msg.Damage = 0; | |||
| msg.TimeUntilSkillAvailable = 0; | |||
| //msg.Place = 0; 下面写了 | |||
| //msg.Prop = PropType.NullPropType; // 下面写 | |||
| msg.TrickerType = TrickerType.NullTrickerType; // 下面写 | |||
| msg.Guid = 0; | |||
| msg.Movable = false; | |||
| msg.PlayerId = 0; | |||
| msg.ViewRange = 0; | |||
| msg.Radius = 0; | |||
| //msg.Buff[0] = ButcherBuffType.NullSbuffType; 下面写了 | |||
| msg.MessageOfCharacter.X = player.Position.x; | |||
| msg.MessageOfCharacter.Y = player.Position.y; | |||
| msg.MessageOfCharacter.AttackRange = player.AttackRange; | |||
| msg.MessageOfCharacter.BulletNum = player.BulletNum; | |||
| msg.MessageOfCharacter.CanMove = player.CanMove; | |||
| msg.MessageOfCharacter.CD = player.CD; | |||
| msg.MessageOfCharacter.GemNum = player.GemNum; | |||
| msg.MessageOfCharacter.Guid = player.ID; | |||
| msg.MessageOfCharacter.IsResetting = player.IsResetting; | |||
| msg.MessageOfCharacter.Life = player.HP; | |||
| msg.MessageOfCharacter.LifeNum = player.DeathCount + 1; | |||
| msg.MessageOfCharacter.Radius = player.Radius; | |||
| msg.MessageOfCharacter.Speed = player.MoveSpeed; | |||
| msg.MessageOfCharacter.TimeUntilCommonSkillAvailable = player.TimeUntilCommonSkillAvailable; | |||
| msg.MessageOfCharacter.TeamID = player.TeamID; | |||
| msg.MessageOfCharacter.PlayerID = player.PlayerID; | |||
| msg.MessageOfCharacter.IsInvisible = player.IsInvisible; | |||
| msg.MessageOfCharacter.FacingDirection = player.FacingDirection; | |||
| /* THUAI5中的内容 | |||
| msg.BulletNum = player.BulletNum; | |||
| msg.CanMove = player.CanMove; | |||
| msg.CD = player.CD; | |||
| msg.GemNum = player.GemNum; | |||
| msg.Guid = player.ID; | |||
| msg.IsResetting = player.IsResetting; | |||
| msg.LifeNum = player.DeathCount + 1; | |||
| msg.Radius = player.Radius; | |||
| msg.TimeUntilCommonSkillAvailable = player.TimeUntilCommonSkillAvailable; | |||
| msg.TeamID = player.TeamID; | |||
| msg.PlayerID = player.PlayerID; | |||
| msg.IsInvisible = player.IsInvisible; | |||
| msg.FacingDirection = player.FacingDirection; | |||
| //应该要发队伍分数,这里先发个人分数 | |||
| msg.MessageOfCharacter.Score = player.Score; | |||
| msg.MessageOfHuman.Score = player.Score; | |||
| //这条暂时没啥用 | |||
| msg.MessageOfCharacter.TimeUntilUltimateSkillAvailable = 0; | |||
| msg.MessageOfHuman.TimeUntilUltimateSkillAvailable = 0; | |||
| msg.MessageOfHuman.Vampire = player.Vampire;*/ | |||
| msg.MessageOfCharacter.Vampire = player.Vampire; | |||
| foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff) | |||
| { | |||
| if (kvp.Value) | |||
| { | |||
| switch(kvp.Key) | |||
| switch (kvp.Key) // ButcherBuffType具体内容待定 | |||
| { | |||
| case Preparation.Utility.BuffType.Spear: | |||
| msg.MessageOfCharacter.Buff.Add(BuffType.SpearBuff); | |||
| msg.Buff.Add(TrickerBuffType.NullTbuffType); | |||
| break; | |||
| case Preparation.Utility.BuffType.AddLIFE: | |||
| msg.MessageOfCharacter.Buff.Add(BuffType.AddLife); | |||
| msg.Buff.Add(TrickerBuffType.NullTbuffType); | |||
| break; | |||
| case Preparation.Utility.BuffType.Shield: | |||
| msg.MessageOfCharacter.Buff.Add(BuffType.ShieldBuff); | |||
| msg.Buff.Add(TrickerBuffType.NullTbuffType); | |||
| break; | |||
| case Preparation.Utility.BuffType.AddSpeed: | |||
| msg.MessageOfCharacter.Buff.Add(BuffType.MoveSpeed); | |||
| msg.Buff.Add(TrickerBuffType.NullTbuffType); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| switch (player.Place) | |||
| /*switch (player.Place) | |||
| { | |||
| case Preparation.Utility.PlaceType.Null: | |||
| msg.MessageOfCharacter.Place = Communication.Proto.PlaceType.Null; | |||
| case Preparation.Utility.PlaceType.Land: | |||
| msg.Place = PlaceType.Land; | |||
| break; | |||
| case Preparation.Utility.PlaceType.Grass: | |||
| msg.MessageOfCharacter.Place = Communication.Proto.PlaceType.Grass; | |||
| case Preparation.Utility.PlaceType.Grass1: | |||
| msg.Place = PlaceType.Grass; | |||
| break; | |||
| case Preparation.Utility.PlaceType.Grass: | |||
| msg.MessageOfCharacter.Place = Communication.Proto.PlaceType.Grass; | |||
| case Preparation.Utility.PlaceType.Grass2: | |||
| msg.Place = PlaceType.Grass; | |||
| break; | |||
| case Preparation.Utility.PlaceType.Grass: | |||
| msg.MessageOfCharacter.Place = Communication.Proto.PlaceType.Grass; | |||
| case Preparation.Utility.PlaceType.Grass3: | |||
| msg.Place = PlaceType.Grass; | |||
| break; | |||
| // case Preparation.Utility.PlacccceType.Invisible: | |||
| // msg.MessageOfCharacter.Place = Communication.Proto.PlacccceType.Invisible; | |||
| // break; | |||
| // case Preparation.Utility.PlaceType.Invisible: | |||
| // msg.MessageOfHuman.Place = Communication.Proto.PlaceType.Invisible; | |||
| // break; | |||
| default: | |||
| msg.MessageOfCharacter.Place = Communication.Proto.PlacccceType.NullPlaceType; | |||
| msg.Place = PlaceType.NullPlaceType; | |||
| break; | |||
| } | |||
| }*/ | |||
| //Character的储存方式可能得改,用enum type存道具和子弹,不应该用对象 | |||
| //现在懒得改了,有时间再重整一波 | |||
| if (player.PropInventory == null) | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.NullPropType; | |||
| /*if (player.PropInventory == null) | |||
| msg.Prop = PropType.NullPropType; | |||
| else | |||
| { | |||
| switch (player.PropInventory.GetPropType()) | |||
| { | |||
| case Preparation.Utility.PropType.Gem: | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.Gem; | |||
| msg.Prop = PropType.NullPropType; | |||
| break; | |||
| case Preparation.Utility.PropType.addLIFE: | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.AddLife; | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddLife; | |||
| break; | |||
| case Preparation.Utility.PropType.addSpeed: | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.AddSpeed; | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddSpeed; | |||
| break; | |||
| case Preparation.Utility.PropType.Shield: | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.Shield; | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.Shield; | |||
| break; | |||
| case Preparation.Utility.PropType.Spear: | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.Spear; | |||
| msg.MessageOfHuman.Prop = Communication.Proto.PropType.Spear; | |||
| break; | |||
| default: | |||
| msg.MessageOfCharacter.Prop = Communication.Proto.PropType.NullPropType; | |||
| msg.Prop = PropType.NullPropType; | |||
| break; | |||
| } | |||
| } | |||
| switch (player.PassiveSkillType) | |||
| }*/ | |||
| /*switch (player.PassiveSkillType) 需要对接一下,proto里似乎没有这个 | |||
| { | |||
| case Preparation.Utility.PassiveSkillType.RecoverAfterBattle: | |||
| msg.MessageOfCharacter.PassiveSkillType = Communication.Proto.PassiveSkillType.RecoverAfterBattle; | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.RecoverAfterBattle; | |||
| break; | |||
| case Preparation.Utility.PassiveSkillType.SpeedUpWhenLeavingGrass: | |||
| msg.MessageOfCharacter.PassiveSkillType = Communication.Proto.PassiveSkillType.SpeedUpWhenLeavingGrass; | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.SpeedUpWhenLeavingGrass; | |||
| break; | |||
| case Preparation.Utility.PassiveSkillType.Vampire: | |||
| msg.MessageOfCharacter.PassiveSkillType = Communication.Proto.PassiveSkillType.Vampire; | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.Vampire; | |||
| break; | |||
| default: | |||
| msg.MessageOfCharacter.PassiveSkillType = Communication.Proto.PassiveSkillType.NullPassiveSkillType; | |||
| msg.MessageOfHuman.PassiveSkillType = Communication.Proto.PassiveSkillType.NullPassiveSkillType; | |||
| break; | |||
| } | |||
| switch (player.CommonSkillType) | |||
| { | |||
| case Preparation.Utility.ActiveSkillType.BecomeAssassin: | |||
| msg.MessageOfCharacter.ActiveSkillType = Communication.Proto.ActiveSkillType.BecomeAssassin; | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.BecomeAssassin; | |||
| break; | |||
| case Preparation.Utility.ActiveSkillType.BecomeVampire: | |||
| msg.MessageOfCharacter.ActiveSkillType = Communication.Proto.ActiveSkillType.BecomeVampire; | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.BecomeVampire; | |||
| break; | |||
| case Preparation.Utility.ActiveSkillType.NuclearWeapon: | |||
| msg.MessageOfCharacter.ActiveSkillType = Communication.Proto.ActiveSkillType.NuclearWeapon; | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.NuclearWeapon; | |||
| break; | |||
| case Preparation.Utility.ActiveSkillType.SuperFast: | |||
| msg.MessageOfCharacter.ActiveSkillType = Communication.Proto.ActiveSkillType.SuperFast; | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.SuperFast; | |||
| break; | |||
| default: | |||
| msg.MessageOfCharacter.ActiveSkillType = Communication.Proto.ActiveSkillType.NullActiveSkillType; | |||
| msg.MessageOfHuman.ActiveSkillType = Communication.Proto.ActiveSkillType.NullActiveSkillType; | |||
| break; | |||
| } | |||
| switch (player.BulletOfPlayer) | |||
| { | |||
| case Preparation.Utility.BulletType.AtomBomb: | |||
| msg.MessageOfCharacter.BulletType = Communication.Proto.BulletType.AtomBomb; | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.AtomBomb; | |||
| break; | |||
| case Preparation.Utility.BulletType.OrdinaryBullet: | |||
| msg.MessageOfCharacter.BulletType = Communication.Proto.BulletType.OrdinaryBullet; | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.OrdinaryBullet; | |||
| break; | |||
| case Preparation.Utility.BulletType.FastBullet: | |||
| msg.MessageOfCharacter.BulletType = Communication.Proto.BulletType.FastBullet; | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.FastBullet; | |||
| break; | |||
| case Preparation.Utility.BulletType.LineBullet: | |||
| msg.MessageOfCharacter.BulletType = Communication.Proto.BulletType.LineBullet; | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.LineBullet; | |||
| break; | |||
| default: | |||
| msg.MessageOfCharacter.BulletType = Communication.Proto.BulletType.NullBulletType; | |||
| msg.MessageOfHuman.BulletType = Communication.Proto.BulletType.NullBulletType; | |||
| break; | |||
| } | |||
| }*/ | |||
| return msg; | |||
| } | |||
| private static MessageToClient.Types.GameObjMessage Bullet(Bullet bullet) | |||
| /*private static MessageToClient.Types.GameObjMessage Bullet(Bullet bullet) | |||
| { | |||
| MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage(); | |||
| msg.MessageOfBullet = new MessageOfBullet(); | |||
| @@ -229,39 +408,47 @@ namespace Server | |||
| break; | |||
| } | |||
| return msg; | |||
| } | |||
| }*/ | |||
| private static MessageToClient.Types.GameObjMessage Prop(Prop prop) | |||
| private static MessageOfProp Prop(Prop prop) | |||
| { | |||
| MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage(); | |||
| msg.MessageOfProp = new MessageOfProp(); | |||
| MessageOfProp msg = new MessageOfProp(); | |||
| //msg.Type = PropType.NullPropType; 下面写 | |||
| msg.X = prop.Position.x; | |||
| msg.Y = prop.Position.y; | |||
| msg.FacingDirection = 0; | |||
| msg.Guid = 0; | |||
| msg.Place = PlaceType.NullPlaceType; | |||
| msg.Size = 0; | |||
| msg.IsMoving = false; | |||
| /* THUAI5中的内容 | |||
| msg.MessageOfProp.FacingDirection = prop.FacingDirection; | |||
| msg.MessageOfProp.Guid = prop.ID; | |||
| msg.MessageOfProp.IsMoving = prop.IsMoving; | |||
| msg.MessageOfProp.IsMoving = prop.IsMoving;*/ | |||
| switch (prop.GetPropType()) | |||
| { | |||
| case Preparation.Utility.PropType.Gem: | |||
| msg.MessageOfProp.Type = Communication.Proto.PropType.Gem; | |||
| /*case Preparation.Utility.PropType.Gem: | |||
| msg.Type = PropType.Gem; | |||
| break; | |||
| case Preparation.Utility.PropType.addLIFE: | |||
| msg.MessageOfProp.Type = Communication.Proto.PropType.AddLife; | |||
| msg.Type = PropType.AddLife; | |||
| break; | |||
| case Preparation.Utility.PropType.addSpeed: | |||
| msg.MessageOfProp.Type = Communication.Proto.PropType.AddSpeed; | |||
| msg.Type = PropType.AddSpeed; | |||
| break; | |||
| case Preparation.Utility.PropType.Shield: | |||
| msg.MessageOfProp.Type = Communication.Proto.PropType.Shield; | |||
| msg.Type = PropType.Shield; | |||
| break; | |||
| case Preparation.Utility.PropType.Spear: | |||
| msg.MessageOfProp.Type = Communication.Proto.PropType.Spear; | |||
| break; | |||
| msg.Type = PropType.Spear; | |||
| break;*/ | |||
| default: | |||
| msg.MessageOfProp.Type = Communication.Proto.PropType.NullPropType; | |||
| msg.Type = PropType.NullPropType; | |||
| break; | |||
| } | |||
| msg.MessageOfProp.X = prop.Position.x; | |||
| msg.MessageOfProp.Y = prop.Position.y; | |||
| if(prop is Gem) | |||
| /*if(prop is Gem) | |||
| { | |||
| msg.MessageOfProp.Size = ((Gem)prop).Size; | |||
| } | |||
| @@ -286,20 +473,19 @@ namespace Server | |||
| default: | |||
| msg.MessageOfProp.Place = Communication.Proto.PlacccceType.NullPlaceType; | |||
| break; | |||
| } | |||
| }*/ | |||
| return msg; | |||
| } | |||
| private static MessageToClient.Types.GameObjMessage BombedBullet(BombedBullet bombedBullet) | |||
| /*private static MessageOfBombedBullet BombedBullet(BombedBullet bombedBullet) | |||
| { | |||
| MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage(); | |||
| msg.MessageOfBombedBullet = new MessageOfBombedBullet(); | |||
| MessageOfBombedBullet msg = new MessageOfBombedBullet; | |||
| msg.MessageOfBombedBullet.FacingDirection = bombedBullet.bulletHasBombed.FacingDirection; | |||
| msg.MessageOfBombedBullet.X = bombedBullet.bulletHasBombed.Position.x; | |||
| msg.MessageOfBombedBullet.Y = bombedBullet.bulletHasBombed.Position.y; | |||
| msg.MessageOfBombedBullet.MappingID = bombedBullet.MappingID; | |||
| msg.MessageOfBombedBullet.BombRange = BulletFactory.BulletBombRange(bombedBullet.bulletHasBombed.TypeOfBullet); | |||
| msg.FacingDirection = bombedBullet.FacingDirection; | |||
| msg.X = bombedBullet.bulletHasBombed.Position.x; | |||
| msg.Y = bombedBullet.bulletHasBombed.Position.y; | |||
| msg.MappingID = bombedBullet.MappingID; | |||
| msg.BombRange = BulletFactory.BulletBombRange(bombedBullet.bulletHasBombed.TypeOfBullet); | |||
| switch (bombedBullet.bulletHasBombed.TypeOfBullet) | |||
| { | |||
| case Preparation.Utility.BulletType.OrdinaryBullet: | |||
| @@ -319,9 +505,9 @@ namespace Server | |||
| break; | |||
| } | |||
| return msg; | |||
| } | |||
| }*/ | |||
| private static MessageToClient.Types.GameObjMessage PickedProp(PickedProp pickedProp) | |||
| /*private static MessageToClient.Types.GameObjMessage PickedProp(PickedProp pickedProp) | |||
| { | |||
| MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage(); | |||
| msg.MessageOfPickedProp = new MessageOfPickedProp(); | |||
| @@ -352,7 +538,6 @@ namespace Server | |||
| break; | |||
| } | |||
| return msg; | |||
| } | |||
| }*/ | |||
| } | |||
| }*/ | |||
| // 等Preparation完成再写 | |||
| } | |||
| @@ -6,6 +6,8 @@ using System; | |||
| using System.Net.Http.Headers; | |||
| using Gaming; | |||
| using GameClass.GameObj; | |||
| using Preparation.Utility; | |||
| namespace Server | |||
| { | |||
| @@ -13,9 +15,17 @@ namespace Server | |||
| { | |||
| private Dictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new(); | |||
| private object gameLock = new(); | |||
| private const int playerNum = 2; // 注意修改 | |||
| private const int playerNum = 1; // 注意修改 | |||
| private MessageToClient currentGameInfo = new(); | |||
| private SemaphoreSlim endGameSem = new(0); | |||
| object gameInfo = new(); | |||
| private int isGaming = 0; | |||
| public bool IsGaming | |||
| { | |||
| get => Interlocked.CompareExchange(ref isGaming, 0, 0) != 0; | |||
| set => Interlocked.Exchange(ref isGaming, value ? 1 : 0); | |||
| } | |||
| // 以上是测试时用到的定义 | |||
| protected readonly ArgumentOptions options; | |||
| @@ -29,6 +39,46 @@ namespace Server | |||
| private readonly Semaphore endGameInfoSema = new(0, 1); | |||
| // private MessageWriter? mwr = null; | |||
| public SemaphoreSlim StartGameTest() | |||
| { | |||
| IsGaming = true; | |||
| var waitHandle = new SemaphoreSlim(0); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| () => IsGaming, | |||
| () => | |||
| { | |||
| lock (gameInfo) | |||
| { | |||
| /*for (int i = 0; i < gameInfo.GameObjs.Count; i++) | |||
| { | |||
| if (gameInfo.GameObjs[i].Character != null) | |||
| { | |||
| gameInfo.GameObjs[i].Character.X++; | |||
| gameInfo.GameObjs[i].Character.Y--; | |||
| } | |||
| }*/ | |||
| } | |||
| }, | |||
| 100, | |||
| () => | |||
| { | |||
| IsGaming = false; | |||
| waitHandle.Release(); | |||
| return 0; | |||
| }, | |||
| 3000//gameTime | |||
| ).Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return waitHandle; | |||
| } | |||
| public void StartGame() | |||
| { | |||
| bool gameState = game.StartGame((int)options.GameTimeInSecond * 1000); | |||
| @@ -63,9 +113,7 @@ namespace Server | |||
| public void ReportGame() | |||
| { | |||
| // currentGameInfo = game.GetCopiedGameInfo(); | |||
| currentGameInfo.HumanMessage[0].X = 1; | |||
| currentGameInfo.ButcherMessage[0].X = 1; | |||
| //currentGameInfo = null; | |||
| foreach (var kvp in semaDict) | |||
| { | |||
| @@ -77,13 +125,29 @@ namespace Server | |||
| kvp.Value.Item2.Wait(); | |||
| } | |||
| } | |||
| private uint GetBirthPointIdx(long teamID, long playerID) // 获取出生点位置 | |||
| private int PlayerTypeToTeamID(PlayerType playerType) | |||
| { | |||
| return (uint)((teamID * options.PlayerCountPerTeam) + playerID); | |||
| if (playerType == PlayerType.StudentPlayer) return 0; | |||
| if (playerType == PlayerType.TrickerPlayer) return 1; | |||
| return -1; | |||
| } | |||
| private uint GetBirthPointIdx(PlayerType playerType, long playerID) // 获取出生点位置 | |||
| { | |||
| return (uint)((PlayerTypeToTeamID(playerType) * options.PlayerCountPerTeam) + playerID + 1); | |||
| } | |||
| private bool ValidPlayerTypeAndPlayerID(PlayerType playerType, long playerID) | |||
| { | |||
| if (playerType == PlayerType.StudentPlayer && 0 <= playerID && playerID < options.PlayerCountPerTeam) | |||
| return true; // 人数待修改 | |||
| if (playerType == PlayerType.TrickerPlayer && 0 <= playerID && playerID < options.PlayerCountPerTeam) | |||
| return true; | |||
| return false; | |||
| } | |||
| public override Task<BoolRes> TryConnection(IDMsg request, ServerCallContext context) | |||
| { | |||
| Console.WriteLine($"TryConnection ID: {request.PlayerId}"); | |||
| var onConnection = new BoolRes(); | |||
| lock (gameLock) | |||
| { | |||
| @@ -101,6 +165,7 @@ namespace Server | |||
| protected readonly object addPlayerLock = new(); | |||
| public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter<MessageToClient> responseStream, ServerCallContext context) | |||
| { | |||
| Console.WriteLine($"AddPlayer: {request.PlayerId}"); | |||
| if (request.PlayerId >= spectatorMinPlayerID && request.PlayerType == PlayerType.NullPlayerType) | |||
| { | |||
| // 观战模式 | |||
| @@ -115,23 +180,23 @@ namespace Server | |||
| if (game.GameMap.Timer.IsGaming) | |||
| return; | |||
| /*if (!ValidTeamIDAndPlayerID(msg.TeamID, msg.PlayerID)) //玩家id是否正确 | |||
| return; | |||
| if (communicationToGameID[msg.TeamID, msg.PlayerID] != GameObj.invalidID) //是否已经添加了该玩家 | |||
| return false; | |||
| if (!ValidPlayerTypeAndPlayerID(request.PlayerType, request.PlayerId)) //玩家id是否正确 | |||
| return; | |||
| //if (communicationToGameID[PlayerTypeToTeamID(request.PlayerType), request.PlayerId] != GameObj.invalidID) //是否已经添加了该玩家 | |||
| //return; | |||
| Preparation.Utility.CharacterType characterType = Preparation.Utility.CharacterType.Athlete; // 待修改 | |||
| Preparation.Utility.PassiveSkillType passiveSkill; | |||
| */ | |||
| lock (addPlayerLock) | |||
| { | |||
| /*Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(msg.TeamID, msg.PlayerID), msg.TeamID, msg.PlayerID, passiveSkill, commonSkill); | |||
| Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerType, request.PlayerId), PlayerTypeToTeamID(request.PlayerType), request.PlayerId, characterType); | |||
| long newPlayerID = game.AddPlayer(playerInitInfo); | |||
| if (newPlayerID == GameObj.invalidID) | |||
| return false;*/ | |||
| //if (newPlayerID == GameObj.invalidID) | |||
| //return; | |||
| // 内容待修改 | |||
| var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1)); | |||
| bool start = false; | |||
| Console.WriteLine($"Id: {request.PlayerId} joins."); | |||
| Console.WriteLine($"PlayerType: {request.PlayerType} Id: {request.PlayerId} joins."); | |||
| lock (semaDict) | |||
| { | |||
| semaDict.Add(request.PlayerId, temp); | |||
| @@ -157,29 +222,12 @@ namespace Server | |||
| } while (game.GameMap.Timer.IsGaming); | |||
| } | |||
| public override Task<BoolRes> Attack(AttackMsg request, ServerCallContext context) | |||
| { | |||
| return base.Attack(request, context); | |||
| } | |||
| public override Task<BoolRes> CarryHuman(IDMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> Trick(TrickMsg request, ServerCallContext context) | |||
| { | |||
| return base.CarryHuman(request, context); | |||
| } | |||
| public override Task<BoolRes> EndFixMachine(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.EndFixMachine(request, context); | |||
| } | |||
| public override Task<BoolRes> EndSaveHuman(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.EndSaveHuman(request, context); | |||
| } | |||
| public override Task<BoolRes> Escape(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.Escape(request, context); | |||
| game.Attack(request.PlayerId, request.Angle); | |||
| BoolRes boolRes = new(); | |||
| boolRes.ActSuccess = true; | |||
| return Task.FromResult(boolRes); | |||
| } | |||
| public override Task GetMessage(IDMsg request, IServerStreamWriter<MsgRes> responseStream, ServerCallContext context) | |||
| @@ -187,57 +235,62 @@ namespace Server | |||
| return base.GetMessage(request, responseStream, context); | |||
| } | |||
| public override Task<BoolRes> HangHuman(IDMsg request, ServerCallContext context) | |||
| public override Task<MoveRes> Move(MoveMsg request, ServerCallContext context) | |||
| { | |||
| return base.HangHuman(request, context); | |||
| Console.WriteLine($"Move ID: {request.PlayerId}, TimeInMilliseconds: {request.TimeInMilliseconds}"); | |||
| game.MovePlayer(request.PlayerId, (int)request.TimeInMilliseconds, request.Angle); | |||
| // 之后game.MovePlayer可能改为bool类型 | |||
| MoveRes moveRes = new(); | |||
| moveRes.ActSuccess = true; | |||
| return Task.FromResult(moveRes); | |||
| } | |||
| public override Task<MoveRes> Move(MoveMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> PickProp(PropMsg request, ServerCallContext context) | |||
| { | |||
| return base.Move(request, context); | |||
| BoolRes boolRes = new(); | |||
| if (request.PropType == Protobuf.PropType.NullPropType) | |||
| boolRes.ActSuccess = game.PickProp(request.PlayerId, Preparation.Utility.PropType.Null); | |||
| return Task.FromResult(boolRes); | |||
| } | |||
| public override Task<BoolRes> PickProp(PickMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> SendMessage(SendMsg request, ServerCallContext context) | |||
| { | |||
| return base.PickProp(request, context); | |||
| return base.SendMessage(request, context); | |||
| } | |||
| public override Task<BoolRes> ReleaseHuman(IDMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> UseProp(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.ReleaseHuman(request, context); | |||
| return base.UseProp(request, context); | |||
| } | |||
| public override Task<BoolRes> SendMessage(SendMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> UseSkill(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.SendMessage(request, context); | |||
| return base.UseSkill(request, context); | |||
| } | |||
| public override Task<BoolRes> StartFixMachine(IDMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> Graduate(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.StartFixMachine(request, context); | |||
| return base.Graduate(request, context); | |||
| } | |||
| public override Task<BoolRes> StartSaveHuman(IDMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> StartHealMate(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.StartSaveHuman(request, context); | |||
| return base.StartHealMate(request, context); | |||
| } | |||
| public override Task<BoolRes> UseProp(IDMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> StartHelpMate(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.UseProp(request, context); | |||
| return base.StartHelpMate(request, context); | |||
| } | |||
| public override Task<BoolRes> UseSkill(IDMsg request, ServerCallContext context) | |||
| public override Task<BoolRes> StartLearning(IDMsg request, ServerCallContext context) | |||
| { | |||
| return base.UseSkill(request, context); | |||
| return base.StartLearning(request, context); | |||
| } | |||
| public GameServer(ArgumentOptions options) | |||
| { | |||
| /*this.options = options; | |||
| if (options.mapResource == DefaultArgumentOptions.MapResource) | |||
| this.game = new Game(MapInfo.defaultMap, options.TeamCount); | |||
| else | |||
| this.options = options; | |||
| //if (options.mapResource == DefaultArgumentOptions.MapResource) | |||
| // this.game = new Game(MapInfo.defaultMap, options.TeamCount); | |||
| //else | |||
| { | |||
| uint[,] map = new uint[GameData.rows, GameData.cols]; | |||
| try | |||
| @@ -305,7 +358,7 @@ namespace Server | |||
| if (options.Url != DefaultArgumentOptions.Url && options.Token != DefaultArgumentOptions.Token) | |||
| { | |||
| //this.httpSender = new HttpSender(options.Url, options.Token, "PUT"); | |||
| }*/ | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| { | |||
| "profiles": { | |||
| "Server": { | |||
| "commandName": "Project", | |||
| "commandLineArgs": "-p 8888" | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,134 @@ | |||
| using Communication.Proto; | |||
| using Google.Protobuf; | |||
| using System; | |||
| using System.IO; | |||
| using System.IO.Compression; | |||
| namespace Playback | |||
| { | |||
| public class FileFormatNotLegalException : Exception | |||
| { | |||
| private readonly string fileName; | |||
| public FileFormatNotLegalException(string fileName) | |||
| { | |||
| this.fileName = fileName; | |||
| } | |||
| public override string Message => $"The file: " + this.fileName + " is not a legal playback file for THUAI6."; | |||
| } | |||
| public class MessageReader : IDisposable | |||
| { | |||
| private FileStream? fs; | |||
| private CodedInputStream cos; | |||
| private GZipStream gzs; | |||
| private byte[] buffer; | |||
| public bool Finished { get; private set; } = false; | |||
| public readonly uint teamCount; | |||
| public readonly uint playerCount; | |||
| const int bufferMaxSize = 1024 * 1024; // 1M | |||
| public MessageReader(string fileName) | |||
| { | |||
| if (!fileName.EndsWith(PlayBackConstant.ExtendedName)) | |||
| { | |||
| fileName += PlayBackConstant.ExtendedName; | |||
| } | |||
| fs = new FileStream(fileName, FileMode.Open, FileAccess.Read); | |||
| try | |||
| { | |||
| var prefixLen = PlayBackConstant.Prefix.Length; | |||
| byte[] bt = new byte[prefixLen + sizeof(UInt32) * 2]; | |||
| fs.Read(bt, 0, bt.Length); | |||
| for (int i = 0; i < prefixLen; ++i) | |||
| { | |||
| if (bt[i] != PlayBackConstant.Prefix[i]) throw new FileFormatNotLegalException(fileName); | |||
| } | |||
| teamCount = BitConverter.ToUInt32(bt, prefixLen); | |||
| playerCount = BitConverter.ToUInt32(bt, prefixLen + sizeof(UInt32)); | |||
| } | |||
| catch | |||
| { | |||
| throw new FileFormatNotLegalException(fileName); | |||
| } | |||
| gzs = new GZipStream(fs, CompressionMode.Decompress); | |||
| var tmpBuffer = new byte[bufferMaxSize]; | |||
| var bufferSize = gzs.Read(tmpBuffer); | |||
| if (bufferSize == 0) | |||
| { | |||
| buffer = tmpBuffer; | |||
| Finished = true; | |||
| } | |||
| else if (bufferSize != bufferMaxSize) // 不留空位,防止 CodedInputStream 获取信息错误 | |||
| { | |||
| if (bufferSize == 0) | |||
| { | |||
| Finished = true; | |||
| } | |||
| buffer = new byte[bufferSize]; | |||
| Array.Copy(tmpBuffer, buffer, bufferSize); | |||
| } | |||
| else | |||
| { | |||
| buffer = tmpBuffer; | |||
| } | |||
| cos = new CodedInputStream(buffer); | |||
| } | |||
| public MessageToClient? ReadOne() | |||
| { | |||
| beginRead: | |||
| if (Finished) return null; | |||
| var pos = cos.Position; | |||
| try | |||
| { | |||
| MessageToClient? msg = new MessageToClient(); | |||
| cos.ReadMessage(msg); | |||
| return msg; | |||
| } | |||
| catch (InvalidProtocolBufferException) | |||
| { | |||
| var leftByte = buffer.Length - pos; // 上次读取剩余的字节 | |||
| for (int i = 0; i < leftByte; ++i) | |||
| { | |||
| buffer[i] = buffer[pos + i]; | |||
| } | |||
| var bufferSize = gzs.Read(buffer, (int)leftByte, (int)(buffer.Length - leftByte)) + leftByte; | |||
| if (bufferSize == leftByte) | |||
| { | |||
| Finished = true; | |||
| return null; | |||
| } | |||
| if (bufferSize != buffer.Length) // 不留空位,防止 CodedInputStream 获取信息错误 | |||
| { | |||
| var tmpBuffer = new byte[bufferSize]; | |||
| Array.Copy(buffer, tmpBuffer, bufferSize); | |||
| buffer = tmpBuffer; | |||
| } | |||
| cos = new CodedInputStream(buffer); | |||
| goto beginRead; | |||
| } | |||
| } | |||
| public void Dispose() | |||
| { | |||
| Finished = true; | |||
| if (fs == null) | |||
| return; | |||
| if (fs.CanRead) | |||
| { | |||
| fs.Close(); | |||
| } | |||
| } | |||
| ~MessageReader() | |||
| { | |||
| Dispose(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,74 @@ | |||
| using Communication.Proto; | |||
| using Google.Protobuf; | |||
| using System; | |||
| using System.IO; | |||
| using System.IO.Compression; | |||
| namespace Playback | |||
| { | |||
| public class MessageWriter : IDisposable | |||
| { | |||
| private FileStream fs; | |||
| private CodedOutputStream cos; | |||
| private MemoryStream ms; | |||
| private GZipStream gzs; | |||
| private const int memoryCapacity = 1024 * 1024; // 1M | |||
| private static void ClearMemoryStream(MemoryStream msToClear) | |||
| { | |||
| msToClear.Position = 0; | |||
| msToClear.SetLength(0); | |||
| } | |||
| public MessageWriter(string fileName, uint teamCount, uint playerCount) | |||
| { | |||
| if (!fileName.EndsWith(PlayBackConstant.ExtendedName)) | |||
| { | |||
| fileName += PlayBackConstant.ExtendedName; | |||
| } | |||
| fs = new FileStream(fileName, FileMode.Create, FileAccess.Write); | |||
| fs.Write(PlayBackConstant.Prefix); // 写入前缀 | |||
| fs.Write(BitConverter.GetBytes((UInt32)teamCount)); // 写入队伍数 | |||
| fs.Write(BitConverter.GetBytes((UInt32)playerCount)); // 写入每队的玩家人数 | |||
| ms = new MemoryStream(memoryCapacity); | |||
| cos = new CodedOutputStream(ms); | |||
| gzs = new GZipStream(fs, CompressionMode.Compress); | |||
| } | |||
| public void WriteOne(MessageToClient msg) | |||
| { | |||
| cos.WriteMessage(msg); | |||
| if (ms.Length > memoryCapacity) | |||
| Flush(); | |||
| } | |||
| public void Flush() | |||
| { | |||
| if (fs.CanWrite) | |||
| { | |||
| cos.Flush(); | |||
| gzs.Write(ms.GetBuffer(), 0, (int)ms.Length); | |||
| ClearMemoryStream(ms); | |||
| fs.Flush(); | |||
| } | |||
| } | |||
| public void Dispose() | |||
| { | |||
| if (fs.CanWrite) | |||
| { | |||
| Flush(); | |||
| cos.Dispose(); | |||
| gzs.Dispose(); | |||
| fs.Dispose(); | |||
| } | |||
| } | |||
| ~MessageWriter() | |||
| { | |||
| Dispose(); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,6 +0,0 @@ | |||
| namespace Playback | |||
| { | |||
| public class Playback | |||
| { | |||
| } | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <TargetFramework>net6.0</TargetFramework> | |||
| <TargetFrameworks>net6.0;netstandard2.1</TargetFrameworks> | |||
| <ImplicitUsings>enable</ImplicitUsings> | |||
| <Nullable>enable</Nullable> | |||
| </PropertyGroup> | |||
| @@ -0,0 +1,8 @@ | |||
| namespace Playback | |||
| { | |||
| public static class PlayBackConstant | |||
| { | |||
| public static string ExtendedName = ".thuaipb"; | |||
| public static byte[] Prefix = { (byte)'P', (byte)'B', 6, 0 }; // 文件前缀,用于标识文件类型,版本号为6 | |||
| } | |||
| } | |||