Browse Source

Merge branch 'new' of github.com:shangfengh/THUAI6 into new

tags/0.1.0
shangfengh 2 years ago
parent
commit
ce67c3c9df
19 changed files with 565 additions and 359 deletions
  1. +24
    -0
      .github/workflows/build.yml
  2. +47
    -1
      CAPI/cpp/API/include/API.h
  3. +7
    -0
      CAPI/cpp/API/include/logic.h
  4. +78
    -0
      CAPI/cpp/API/src/API.cpp
  5. +82
    -0
      CAPI/cpp/API/src/DebugAPI.cpp
  6. +36
    -0
      CAPI/cpp/API/src/logic.cpp
  7. +5
    -0
      README.md
  8. +3
    -3
      dependency/proto/Message2Clients.proto
  9. +9
    -17
      dependency/proto/Message2Server.proto
  10. +5
    -7
      logic/ClientTest/Program.cs
  11. +1
    -0
      logic/Gaming/Game.cs
  12. +140
    -288
      logic/Server/CopyInfo.cs
  13. +107
    -37
      logic/Server/GameServer.cs
  14. +1
    -1
      logic/Server/Program.cs
  15. +1
    -0
      logic/Server/Server.csproj
  16. +6
    -0
      logic/logic.sln
  17. +2
    -2
      playback/Playback/MessageReader.cs
  18. +1
    -1
      playback/Playback/MessageWriter.cs
  19. +10
    -2
      playback/Playback/Playback.csproj

+ 24
- 0
.github/workflows/build.yml View File

@@ -0,0 +1,24 @@
name: build
on: [push, pull_request]
jobs:
dotnet-build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Build Logic
run: dotnet build "./logic/logic.sln" -c Release
- name: Build Installer
run: dotnet build "./installer/installer.sln" -c Release
- name: Build Launcher
run: dotnet build "./launcher/launcher.sln" -c Release
- name: Build Playback
run: dotnet build "./playback/playback.sln" -c Release

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

@@ -61,6 +61,13 @@ public:
virtual bool StartTreatMate() = 0;
virtual bool StartRescueMate() = 0;

virtual bool OpenDoor() = 0;
virtual bool CloseDoor() = 0;
virtual bool SkipWindow() = 0;
virtual bool StartOpenGate() = 0;
virtual bool StartOpenChest() = 0;
virtual bool EndAllAction() = 0;

// ITrickerAPI使用的部分
virtual bool Attack(double angle) = 0;

@@ -84,6 +91,14 @@ public:
virtual std::future<bool> PickProp(THUAI6::PropType prop) = 0;
virtual std::future<bool> UseProp(THUAI6::PropType prop) = 0;
virtual std::future<bool> UseSkill(int32_t skillID) = 0;
virtual std::future<bool> Attack(double angleInRadian) = 0;

virtual std::future<bool> OpenDoor() = 0;
virtual std::future<bool> CloseDoor() = 0;
virtual std::future<bool> SkipWindow() = 0;
virtual std::future<bool> StartOpenGate() = 0;
virtual std::future<bool> StartOpenChest() = 0;
virtual std::future<bool> EndAllAction() = 0;

// 发送信息、接受信息,注意收消息时无消息则返回nullopt
virtual std::future<bool> SendMessage(int64_t, std::string) = 0;
@@ -149,7 +164,6 @@ class ITrickerAPI : public IAPI
public:
/*****捣蛋鬼阵营的特定函数*****/

virtual std::future<bool> Attack(double angleInRadian) = 0;
[[nodiscard]] virtual std::shared_ptr<const THUAI6::Tricker> GetSelfInfo() const = 0;
};

@@ -190,6 +204,15 @@ public:
std::future<bool> UseProp(THUAI6::PropType prop) override;
std::future<bool> UseSkill(int32_t skillID) override;

std::future<bool> Attack(double angleInRadian) override;

std::future<bool> OpenDoor() override;
std::future<bool> CloseDoor() override;
std::future<bool> SkipWindow() override;
std::future<bool> StartOpenGate() override;
std::future<bool> StartOpenChest() override;
std::future<bool> EndAllAction() override;

std::future<bool> SendMessage(int64_t, std::string) override;
[[nodiscard]] std::future<bool> HaveMessage() override;
[[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override;
@@ -256,6 +279,13 @@ public:
std::future<bool> UseProp(THUAI6::PropType prop) override;
std::future<bool> UseSkill(int32_t skillID) override;

std::future<bool> OpenDoor() override;
std::future<bool> CloseDoor() override;
std::future<bool> SkipWindow() override;
std::future<bool> StartOpenGate() override;
std::future<bool> StartOpenChest() override;
std::future<bool> EndAllAction() override;

std::future<bool> SendMessage(int64_t, std::string) override;
[[nodiscard]] std::future<bool> HaveMessage() override;
[[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override;
@@ -312,6 +342,15 @@ public:
std::future<bool> UseProp(THUAI6::PropType prop) override;
std::future<bool> UseSkill(int32_t skillID) override;

std::future<bool> Attack(double angleInRadian) override;

std::future<bool> OpenDoor() override;
std::future<bool> CloseDoor() override;
std::future<bool> SkipWindow() override;
std::future<bool> StartOpenGate() override;
std::future<bool> StartOpenChest() override;
std::future<bool> EndAllAction() override;

std::future<bool> SendMessage(int64_t, std::string) override;
[[nodiscard]] std::future<bool> HaveMessage() override;
[[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override;
@@ -365,6 +404,13 @@ public:
std::future<bool> UseProp(THUAI6::PropType prop) override;
std::future<bool> UseSkill(int32_t skillID) override;

std::future<bool> OpenDoor() override;
std::future<bool> CloseDoor() override;
std::future<bool> SkipWindow() override;
std::future<bool> StartOpenGate() override;
std::future<bool> StartOpenChest() override;
std::future<bool> EndAllAction() override;

std::future<bool> SendMessage(int64_t, std::string) override;
[[nodiscard]] std::future<bool> HaveMessage() override;
[[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override;


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

@@ -118,6 +118,13 @@ private:

bool Attack(double angle) override;

bool OpenDoor() override;
bool CloseDoor() override;
bool SkipWindow() override;
bool StartOpenGate() override;
bool StartOpenChest() override;
bool EndAllAction() override;

bool WaitThread() override;

int GetCounter() const override;


+ 78
- 0
CAPI/cpp/API/src/API.cpp View File

@@ -101,6 +101,78 @@ std::future<bool> TrickerAPI::UseSkill(int32_t skillID)
{ return logic.UseSkill(skillID); });
}

std::future<bool> StudentAPI::OpenDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.OpenDoor(); });
}

std::future<bool> TrickerAPI::OpenDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.OpenDoor(); });
}

std::future<bool> StudentAPI::CloseDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.CloseDoor(); });
}

std::future<bool> TrickerAPI::CloseDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.CloseDoor(); });
}

std::future<bool> StudentAPI::SkipWindow()
{
return std::async(std::launch::async, [&]()
{ return logic.SkipWindow(); });
}

std::future<bool> TrickerAPI::SkipWindow()
{
return std::async(std::launch::async, [&]()
{ return logic.SkipWindow(); });
}

std::future<bool> StudentAPI::StartOpenGate()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenGate(); });
}

std::future<bool> TrickerAPI::StartOpenGate()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenGate(); });
}

std::future<bool> StudentAPI::StartOpenChest()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenChest(); });
}

std::future<bool> TrickerAPI::StartOpenChest()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenChest(); });
}

std::future<bool> StudentAPI::EndAllAction()
{
return std::async(std::launch::async, [&]()
{ return logic.EndAllAction(); });
}

std::future<bool> TrickerAPI::EndAllAction()
{
return std::async(std::launch::async, [&]()
{ return logic.EndAllAction(); });
}

std::future<bool> StudentAPI::SendMessage(int64_t toID, std::string message)
{
return std::async(std::launch::async, [&]()
@@ -252,6 +324,12 @@ std::future<bool> TrickerAPI::Attack(double angleInRadian)
{ return logic.Attack(angleInRadian); });
}

std::future<bool> StudentAPI::Attack(double angleInRadian)
{
return std::async(std::launch::async, [&]()
{ return logic.Attack(angleInRadian); });
}

std::shared_ptr<const THUAI6::Tricker> TrickerAPI::GetSelfInfo() const
{
return logic.TrickerGetSelfInfo();


+ 82
- 0
CAPI/cpp/API/src/DebugAPI.cpp View File

@@ -206,6 +206,78 @@ std::future<bool> TrickerDebugAPI::UseSkill(int32_t skillID)
return result; });
}

std::future<bool> StudentDebugAPI::OpenDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.OpenDoor(); });
}

std::future<bool> TrickerDebugAPI::OpenDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.OpenDoor(); });
}

std::future<bool> StudentDebugAPI::CloseDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.CloseDoor(); });
}

std::future<bool> TrickerDebugAPI::CloseDoor()
{
return std::async(std::launch::async, [&]()
{ return logic.CloseDoor(); });
}

std::future<bool> StudentDebugAPI::SkipWindow()
{
return std::async(std::launch::async, [&]()
{ return logic.SkipWindow(); });
}

std::future<bool> TrickerDebugAPI::SkipWindow()
{
return std::async(std::launch::async, [&]()
{ return logic.SkipWindow(); });
}

std::future<bool> StudentDebugAPI::StartOpenGate()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenGate(); });
}

std::future<bool> TrickerDebugAPI::StartOpenGate()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenGate(); });
}

std::future<bool> StudentDebugAPI::StartOpenChest()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenChest(); });
}

std::future<bool> TrickerDebugAPI::StartOpenChest()
{
return std::async(std::launch::async, [&]()
{ return logic.StartOpenChest(); });
}

std::future<bool> StudentDebugAPI::EndAllAction()
{
return std::async(std::launch::async, [&]()
{ return logic.EndAllAction(); });
}

std::future<bool> TrickerDebugAPI::EndAllAction()
{
return std::async(std::launch::async, [&]()
{ return logic.EndAllAction(); });
}

std::future<bool> StudentDebugAPI::SendMessage(int64_t toID, std::string message)
{
logger->info("SendMessage: toID = {}, message = {}, called at {}ms", toID, message, Time::TimeSinceStart(startPoint));
@@ -403,6 +475,16 @@ std::future<bool> TrickerDebugAPI::Attack(double angleInRadian)
return result; });
}

std::future<bool> StudentDebugAPI::Attack(double angleInRadian)
{
logger->info("Attack: angleInRadian = {}, called at {}ms", angleInRadian, Time::TimeSinceStart(startPoint));
return std::async(std::launch::async, [=]()
{ auto result = logic.Attack(angleInRadian);
if (!result)
logger->warn("Attack: failed at {}ms", Time::TimeSinceStart(startPoint));
return result; });
}

std::shared_ptr<const THUAI6::Tricker> TrickerDebugAPI::GetSelfInfo() const
{
return logic.TrickerGetSelfInfo();


+ 36
- 0
CAPI/cpp/API/src/logic.cpp View File

@@ -147,6 +147,42 @@ bool Logic::Attack(double angle)
return pComm->Attack(angle, playerID);
}

bool Logic::OpenDoor()
{
logger->debug("Called OpenDoor");
return pComm->OpenDoor(playerID);
}

bool Logic::CloseDoor()
{
logger->debug("Called CloseDoor");
return pComm->CloseDoor(playerID);
}

bool Logic::SkipWindow()
{
logger->debug("Called SkipWindow");
return pComm->SkipWindow(playerID);
}

bool Logic::StartOpenGate()
{
logger->debug("Called StartOpenGate");
return pComm->StartOpenGate(playerID);
}

bool Logic::StartOpenChest()
{
logger->debug("Called StartOpenChest");
return pComm->StartOpenChest(playerID);
}

bool Logic::EndAllAction()
{
logger->debug("Called EndAllAction");
return pComm->EndAllAction(playerID);
}

bool Logic::WaitThread()
{
Update();


+ 5
- 0
README.md View File

@@ -1,10 +1,15 @@
# THUAI6

清华大学第六届人工智能挑战赛电子系赛道(原电子系第 24 届队式程序设计大赛 teamstyle24)

Gitee 镜像地址:[THUAI6: Gitee Mirror](https://gitee.com/eesast/THUAI6)

GitLink 镜像地址:[THUAI6: GitLink Mirror](https://www.gitlink.org.cn/EESAST/THUAI6)

项目主页:[THUAI6 Project Home Page](https://eesast.github.io/THUAI6)

关于本届及历届清华大学人工智能挑战赛与队式程序设计大赛的更多内容参见:[THUAI6 Github Wiki](https://github.com/eesast/THUAI6/wiki)

## 赛题背景

待定


+ 3
- 3
dependency/proto/Message2Clients.proto View File

@@ -10,8 +10,8 @@ message MessageOfStudent
int32 y = 2;
int32 speed = 3;
int32 determination = 4; // 剩余的学习毅力,相当于血量
int32 fail_num = 5; // 挂科的科目数
double time_until_skill_available = 6;
//int32 fail_num = 5; // 挂科的科目数
repeated double time_until_skill_available = 6;
PlaceType place = 7;
repeated PropType prop = 8;
PlayerState player_state = 9;
@@ -142,7 +142,6 @@ message MessageOfMap
repeated PlaceType col = 1;
}
repeated Row row = 2;
repeated MessageOfMapObj map_obj_message = 3;
}

message MessageOfObj
@@ -154,6 +153,7 @@ message MessageOfObj
MessageOfProp prop_message = 3;
MessageOfBullet bullet_message = 4;
MessageOfBombedBullet bombed_bullet_message = 5;
MessageOfMapObj map_obj_message = 6;
}
}



+ 9
- 17
dependency/proto/Message2Server.proto View File

@@ -7,56 +7,48 @@ import "MessageType.proto";
message PlayerMsg
{
int64 player_id = 1;
PlayerType player_type = 2;
oneof job_type
{
StudentType student_type = 3;
TrickerType tricker_type = 4;
StudentType student_type = 2;
TrickerType tricker_type = 3;
}
}

message MoveMsg
{
int64 player_id = 1;
PlayerType player_type = 2;
double angle = 3;
int64 time_in_milliseconds = 4;
double angle = 2;
int64 time_in_milliseconds = 3;
}

message PropMsg
{
int64 player_id = 1;
PlayerType player_type = 2;
PropType prop_type = 3;
PropType prop_type = 2;
}

message SendMsg
{
int64 player_id = 1;
PlayerType player_type = 2;
int64 to_player_id = 3;
PlayerType to_player_type = 4;
string message = 5;
int64 to_player_id = 2;
string message = 3;
}

message AttackMsg // 相当于攻击
{
int64 player_id = 1;
PlayerType player_type = 2;
double angle = 3;
double angle = 2;
}

message IDMsg
{
int64 player_id = 1;
PlayerType player_type = 2;
}

message SkillMsg
{
int64 player_id = 1;
PlayerType player_type = 2;
int32 skill_id = 3;
int32 skill_id = 2;
}

// 基本继承于THUAI5,为了使发送的信息尽可能不被浪费,暂定不发这类大包。


+ 5
- 7
logic/ClientTest/Program.cs View File

@@ -12,12 +12,10 @@ namespace ClientTest
var client = new AvailableService.AvailableServiceClient(channel);
PlayerMsg playerInfo = new();
playerInfo.PlayerId = 0;
playerInfo.PlayerType = PlayerType.StudentPlayer;
playerInfo.StudentType = StudentType.NullStudentType;
var call = client.AddPlayer(playerInfo);
MoveMsg moveMsg = new();
moveMsg.PlayerId = 0;
moveMsg.PlayerType = PlayerType.StudentPlayer;
moveMsg.TimeInMilliseconds = 100;
moveMsg.Angle = 0;
while (true)
@@ -29,15 +27,15 @@ namespace ClientTest

while (await call.ResponseStream.MoveNext())
{
Console.WriteLine("hi");
var currentGameInfo = call.ResponseStream.Current;
if (playerInfo.PlayerType == PlayerType.StudentPlayer)
for (int i = 0; i < currentGameInfo.ObjMessage.Count; i++)
{
for (int i = 0; i < currentGameInfo.ObjMessage.Count; i++)
{
//Console.WriteLine($"Human is at ({currentGameInfo.StudentMessage[i].X}, {currentGameInfo.StudentMessage[i].Y})");
}
if (currentGameInfo.ObjMessage[i].MessageOfObjCase == MessageOfObj.MessageOfObjOneofCase.StudentMessage)
Console.WriteLine($"Human is at ({currentGameInfo.ObjMessage[i].StudentMessage.X}, {currentGameInfo.ObjMessage[i].StudentMessage.Y})");
}
}

}
}
}

+ 1
- 0
logic/Gaming/Game.cs View File

@@ -179,6 +179,7 @@ namespace Gaming

propManager.StartProducing();

// 开始游戏
new Thread
(
() =>


+ 140
- 288
logic/Server/CopyInfo.cs View File

@@ -8,13 +8,14 @@ namespace Server
public static class CopyInfo
{
// 下面赋值为0的大概率是还没写完 2023-03-03
/*public static MessageOfObj? Auto(GameObj gameObj)
public static MessageOfObj? Auto(GameObj gameObj)
{
if (gameObj.Type == Preparation.Utility.GameObjType.Character)
{
Character character = (Character)gameObj;
if (character.IsGhost())
return Tri
return Tricker((Character)character);
else return Student((Character)character);
}
else if (gameObj.Type == Preparation.Utility.GameObjType.Bullet)
return Bullet((Bullet)gameObj);
@@ -25,28 +26,34 @@ namespace Server
else if (gameObj.Type == Preparation.Utility.GameObjType.PickedProp)
return PickedProp((PickedProp)gameObj);
else return null; //先写着防报错
}*/
}

private static MessageOfStudent? Student(Character player)
private static MessageOfObj? Student(Character player)
{
MessageOfStudent msg = new MessageOfStudent();
MessageOfObj msg = new MessageOfObj();
if (player.IsGhost()) return null;
msg.StudentMessage = new();

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.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.StudentMessage.X = player.Position.x;
msg.StudentMessage.Y = player.Position.y;
msg.StudentMessage.Speed = player.MoveSpeed;
msg.StudentMessage.Determination = player.HP;
//msg.StudentMessage.FailNum = 0;
foreach (var keyValue in player.TimeUntilActiveSkillAvailable)
msg.StudentMessage.TimeUntilSkillAvailable.Add(keyValue.Value);
//msg.StudentMessage.StudentType; // 下面写
msg.StudentMessage.Guid = player.ID;
// msg.StudentMessage.State = player.PlayerState;
msg.StudentMessage.FailTime = 0;
msg.StudentMessage.EmoTime = 0;
msg.StudentMessage.PlayerId = 0;
msg.StudentMessage.ViewRange = 0;
msg.StudentMessage.Radius = 0;
msg.StudentMessage.Damage = 0;
msg.StudentMessage.DangerAlert = 0;
msg.StudentMessage.Score = 0;
msg.StudentMessage.TreatProgress = 0;
msg.StudentMessage.RescueProgress = 0;

foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff)
{
@@ -55,178 +62,77 @@ namespace Server
switch (kvp.Key) // StudentBuffType具体内容待定
{
case Preparation.Utility.BuffType.Spear:
msg.Buff.Add(StudentBuffType.NullSbuffType);
msg.StudentMessage.Buff.Add(StudentBuffType.NullSbuffType);
break;
case Preparation.Utility.BuffType.AddLIFE:
msg.Buff.Add(StudentBuffType.NullSbuffType);
msg.StudentMessage.Buff.Add(StudentBuffType.NullSbuffType);
break;
case Preparation.Utility.BuffType.Shield:
msg.Buff.Add(StudentBuffType.NullSbuffType);
msg.StudentMessage.Buff.Add(StudentBuffType.NullSbuffType);
break;
case Preparation.Utility.BuffType.AddSpeed:
msg.Buff.Add(StudentBuffType.NullSbuffType);
msg.StudentMessage.Buff.Add(StudentBuffType.NullSbuffType);
break;
default:
break;
}
}
}
switch (player.Place)
{
case Preparation.Utility.PlaceType.EmergencyExit:
msg.Place = PlaceType.HiddenGate;
break;
case Preparation.Utility.PlaceType.Doorway:
msg.Place = PlaceType.Gate;
break;
case Preparation.Utility.PlaceType.Grass:
msg.Place = PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.BirthPoint1:
case Preparation.Utility.PlaceType.BirthPoint2:
case Preparation.Utility.PlaceType.BirthPoint3:
case Preparation.Utility.PlaceType.BirthPoint4:
case Preparation.Utility.PlaceType.BirthPoint5:
case Preparation.Utility.PlaceType.Null:
msg.Place = PlaceType.Land;
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.Add(PropType.NullPropType);
msg.StudentMessage.Prop.Add(PropType.NullPropType);
else
{
switch (player.PropInventory.GetPropType())
{
case Preparation.Utility.PropType.Gem:
msg.Prop.Add(PropType.NullPropType);
msg.StudentMessage.Prop.Add(PropType.NullPropType);
break;
/*case Preparation.Utility.PropType.addLIFE:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddLife;
msg.StudentMessage.MessageOfHuman.Prop = Communication.Proto.PropType.AddLife;
break;
case Preparation.Utility.PropType.addSpeed:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddSpeed;
msg.StudentMessage.MessageOfHuman.Prop = Communication.Proto.PropType.AddSpeed;
break;
case Preparation.Utility.PropType.Shield:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.Shield;
msg.StudentMessage.MessageOfHuman.Prop = Communication.Proto.PropType.Shield;
break;
case Preparation.Utility.PropType.Spear:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.Spear;
msg.StudentMessage.MessageOfHuman.Prop = Communication.Proto.PropType.Spear;
break;
default:
msg.Prop = PropType.NullPropType;
msg.StudentMessage.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 MessageOfTricker? Butcher(Character player)
private static MessageOfObj? Tricker(Character player)
{
MessageOfTricker msg = new MessageOfTricker();
MessageOfObj msg = new MessageOfObj();
if (!player.IsGhost()) return null;
msg.TrickerMessage = new();

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; 下面写了

/* THUAI5中的内容
msg.BulletNum = player.BulletNum;
msg.CanMove = player.CanMove;
msg.CD = player.CD;
msg.GemNum = player.GemNum;
msg.Guid = player.ID;
msg.IsDeceased = player.IsDeceased;
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.TrickerMessage.X = player.Position.x;
msg.TrickerMessage.Y = player.Position.y;
msg.TrickerMessage.Speed = player.MoveSpeed;
msg.TrickerMessage.Damage = 0;
msg.TrickerMessage.TimeUntilSkillAvailable = 0;
//msg.TrickerMessage.Place = 0; 下面写了
//msg.TrickerMessage.Prop = PropType.NullPropType; // 下面写
msg.TrickerMessage.TrickerType = TrickerType.NullTrickerType; // 下面写
msg.TrickerMessage.Guid = 0;
msg.TrickerMessage.Movable = false;
msg.TrickerMessage.PlayerId = 0;
msg.TrickerMessage.ViewRange = 0;
msg.TrickerMessage.Radius = 0;
//msg.TrickerMessage.Buff[0] = ButcherBuffType.NullSbuffType; 下面写了

//应该要发队伍分数,这里先发个人分数
msg.MessageOfHuman.Score = player.Score;

//这条暂时没啥用
msg.MessageOfHuman.TimeUntilUltimateSkillAvailable = 0;

msg.MessageOfHuman.Vampire = player.Vampire;*/

foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff)
{
@@ -235,16 +141,16 @@ namespace Server
switch (kvp.Key) // ButcherBuffType具体内容待定
{
case Preparation.Utility.BuffType.Spear:
msg.Buff.Add(TrickerBuffType.NullTbuffType);
msg.TrickerMessage.Buff.Add(TrickerBuffType.NullTbuffType);
break;
case Preparation.Utility.BuffType.AddLIFE:
msg.Buff.Add(TrickerBuffType.NullTbuffType);
msg.TrickerMessage.Buff.Add(TrickerBuffType.NullTbuffType);
break;
case Preparation.Utility.BuffType.Shield:
msg.Buff.Add(TrickerBuffType.NullTbuffType);
msg.TrickerMessage.Buff.Add(TrickerBuffType.NullTbuffType);
break;
case Preparation.Utility.BuffType.AddSpeed:
msg.Buff.Add(TrickerBuffType.NullTbuffType);
msg.TrickerMessage.Buff.Add(TrickerBuffType.NullTbuffType);
break;
default:
break;
@@ -254,261 +160,207 @@ namespace Server
/*switch (player.Place)
{
case Preparation.Utility.PlaceType.Land:
msg.Place = PlaceType.Land;
msg.TrickerMessage.Place = PlaceType.Land;
break;
case Preparation.Utility.PlaceType.Grass1:
msg.Place = PlaceType.Grass;
msg.TrickerMessage.Place = PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.Grass2:
msg.Place = PlaceType.Grass;
msg.TrickerMessage.Place = PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.Grass3:
msg.Place = PlaceType.Grass;
msg.TrickerMessage.Place = PlaceType.Grass;
break;
// case Preparation.Utility.PlaceType.Invisible:
// msg.MessageOfHuman.Place = Communication.Proto.PlaceType.Invisible;
// msg.TrickerMessage.MessageOfHuman.Place = Communication.Proto.PlaceType.Invisible;
// break;
default:
msg.Place = PlaceType.NullPlaceType;
msg.TrickerMessage.Place = PlaceType.NullPlaceType;
break;
}*/

//Character的储存方式可能得改,用enum type存道具和子弹,不应该用对象
//现在懒得改了,有时间再重整一波
/*if (player.PropInventory == null)
msg.Prop = PropType.NullPropType;
msg.TrickerMessage.Prop = PropType.NullPropType;
else
{
switch (player.PropInventory.GetPropType())
{
case Preparation.Utility.PropType.Gem:
msg.Prop = PropType.NullPropType;
msg.TrickerMessage.Prop = PropType.NullPropType;
break;
case Preparation.Utility.PropType.addLIFE:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddLife;
msg.TrickerMessage.MessageOfHuman.Prop = Communication.Proto.PropType.AddLife;
break;
case Preparation.Utility.PropType.addSpeed:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.AddSpeed;
msg.TrickerMessage.MessageOfHuman.Prop = Communication.Proto.PropType.AddSpeed;
break;
case Preparation.Utility.PropType.Shield:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.Shield;
msg.TrickerMessage.MessageOfHuman.Prop = Communication.Proto.PropType.Shield;
break;
case Preparation.Utility.PropType.Spear:
msg.MessageOfHuman.Prop = Communication.Proto.PropType.Spear;
msg.TrickerMessage.MessageOfHuman.Prop = Communication.Proto.PropType.Spear;
break;
default:
msg.Prop = PropType.NullPropType;
msg.TrickerMessage.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 Bullet(Bullet bullet)
private static MessageOfObj Bullet(Bullet bullet)
{
MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage();
msg.MessageOfBullet = new MessageOfBullet();
msg.MessageOfBullet.FacingDirection = bullet.FacingDirection;
msg.MessageOfBullet.Guid = bullet.ID;
msg.MessageOfBullet.BombRange = BulletFactory.BulletBombRange(bullet.TypeOfBullet);
MessageOfObj msg = new MessageOfObj();
msg.BulletMessage = new();
msg.BulletMessage.X = bullet.Position.x;
msg.BulletMessage.Y = bullet.Position.y;
//msg.BulletMessage.FacingDirection = bullet.FacingDirection; // XY转double?
msg.BulletMessage.Guid = bullet.ID;
msg.BulletMessage.Team = PlayerType.NullPlayerType;
msg.BulletMessage.Place = PlaceType.NullPlaceType;
msg.BulletMessage.BombRange = 0;
switch (bullet.TypeOfBullet)
{
case Preparation.Utility.BulletType.AtomBomb:
msg.MessageOfBullet.Type = Communication.Proto.BulletType.AtomBomb;
msg.BulletMessage.Type = BulletType.AtomBomb;
break;
case Preparation.Utility.BulletType.OrdinaryBullet:
msg.MessageOfBullet.Type = Communication.Proto.BulletType.OrdinaryBullet;
msg.BulletMessage.Type = BulletType.OrdinaryBullet;
break;
case Preparation.Utility.BulletType.FastBullet:
msg.MessageOfBullet.Type = Communication.Proto.BulletType.FastBullet;
msg.BulletMessage.Type = BulletType.FastBullet;
break;
case Preparation.Utility.BulletType.LineBullet:
msg.MessageOfBullet.Type = Communication.Proto.BulletType.LineBullet;
msg.BulletMessage.Type = BulletType.LineBullet;
break;
default:
msg.MessageOfBullet.Type = Communication.Proto.BulletType.NullBulletType;
msg.BulletMessage.Type = BulletType.NullBulletType;
break;
}
msg.MessageOfBullet.X = bullet.Position.x;
msg.MessageOfBullet.Y = bullet.Position.y;
if (bullet.Parent != null)
msg.MessageOfBullet.ParentTeamID = bullet.Parent.TeamID;
switch (bullet.Place)
//if (bullet.Parent != null)
//msg.BulletMessage.MessageOfBullet.ParentTeamID = bullet.Parent.TeamID;
/*switch (bullet.Place)
{
case Preparation.Utility.PlaceType.Null:
msg.MessageOfBullet.Place = Communication.Proto.PlaceType.Null;
msg.BulletMessage.MessageOfBullet.Place = Communication.Proto.PlaceType.Null;
break;
case Preparation.Utility.PlaceType.Grass:
msg.MessageOfBullet.Place = Communication.Proto.PlaceType.Grass;
msg.BulletMessage.MessageOfBullet.Place = Communication.Proto.PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.Grass:
msg.MessageOfBullet.Place = Communication.Proto.PlaceType.Grass;
msg.BulletMessage.MessageOfBullet.Place = Communication.Proto.PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.Grass:
msg.MessageOfBullet.Place = Communication.Proto.PlaceType.Grass;
msg.BulletMessage.MessageOfBullet.Place = Communication.Proto.PlaceType.Grass;
break;
default:
msg.MessageOfBullet.Place = Communication.Proto.PlacccceType.NullPlaceType;
msg.BulletMessage.MessageOfBullet.Place = Communication.Proto.PlacccceType.NullPlaceType;
break;
}
}*/
return msg;
}*/
}

private static MessageOfProp Prop(Prop prop)
private static MessageOfObj Prop(Prop prop)
{
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;*/
MessageOfObj msg = new MessageOfObj();
msg.PropMessage = new();
//msg.PropMessage.Type = PropType.NullPropType; 下面写
msg.PropMessage.X = prop.Position.x;
msg.PropMessage.Y = prop.Position.y;
msg.PropMessage.FacingDirection = 0;
msg.PropMessage.Guid = 0;
msg.PropMessage.Place = PlaceType.NullPlaceType;
msg.PropMessage.Size = 0;
msg.PropMessage.IsMoving = false;

switch (prop.GetPropType())
{
/*case Preparation.Utility.PropType.Gem:
msg.Type = PropType.Gem;
msg.PropMessage.Type = PropType.Gem;
break;
case Preparation.Utility.PropType.addLIFE:
msg.Type = PropType.AddLife;
msg.PropMessage.Type = PropType.AddLife;
break;
case Preparation.Utility.PropType.addSpeed:
msg.Type = PropType.AddSpeed;
msg.PropMessage.Type = PropType.AddSpeed;
break;
case Preparation.Utility.PropType.Shield:
msg.Type = PropType.Shield;
msg.PropMessage.Type = PropType.Shield;
break;
case Preparation.Utility.PropType.Spear:
msg.Type = PropType.Spear;
msg.PropMessage.Type = PropType.Spear;
break;*/
default:
msg.Type = PropType.NullPropType;
msg.PropMessage.Type = PropType.NullPropType;
break;
}

/*if(prop is Gem)
{
msg.MessageOfProp.Size = ((Gem)prop).Size;
msg.PropMessage.MessageOfProp.Size = ((Gem)prop).Size;
}
else
{
msg.MessageOfProp.Size = 1;
msg.PropMessage.MessageOfProp.Size = 1;
}
switch (prop.Place)
{
case Preparation.Utility.PlaceType.Null:
msg.MessageOfProp.Place = Communication.Proto.PlaceType.Null;
msg.PropMessage.MessageOfProp.Place = Communication.Proto.PlaceType.Null;
break;
case Preparation.Utility.PlaceType.Grass:
msg.MessageOfProp.Place = Communication.Proto.PlaceType.Grass;
msg.PropMessage.MessageOfProp.Place = Communication.Proto.PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.Grass:
msg.MessageOfProp.Place = Communication.Proto.PlaceType.Grass;
msg.PropMessage.MessageOfProp.Place = Communication.Proto.PlaceType.Grass;
break;
case Preparation.Utility.PlaceType.Grass:
msg.MessageOfProp.Place = Communication.Proto.PlaceType.Grass;
msg.PropMessage.MessageOfProp.Place = Communication.Proto.PlaceType.Grass;
break;
default:
msg.MessageOfProp.Place = Communication.Proto.PlacccceType.NullPlaceType;
msg.PropMessage.MessageOfProp.Place = Communication.Proto.PlacccceType.NullPlaceType;
break;
}*/
return msg;
}

/*private static MessageOfBombedBullet BombedBullet(BombedBullet bombedBullet)
private static MessageOfObj BombedBullet(BombedBullet bombedBullet)
{
MessageOfBombedBullet msg = new MessageOfBombedBullet;
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);
MessageOfObj msg = new MessageOfObj();
msg.BombedBulletMessage = new();
msg.BombedBulletMessage.X = bombedBullet.bulletHasBombed.Position.x;
msg.BombedBulletMessage.Y = bombedBullet.bulletHasBombed.Position.y;
//msg.BombedBulletMessage.FacingDirection = bombedBullet.FacingDirection; XY类型转double?
msg.BombedBulletMessage.MappingId = bombedBullet.MappingID;
msg.BombedBulletMessage.BombRange = BulletFactory.BulletRadius(bombedBullet.bulletHasBombed.TypeOfBullet); // 待确认
switch (bombedBullet.bulletHasBombed.TypeOfBullet)
{
case Preparation.Utility.BulletType.OrdinaryBullet:
msg.MessageOfBombedBullet.Type = Communication.Proto.BulletType.OrdinaryBullet;
msg.BombedBulletMessage.Type = BulletType.OrdinaryBullet;
break;
case Preparation.Utility.BulletType.AtomBomb:
msg.MessageOfBombedBullet.Type = Communication.Proto.BulletType.AtomBomb;
msg.BombedBulletMessage.Type = BulletType.AtomBomb;
break;
case Preparation.Utility.BulletType.FastBullet:
msg.MessageOfBombedBullet.Type = Communication.Proto.BulletType.FastBullet;
msg.BombedBulletMessage.Type = BulletType.FastBullet;
break;
case Preparation.Utility.BulletType.LineBullet:
msg.MessageOfBombedBullet.Type = Communication.Proto.BulletType.LineBullet;
msg.BombedBulletMessage.Type = BulletType.LineBullet;
break;
default:
msg.MessageOfBombedBullet.Type = Communication.Proto.BulletType.NullBulletType;
msg.BombedBulletMessage.Type = BulletType.NullBulletType;
break;
}
return msg;
}*/
}

/*private static MessageToClient.Types.GameObjMessage PickedProp(PickedProp pickedProp)
private static MessageOfObj PickedProp(PickedProp pickedProp)
{
MessageToClient.Types.GameObjMessage msg = new MessageToClient.Types.GameObjMessage();
msg.MessageOfPickedProp = new MessageOfPickedProp();
MessageOfObj msg = new MessageOfObj(); // MessageOfObj中没有PickedProp
/*msg.MessageOfPickedProp = new MessageOfPickedProp();

msg.MessageOfPickedProp.MappingID = pickedProp.MappingID;
msg.MessageOfPickedProp.X = pickedProp.PropHasPicked.Position.x;
@@ -534,8 +386,8 @@ namespace Server
default:
msg.MessageOfPickedProp.Type = Communication.Proto.PropType.NullPropType;
break;
}
}*/
return msg;
}*/
}
}
}

+ 107
- 37
logic/Server/GameServer.cs View File

@@ -7,6 +7,7 @@ using System.Net.Http.Headers;
using Gaming;
using GameClass.GameObj;
using Preparation.Utility;
using Playback;


namespace Server
@@ -31,13 +32,13 @@ namespace Server
protected readonly ArgumentOptions options;
protected readonly Game game;
private uint spectatorMinPlayerID = 2022;
private List<Tuple<PlayerType, uint>> spectatorList = new List<Tuple<PlayerType, uint>>();
private List<uint> spectatorList = new List<uint>();
public int TeamCount => options.TeamCount;
protected long[,] communicationToGameID; // 通信用的ID映射到游戏内的ID,[i,j]表示team:i,player:j的id。
private readonly object messageToAllClientsLock = new();
public static readonly long SendMessageToClientIntervalInMilliseconds = 50;
private readonly Semaphore endGameInfoSema = new(0, 1);
// private MessageWriter? mwr = null;
private MessageWriter? mwr = null;

public SemaphoreSlim StartGameTest()
{
@@ -81,40 +82,75 @@ namespace Server
}
public void StartGame()
{
bool gameState = game.StartGame((int)options.GameTimeInSecond * 1000);
var waitHandle = new SemaphoreSlim(gameState == true ? 1 : 0); // 注意修改
game.StartGame((int)options.GameTimeInSecond * 1000);
Thread.Sleep(1);
new Thread(() =>
{
bool flag = true;
new FrameRateTaskExecutor<int>
(
() => game.GameMap.Timer.IsGaming,
ReportGame,
1000,
() =>
{
ReportGame(); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住
if (flag == true)
{
ReportGame(GameState.GameStart);
flag = false;
}
else ReportGame(GameState.GameRunning);
},
SendMessageToClientIntervalInMilliseconds,
() =>
{
ReportGame(GameState.GameEnd); // 最后发一次消息,唤醒发消息的线程,防止发消息的线程由于有概率处在 Wait 状态而卡住
OnGameEnd();
return 0;
}
).Start();
})
{ IsBackground = true }.Start();
new Thread(() =>
{
waitHandle.Wait();
this.endGameSem.Release();
})
{ IsBackground = true }.Start();

}
public void WaitForEnd()
{
this.endGameSem.Wait();
mwr?.Dispose();
}

private void OnGameEnd()
{
game.ClearAllLists();
mwr?.Flush();
//if (options.ResultFileName != DefaultArgumentOptions.FileName)
//SaveGameResult(options.ResultFileName + ".json");
//SendGameResult();
endGameInfoSema.Release();
}

public void ReportGame()
public void ReportGame(GameState gameState, bool requiredGaming = true)
{
//currentGameInfo = null;
var gameObjList = game.GetGameObj();
currentGameInfo = new();
lock (messageToAllClientsLock)
{
//currentGameInfo.MapMessage = (Messa(game.GameMap));
if (gameState == GameState.GameStart) currentGameInfo.MapMessage = MapMsg(game.GameMap.ProtoGameMap);
switch (gameState)
{
case GameState.GameRunning:
case GameState.GameStart:
case GameState.GameEnd:
foreach (GameObj gameObj in gameObjList)
{
currentGameInfo.ObjMessage.Add(CopyInfo.Auto(gameObj));
}
currentGameInfo.GameState = gameState;
currentGameInfo.AllMessage = new(); // 还没写
mwr?.WriteOne(currentGameInfo);
break;
default:
break;
}
}

foreach (var kvp in semaDict)
{
@@ -127,25 +163,52 @@ namespace Server
}
}

private int PlayerTypeToTeamID(PlayerType playerType)
private int PlayerIDToTeamID(long playerID)
{
if (playerType == PlayerType.StudentPlayer) return 0;
if (playerType == PlayerType.TrickerPlayer) return 1;
if (0 <= playerID && playerID < options.PlayerCountPerTeam) return 0;
if (playerID == options.PlayerCountPerTeam) return 1;
return -1;
}
private uint GetBirthPointIdx(PlayerType playerType, long playerID) // 获取出生点位置
private uint GetBirthPointIdx(long playerID) // 获取出生点位置
{
return (uint)((PlayerTypeToTeamID(playerType) * options.PlayerCountPerTeam) + playerID + 1);
return (uint)(playerID + 1);
}
private bool ValidPlayerTypeAndPlayerID(PlayerType playerType, long playerID)
private bool ValidPlayerID(long playerID)
{
if (playerType == PlayerType.StudentPlayer && 0 <= playerID && playerID < options.PlayerCountPerTeam)
return true; // 人数待修改
if (playerType == PlayerType.TrickerPlayer && 0 <= playerID && playerID < options.PlayerCountPerTeam)
if (0 <= playerID && playerID < options.PlayerCountPerTeam + 1)
return true;
return false;
}

private Protobuf.PlaceType IntToPlaceType(uint n)
{
switch (n)
{
case 0: return Protobuf.PlaceType.Land;
case 6: return Protobuf.PlaceType.Wall;
case 7: return Protobuf.PlaceType.Grass;
case 8: return Protobuf.PlaceType.Classroom;
case 9: return Protobuf.PlaceType.Gate;
case 10: return Protobuf.PlaceType.HiddenGate;
case 11: return Protobuf.PlaceType.Window;
case 12: return Protobuf.PlaceType.Door;
case 13: return Protobuf.PlaceType.Chest;
default: return Protobuf.PlaceType.NullPlaceType;
}
}
private MessageOfMap MapMsg(uint[,] map)
{
MessageOfMap msgOfMap = new MessageOfMap();
for (int i = 0; i < GameData.rows; i++)
{
msgOfMap.Row.Add(new MessageOfMap.Types.Row());
for (int j = 0; j < GameData.cols; j++)
{
msgOfMap.Row[i].Col.Add(IntToPlaceType(map[i, j]));
}
}
return msgOfMap;
}
public override Task<BoolRes> TryConnection(IDMsg request, ServerCallContext context)
{
Console.WriteLine($"TryConnection ID: {request.PlayerId}");
@@ -167,10 +230,10 @@ namespace Server
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)
if (request.PlayerId >= spectatorMinPlayerID)
{
// 观战模式
Tuple<PlayerType, uint> tp = new Tuple<PlayerType, uint>(request.PlayerType, (uint)request.PlayerId);
uint tp = (uint)request.PlayerId;
if (!spectatorList.Contains(tp))
{
spectatorList.Add(tp);
@@ -181,7 +244,7 @@ namespace Server

if (game.GameMap.Timer.IsGaming)
return;
if (!ValidPlayerTypeAndPlayerID(request.PlayerType, request.PlayerId)) //玩家id是否正确
if (!ValidPlayerID(request.PlayerId)) //玩家id是否正确
return;
//if (communicationToGameID[PlayerTypeToTeamID(request.PlayerType), request.PlayerId] != GameObj.invalidID) //是否已经添加了该玩家
//return;
@@ -190,15 +253,15 @@ namespace Server

lock (addPlayerLock)
{
Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerType, request.PlayerId), PlayerTypeToTeamID(request.PlayerType), request.PlayerId, characterType);
Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerIDToTeamID(request.PlayerId), request.PlayerId, characterType);
long newPlayerID = game.AddPlayer(playerInitInfo);
if (newPlayerID == GameObj.invalidID)
return;
communicationToGameID[PlayerTypeToTeamID(request.PlayerType), request.PlayerId] = newPlayerID;
communicationToGameID[PlayerIDToTeamID(request.PlayerId), request.PlayerId] = newPlayerID;
// 内容待修改
var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1));
bool start = false;
Console.WriteLine($"PlayerType: {request.PlayerType} Id: {request.PlayerId} joins.");
Console.WriteLine($"Id: {request.PlayerId} joins.");
lock (semaDict)
{
semaDict.Add(request.PlayerId, temp);
@@ -218,13 +281,13 @@ namespace Server
if (currentGameInfo != null)
{
await responseStream.WriteAsync(currentGameInfo);
Console.WriteLine("Send!");
//Console.WriteLine("Send!");
}
semaDict[request.PlayerId].Item2.Release();
} while (game.GameMap.Timer.IsGaming);
}

public override Task<BoolRes> Trick(TrickMsg request, ServerCallContext context)
public override Task<BoolRes> Attack(AttackMsg request, ServerCallContext context)
{
game.Attack(request.PlayerId, request.Angle);
BoolRes boolRes = new();
@@ -239,8 +302,10 @@ namespace Server

public override Task<MoveRes> Move(MoveMsg request, ServerCallContext context)
{
Console.WriteLine($"SetPos ID: {request.PlayerId}, TimeInMilliseconds: {request.TimeInMilliseconds}");
var gameID = communicationToGameID[PlayerTypeToTeamID(request.PlayerType), request.PlayerId];
#if DEBUG
Console.WriteLine($"Move ID: {request.PlayerId}, TimeInMilliseconds: {request.TimeInMilliseconds}");
#endif
var gameID = communicationToGameID[PlayerIDToTeamID(request.PlayerId), request.PlayerId];
game.MovePlayer(gameID, (int)request.TimeInMilliseconds, request.Angle);
// 之后game.MovePlayer可能改为bool类型
MoveRes moveRes = new();
@@ -283,7 +348,12 @@ namespace Server
}
public override Task<BoolRes> StartLearning(IDMsg request, ServerCallContext context)
{
return base.StartLearning(request, context);
#if DEBUG
Console.WriteLine($"StartLearning ID: {request.PlayerId}");
#endif
BoolRes boolRes = new();
boolRes.ActSuccess = game.Fix(request.PlayerId);
return Task.FromResult(boolRes);
}

public GameServer(ArgumentOptions options)
@@ -348,7 +418,7 @@ namespace Server
{
try
{
//mwr = new MessageWriter(options.FileName, options.TeamCount, options.PlayerCountPerTeam);
mwr = new MessageWriter(options.FileName, options.TeamCount, options.PlayerCountPerTeam);
}
catch
{


+ 1
- 1
logic/Server/Program.cs View File

@@ -34,7 +34,7 @@ namespace Server
Grpc.Core.Server server = new Grpc.Core.Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
{
Services = { AvailableService.BindService(gameServer) },
Ports = { new ServerPort("127.0.0.1", 8888, ServerCredentials.Insecure) }
Ports = { new ServerPort("0.0.0.0", 8888, ServerCredentials.Insecure) }
};
server.Start();



+ 1
- 0
logic/Server/Server.csproj View File

@@ -21,6 +21,7 @@

<ItemGroup>
<ProjectReference Include="..\..\dependency\proto\Protos.csproj" />
<ProjectReference Include="..\..\playback\Playback\Playback.csproj" />
<ProjectReference Include="..\GameClass\GameClass.csproj" />
<ProjectReference Include="..\GameEngine\GameEngine.csproj" />
<ProjectReference Include="..\Gaming\Gaming.csproj" />


+ 6
- 0
logic/logic.sln View File

@@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protos", "..\dependency\pro
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameEngine", "GameEngine\GameEngine.csproj", "{1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playback", "..\playback\Playback\Playback.csproj", "{FF22960A-6BD9-4C80-A029-9A39FB8F64C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -51,6 +53,10 @@ Global
{1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Release|Any CPU.Build.0 = Release|Any CPU
{FF22960A-6BD9-4C80-A029-9A39FB8F64C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF22960A-6BD9-4C80-A029-9A39FB8F64C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF22960A-6BD9-4C80-A029-9A39FB8F64C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF22960A-6BD9-4C80-A029-9A39FB8F64C4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE


+ 2
- 2
playback/Playback/MessageReader.cs View File

@@ -1,5 +1,5 @@
using Communication.Proto;
using Google.Protobuf;
using Google.Protobuf;
using Protobuf;
using System;
using System.IO;
using System.IO.Compression;


+ 1
- 1
playback/Playback/MessageWriter.cs View File

@@ -1,5 +1,5 @@
using Communication.Proto;
using Google.Protobuf;
using Protobuf;
using System;
using System.IO;
using System.IO.Compression;


+ 10
- 2
playback/Playback/Playback.csproj View File

@@ -1,9 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.22.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\dependency\proto\Protos.csproj" />
</ItemGroup>

</Project>

Loading…
Cancel
Save