Browse Source

Merge branch 'dev' of github.com:eesast/THUAI6 into dev

tags/v0.1.0
Shawqeem 2 years ago
parent
commit
b5a53ef87a
40 changed files with 1069 additions and 563 deletions
  1. +3
    -0
      CAPI/cpp/API/include/Communication.h
  2. +107
    -2
      CAPI/cpp/API/src/Communication.cpp
  3. +2
    -0
      CAPI/cpp/proto/Services.grpc.pb.h
  4. +14
    -4
      CAPI/python/PyAPI/API.py
  5. +112
    -20
      CAPI/python/PyAPI/Communication.py
  6. +215
    -184
      CAPI/python/PyAPI/DebugAPI.py
  7. +3
    -6
      CAPI/python/PyAPI/Interface.py
  8. +1
    -0
      CAPI/python/PyAPI/State.py
  9. +59
    -55
      CAPI/python/PyAPI/constants.py
  10. +225
    -79
      CAPI/python/PyAPI/logic.py
  11. +47
    -16
      CAPI/python/PyAPI/main.py
  12. +115
    -52
      CAPI/python/PyAPI/utils.py
  13. +3
    -3
      docs/游戏机制与平衡性调整更新草案.md
  14. +1
    -1
      docs/版本更新说明.md
  15. +2
    -2
      logic/GameClass/GameObj/Bullet/BombedBullet.cs
  16. +1
    -1
      logic/GameClass/GameObj/Bullet/Bullet.cs
  17. +1
    -1
      logic/GameClass/GameObj/Character/Character.Skill.cs
  18. +14
    -7
      logic/GameClass/GameObj/Character/Character.cs
  19. +8
    -41
      logic/GameClass/GameObj/GameObj.cs
  20. +19
    -0
      logic/GameClass/GameObj/Immovable.cs
  21. +4
    -6
      logic/GameClass/GameObj/Map/Chest.cs
  22. +1
    -2
      logic/GameClass/GameObj/Map/Door.cs
  23. +1
    -2
      logic/GameClass/GameObj/Map/Doorway.cs
  24. +1
    -2
      logic/GameClass/GameObj/Map/EmergencyExit.cs
  25. +1
    -2
      logic/GameClass/GameObj/Map/Generator.cs
  26. +0
    -1
      logic/GameClass/GameObj/Map/Map.cs
  27. +1
    -2
      logic/GameClass/GameObj/Map/Wall.cs
  28. +1
    -2
      logic/GameClass/GameObj/Map/Window.cs
  29. +76
    -38
      logic/GameClass/GameObj/Moveable.cs
  30. +13
    -3
      logic/GameClass/GameObj/ObjOfCharacter.cs
  31. +1
    -2
      logic/GameClass/GameObj/OutOfBoundBlock.cs
  32. +3
    -8
      logic/GameClass/GameObj/PickedProp.cs
  33. +1
    -1
      logic/GameClass/GameObj/Prop.cs
  34. +3
    -3
      logic/Gaming/ActionManager.cs
  35. +4
    -10
      logic/Gaming/AttackManager.cs
  36. +1
    -1
      logic/Gaming/CharacterManager .cs
  37. +1
    -1
      logic/Gaming/Game.cs
  38. +1
    -1
      logic/Gaming/PropManager.cs
  39. +1
    -2
      logic/Preparation/Interface/IGameObj.cs
  40. +2
    -0
      logic/Preparation/Interface/IMoveable.cs

+ 3
- 0
CAPI/cpp/API/include/Communication.h View File

@@ -57,6 +57,9 @@ private:
bool haveNewMessage = false;
protobuf::MessageToClient message2Client;
std::mutex mtxMessage;
std::mutex mtxLimit;
int counter;
static constexpr const int limit = 50;
std::condition_variable cvMessage;
};



+ 107
- 2
CAPI/cpp/API/src/Communication.cpp View File

@@ -20,6 +20,12 @@ Communication::Communication(std::string sIP, std::string sPort)

bool Communication::Move(int64_t time, double angle, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::MoveRes moveResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufMove(time, angle, playerID);
@@ -32,6 +38,12 @@ bool Communication::Move(int64_t time, double angle, int64_t playerID)

bool Communication::PickProp(THUAI6::PropType prop, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes pickPropResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufProp(prop, playerID);
@@ -44,6 +56,12 @@ bool Communication::PickProp(THUAI6::PropType prop, int64_t playerID)

bool Communication::UseProp(THUAI6::PropType prop, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes usePropResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufProp(prop, playerID);
@@ -56,6 +74,12 @@ bool Communication::UseProp(THUAI6::PropType prop, int64_t playerID)

bool Communication::ThrowProp(THUAI6::PropType prop, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes throwPropResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufProp(prop, playerID);
@@ -68,6 +92,12 @@ bool Communication::ThrowProp(THUAI6::PropType prop, int64_t playerID)

bool Communication::UseSkill(int32_t skillID, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes useSkillResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufSkill(skillID, playerID);
@@ -80,6 +110,12 @@ bool Communication::UseSkill(int32_t skillID, int64_t playerID)

bool Communication::SendMessage(int64_t toID, std::string message, bool binary, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes sendMessageResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufSend(message, toID, binary, playerID);
@@ -92,6 +128,12 @@ bool Communication::SendMessage(int64_t toID, std::string message, bool binary,

bool Communication::OpenDoor(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes openDoorResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -104,6 +146,12 @@ bool Communication::OpenDoor(int64_t playerID)

bool Communication::CloseDoor(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes closeDoorResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -116,6 +164,12 @@ bool Communication::CloseDoor(int64_t playerID)

bool Communication::SkipWindow(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes skipWindowResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -128,6 +182,12 @@ bool Communication::SkipWindow(int64_t playerID)

bool Communication::StartOpenGate(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes startOpenGateResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -140,6 +200,12 @@ bool Communication::StartOpenGate(int64_t playerID)

bool Communication::StartOpenChest(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes startOpenChestResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -152,6 +218,12 @@ bool Communication::StartOpenChest(int64_t playerID)

bool Communication::EndAllAction(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes endAllActionResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -164,6 +236,12 @@ bool Communication::EndAllAction(int64_t playerID)

bool Communication::Graduate(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes graduateResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -176,6 +254,12 @@ bool Communication::Graduate(int64_t playerID)

bool Communication::StartLearning(int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes startLearningResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
@@ -188,6 +272,12 @@ bool Communication::StartLearning(int64_t playerID)

bool Communication::StartRouseMate(int64_t playerID, int64_t mateID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes saveStudentResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufTreatAndRescue(playerID, mateID);
@@ -200,6 +290,12 @@ bool Communication::StartRouseMate(int64_t playerID, int64_t mateID)

bool Communication::StartEncourageMate(int64_t playerID, int64_t mateID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes healStudentResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufTreatAndRescue(playerID, mateID);
@@ -212,6 +308,12 @@ bool Communication::StartEncourageMate(int64_t playerID, int64_t mateID)

bool Communication::Attack(double angle, int64_t playerID)
{
{
std::lock_guard<std::mutex> lock(mtxLimit);
if (counter > limit)
return false;
counter++;
}
protobuf::BoolRes attackResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufAttack(angle, playerID);
@@ -229,9 +331,7 @@ bool Communication::TryConnection(int64_t playerID)
auto request = THUAI62Proto::THUAI62ProtobufID(playerID);
auto status = THUAI6Stub->TryConnection(&context, request, &reply);
if (status.ok())
{
return true;
}
else
return false;
}
@@ -254,6 +354,7 @@ void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, T
auto MessageReader = THUAI6Stub->AddPlayer(&context, playerMsg);

protobuf::MessageToClient buffer2Client;
counter = 0;

while (MessageReader->Read(&buffer2Client))
{
@@ -261,6 +362,10 @@ void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, T
std::lock_guard<std::mutex> lock(mtxMessage);
message2Client = std::move(buffer2Client);
haveNewMessage = true;
{
std::lock_guard<std::mutex> lock(mtxLimit);
counter = 0;
}
}
cvMessage.notify_one();
}


+ 2
- 0
CAPI/cpp/proto/Services.grpc.pb.h View File

@@ -25,6 +25,8 @@
#include <grpcpp/impl/codegen/stub_options.h>
#include <grpcpp/impl/codegen/sync_stream.h>

#undef SendMessage

namespace protobuf
{



+ 14
- 4
CAPI/python/PyAPI/API.py View File

@@ -6,7 +6,6 @@ from typing import List, cast, Tuple, Union


class StudentAPI(IStudentAPI, IGameTimer):

def __init__(self, logic: ILogic) -> None:
self.__logic = logic
self.__pool = ThreadPoolExecutor(20)
@@ -133,7 +132,13 @@ class StudentAPI(IStudentAPI, IGameTimer):
return self.__logic.GetGameInfo()

def HaveView(self, gridX: int, gridY: int) -> bool:
return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange)
return self.__logic.HaveView(
gridX,
gridY,
self.GetSelfInfo().x,
self.GetSelfInfo().y,
self.GetSelfInfo().viewRange,
)

# 用于DEBUG的输出函数,仅在DEBUG模式下有效

@@ -182,7 +187,6 @@ class StudentAPI(IStudentAPI, IGameTimer):


class TrickerAPI(ITrickerAPI, IGameTimer):

def __init__(self, logic: ILogic) -> None:
self.__logic = logic
self.__pool = ThreadPoolExecutor(20)
@@ -309,7 +313,13 @@ class TrickerAPI(ITrickerAPI, IGameTimer):
return self.__logic.GetGameInfo()

def HaveView(self, gridX: int, gridY: int) -> bool:
return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange)
return self.__logic.HaveView(
gridX,
gridY,
self.GetSelfInfo().x,
self.GetSelfInfo().y,
self.GetSelfInfo().viewRange,
)

# 用于DEBUG的输出函数,仅在DEBUG模式下有效



+ 112
- 20
CAPI/python/PyAPI/Communication.py View File

@@ -19,17 +19,25 @@ class BoolErrorHandler(IErrorHandler):

class Communication:
def __init__(self, sIP: str, sPort: str):
aim = sIP + ':' + sPort
aim = sIP + ":" + sPort
channel = grpc.insecure_channel(aim)
self.__THUAI6Stub = Services.AvailableServiceStub(channel)
self.__haveNewMessage = False
self.__cvMessage = threading.Condition()
self.__message2Client: Message2Clients.MessageToClient
self.__mtxLimit = threading.Lock()
self.__counter = 0
self.__limit = 50

def Move(self, time: int, angle: float, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
moveResult = self.__THUAI6Stub.Move(
THUAI62Proto.THUAI62ProtobufMove(time, angle, playerID))
THUAI62Proto.THUAI62ProtobufMove(time, angle, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -37,8 +45,13 @@ class Communication:

def PickProp(self, propType: THUAI6.PropType, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
pickResult = self.__THUAI6Stub.PickProp(
THUAI62Proto.THUAI62ProtobufProp(propType, playerID))
THUAI62Proto.THUAI62ProtobufProp(propType, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -46,8 +59,13 @@ class Communication:

def UseProp(self, propType: THUAI6.PropType, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
useResult = self.__THUAI6Stub.UseProp(
THUAI62Proto.THUAI62ProtobufProp(propType, playerID))
THUAI62Proto.THUAI62ProtobufProp(propType, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -55,8 +73,13 @@ class Communication:

def ThrowProp(self, propType: THUAI6.PropType, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
throwResult = self.__THUAI6Stub.ThrowProp(
THUAI62Proto.THUAI62ProtobufProp(propType, playerID))
THUAI62Proto.THUAI62ProtobufProp(propType, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -64,8 +87,13 @@ class Communication:

def UseSkill(self, skillID: int, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
useResult = self.__THUAI6Stub.UseSkill(
THUAI62Proto.THUAI62ProtobufSkill(skillID, playerID))
THUAI62Proto.THUAI62ProtobufSkill(skillID, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -73,8 +101,13 @@ class Communication:

def SendMessage(self, toID: int, message: Union[str, bytes], playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
sendResult = self.__THUAI6Stub.SendMessage(
THUAI62Proto.THUAI62ProtobufSend(message, toID, playerID))
THUAI62Proto.THUAI62ProtobufSend(message, toID, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -82,8 +115,13 @@ class Communication:

def Graduate(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
escapeResult = self.__THUAI6Stub.Graduate(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -91,8 +129,13 @@ class Communication:

def StartLearning(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
learnResult = self.__THUAI6Stub.StartLearning(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -100,8 +143,13 @@ class Communication:

def StartEncourageMate(self, playerID: int, mateID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
helpResult = self.__THUAI6Stub.StartTreatMate(
THUAI62Proto.THUAI62ProtobufTreatAndRescue(playerID, mateID))
THUAI62Proto.THUAI62ProtobufTreatAndRescue(playerID, mateID)
)
except grpc.RpcError as e:
return False
else:
@@ -109,8 +157,13 @@ class Communication:

def StartRouseMate(self, playerID: int, mateID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
helpResult = self.__THUAI6Stub.StartRescueMate(
THUAI62Proto.THUAI62ProtobufTreatAndRescue(playerID, mateID))
THUAI62Proto.THUAI62ProtobufTreatAndRescue(playerID, mateID)
)
except grpc.RpcError as e:
return False
else:
@@ -118,8 +171,13 @@ class Communication:

def Attack(self, angle: float, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
attackResult = self.__THUAI6Stub.Attack(
THUAI62Proto.THUAI62ProtobufAttack(angle, playerID))
THUAI62Proto.THUAI62ProtobufAttack(angle, playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -127,8 +185,13 @@ class Communication:

def OpenDoor(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
openResult = self.__THUAI6Stub.OpenDoor(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -136,8 +199,13 @@ class Communication:

def CloseDoor(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
closeResult = self.__THUAI6Stub.CloseDoor(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -145,8 +213,13 @@ class Communication:

def SkipWindow(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
skipResult = self.__THUAI6Stub.SkipWindow(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -154,8 +227,13 @@ class Communication:

def StartOpenGate(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
openResult = self.__THUAI6Stub.StartOpenGate(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -163,8 +241,13 @@ class Communication:

def StartOpenChest(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
openResult = self.__THUAI6Stub.StartOpenChest(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -172,8 +255,13 @@ class Communication:

def EndAllAction(self, playerID: int) -> bool:
try:
with self.__mtxLimit:
if self.__counter > self.__limit:
return False
self.__counter += 1
endResult = self.__THUAI6Stub.EndAllAction(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -182,7 +270,8 @@ class Communication:
def TryConnection(self, playerID: int) -> bool:
try:
connectResult = self.__THUAI6Stub.TryConnection(
THUAI62Proto.THUAI62ProtobufID(playerID))
THUAI62Proto.THUAI62ProtobufID(playerID)
)
except grpc.RpcError as e:
return False
else:
@@ -202,12 +291,15 @@ class Communication:
else:
studentType = THUAI6.StudentType.NullStudentType
playerMsg = THUAI62Proto.THUAI62ProtobufPlayer(
playerID, playerType, studentType, Setting.trickerType())
playerID, playerType, studentType, Setting.trickerType()
)
for msg in self.__THUAI6Stub.AddPlayer(playerMsg):
with self.__cvMessage:
self.__haveNewMessage = True
self.__message2Client = msg
self.__cvMessage.notify()
with self.__mtxLimit:
self.__counter = 0
except grpc.RpcError as e:
return



+ 215
- 184
CAPI/python/PyAPI/DebugAPI.py View File

@@ -10,22 +10,34 @@ from PyAPI.Interface import ILogic, IStudentAPI, ITrickerAPI, IGameTimer, IAI


class StudentDebugAPI(IStudentAPI, IGameTimer):

def __init__(self, logic: ILogic, file: bool, screen: bool, warnOnly: bool, playerID: int) -> None:
def __init__(
self, logic: ILogic, file: bool, screen: bool, warnOnly: bool, playerID: int
) -> None:
self.__logic = logic
self.__pool = ThreadPoolExecutor(20)
self.__startPoint = datetime.datetime.now()
self.__logger = logging.getLogger("api " + str(playerID))
self.__logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s", '%H:%M:%S')
"[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s",
"%H:%M:%S",
)
# 确保文件存在
if not os.path.exists(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"):
os.makedirs(os.path.dirname(os.path.dirname(
os.path.realpath(__file__))) + "/logs")

fileHandler = logging.FileHandler(os.path.dirname(
os.path.dirname(os.path.realpath(__file__))) + "/logs/api-" + str(playerID) + "-log.txt", mode="w+", encoding="utf-8")
if not os.path.exists(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"
):
os.makedirs(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"
)

fileHandler = logging.FileHandler(
os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+ "/logs/api-"
+ str(playerID)
+ "-log.txt",
mode="w+",
encoding="utf-8",
)
screenHandler = logging.StreamHandler()
if file:
fileHandler.setLevel(logging.DEBUG)
@@ -43,13 +55,13 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):

def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]:
self.__logger.info(
f"Move: timeInMilliseconds = {timeInMilliseconds}, angle = {angle}, called at {self.__GetTime()}ms")
f"Move: timeInMilliseconds = {timeInMilliseconds}, angle = {angle}, called at {self.__GetTime()}ms"
)

def logMove() -> bool:
result = self.__logic.Move(timeInMilliseconds, angle)
if not result:
self.__logger.warning(
f"Move: failed at {self.__GetTime()}ms")
self.__logger.warning(f"Move: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logMove)
@@ -69,14 +81,12 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
return self.Move(timeInMilliseconds, 0)

def Attack(self, angle: float) -> Future[bool]:
self.__logger.info(
f"Attack: angle = {angle}, called at {self.__GetTime()}ms")
self.__logger.info(f"Attack: angle = {angle}, called at {self.__GetTime()}ms")

def logAttack() -> bool:
result = self.__logic.Attack(angle)
if not result:
self.__logger.warning(
f"Attack: failed at {self.__GetTime()}ms")
self.__logger.warning(f"Attack: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logAttack)
@@ -85,131 +95,119 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):

def PickProp(self, propType: THUAI6.PropType) -> Future[bool]:
self.__logger.info(
f"PickProp: prop = {propType.name}, called at {self.__GetTime()}ms")
f"PickProp: prop = {propType.name}, called at {self.__GetTime()}ms"
)

def logPick() -> bool:
result = self.__logic.PickProp(propType)
if not result:
self.__logger.warning(
f"PickProp: failed at {self.__GetTime()}ms")
self.__logger.warning(f"PickProp: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logPick)

def UseProp(self, propType: THUAI6.PropType) -> Future[bool]:
self.__logger.info(
f"UseProp: prop = {propType.name}, called at {self.__GetTime()}ms")
f"UseProp: prop = {propType.name}, called at {self.__GetTime()}ms"
)

def logUse() -> bool:
result = self.__logic.UseProp(propType)
if not result:
self.__logger.warning(
f"UseProp: failed at {self.__GetTime()}ms")
self.__logger.warning(f"UseProp: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logUse)

def ThrowProp(self, propType: THUAI6.PropType) -> Future[bool]:
self.__logger.info(
f"ThrowProp: prop = {propType.name}, called at {self.__GetTime()}ms")
f"ThrowProp: prop = {propType.name}, called at {self.__GetTime()}ms"
)

def logThrow() -> bool:
result = self.__logic.ThrowProp(propType)
if not result:
self.__logger.warning(
f"ThrowProp: failed at {self.__GetTime()}ms")
self.__logger.warning(f"ThrowProp: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logThrow)

def UseSkill(self, skillID: int) -> Future[bool]:
self.__logger.info(
f"UseSkill: skillID = {skillID}, called at {self.__GetTime()}ms")
f"UseSkill: skillID = {skillID}, called at {self.__GetTime()}ms"
)

def logUse() -> bool:
result = self.__logic.UseSkill(skillID)
if not result:
self.__logger.warning(
f"UseSkill: failed at {self.__GetTime()}ms")
self.__logger.warning(f"UseSkill: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logUse)

# 与地图交互相关
def OpenDoor(self) -> Future[bool]:
self.__logger.info(
f"OpenDoor: called at {self.__GetTime()}ms")
self.__logger.info(f"OpenDoor: called at {self.__GetTime()}ms")

def logOpen() -> bool:
result = self.__logic.OpenDoor()
if not result:
self.__logger.warning(
f"OpenDoor: failed at {self.__GetTime()}ms")
self.__logger.warning(f"OpenDoor: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logOpen)

def CloseDoor(self) -> Future[bool]:
self.__logger.info(
f"CloseDoor: called at {self.__GetTime()}ms")
self.__logger.info(f"CloseDoor: called at {self.__GetTime()}ms")

def logClose() -> bool:
result = self.__logic.CloseDoor()
if not result:
self.__logger.warning(
f"CloseDoor: failed at {self.__GetTime()}ms")
self.__logger.warning(f"CloseDoor: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logClose)

def SkipWindow(self) -> Future[bool]:
self.__logger.info(
f"SkipWindow: called at {self.__GetTime()}ms")
self.__logger.info(f"SkipWindow: called at {self.__GetTime()}ms")

def logSkip() -> bool:
result = self.__logic.SkipWindow()
if not result:
self.__logger.warning(
f"SkipWindow: failed at {self.__GetTime()}ms")
self.__logger.warning(f"SkipWindow: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logSkip)

def StartOpenGate(self) -> Future[bool]:
self.__logger.info(
f"StartOpenGate: called at {self.__GetTime()}ms")
self.__logger.info(f"StartOpenGate: called at {self.__GetTime()}ms")

def logStart() -> bool:
result = self.__logic.StartOpenGate()
if not result:
self.__logger.warning(
f"StartOpenGate: failed at {self.__GetTime()}ms")
self.__logger.warning(f"StartOpenGate: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logStart)

def StartOpenChest(self) -> Future[bool]:
self.__logger.info(
f"StartOpenChest: called at {self.__GetTime()}ms")
self.__logger.info(f"StartOpenChest: called at {self.__GetTime()}ms")

def logStart() -> bool:
result = self.__logic.StartOpenChest()
if not result:
self.__logger.warning(
f"StartOpenChest: failed at {self.__GetTime()}ms")
self.__logger.warning(f"StartOpenChest: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logStart)

def EndAllAction(self) -> Future[bool]:
self.__logger.info(
f"EndAllAction: called at {self.__GetTime()}ms")
self.__logger.info(f"EndAllAction: called at {self.__GetTime()}ms")

def logEnd() -> bool:
result = self.__logic.EndAllAction()
if not result:
self.__logger.warning(
f"EndAllAction: failed at {self.__GetTime()}ms")
self.__logger.warning(f"EndAllAction: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logEnd)
@@ -218,40 +216,35 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):

def SendMessage(self, toID: int, message: Union[str, bytes]) -> Future[bool]:
self.__logger.info(
f"SendMessage: toID = {toID}, message = {message}, called at {self.__GetTime()}ms")
f"SendMessage: toID = {toID}, message = {message}, called at {self.__GetTime()}ms"
)

def logSend() -> bool:
result = self.__logic.SendMessage(toID, message)
if not result:
self.__logger.warning(
f"SendMessage: failed at {self.__GetTime()}ms")
self.__logger.warning(f"SendMessage: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logSend)

def HaveMessage(self) -> bool:
self.__logger.info(
f"HaveMessage: called at {self.__GetTime()}ms")
self.__logger.info(f"HaveMessage: called at {self.__GetTime()}ms")
result = self.__logic.HaveMessage()
if not result:
self.__logger.warning(
f"HaveMessage: failed at {self.__GetTime()}ms")
self.__logger.warning(f"HaveMessage: failed at {self.__GetTime()}ms")
return result

def GetMessage(self) -> Tuple[int, Union[str, bytes]]:
self.__logger.info(
f"GetMessage: called at {self.__GetTime()}ms")
self.__logger.info(f"GetMessage: called at {self.__GetTime()}ms")
result = self.__logic.GetMessage()
if result[0] == -1:
self.__logger.warning(
f"GetMessage: failed at {self.__GetTime()}ms")
self.__logger.warning(f"GetMessage: failed at {self.__GetTime()}ms")
return result

# 等待下一帧

def Wait(self) -> bool:
self.__logger.info(
f"Wait: called at {self.__GetTime()}ms")
self.__logger.info(f"Wait: called at {self.__GetTime()}ms")
if self.__logic.GetCounter() == -1:
return False
else:
@@ -305,7 +298,13 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
return self.__logic.GetGameInfo()

def HaveView(self, gridX: int, gridY: int) -> bool:
return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange)
return self.__logic.HaveView(
gridX,
gridY,
self.GetSelfInfo().x,
self.GetSelfInfo().y,
self.GetSelfInfo().viewRange,
)

# 用于DEBUG的输出函数,仅在DEBUG模式下有效

@@ -316,20 +315,26 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
for student in self.__logic.GetStudents():
self.__logger.info("******Student Info******")
self.__logger.info(
f"playerID={student.playerID}, GUID={student.guid}, x={student.x}, y={student.y}")
f"playerID={student.playerID}, GUID={student.guid}, x={student.x}, y={student.y}"
)
self.__logger.info(
f"speed={student.speed}, view range={student.viewRange}, radius={student.radius}")
f"speed={student.speed}, view range={student.viewRange}, radius={student.radius}"
)
self.__logger.info(
f"score={student.score}, facing direction={student.facingDirection}, skill time={student.timeUntilSkillAvailable}")
f"score={student.score}, facing direction={student.facingDirection}, skill time={student.timeUntilSkillAvailable}"
)
studentProp = ""
for prop in student.prop:
studentProp += prop.name + ", "
self.__logger.info(
f"state={student.playerState.name}, bullet={student.bulletType.name}, prop={studentProp}")
f"state={student.playerState.name}, bullet={student.bulletType.name}, prop={studentProp}"
)
self.__logger.info(
f"type={student.studentType.name}, determination={student.determination}, addiction={student.addiction}, danger alert={student.dangerAlert}")
f"type={student.studentType.name}, determination={student.determination}, addiction={student.addiction}, danger alert={student.dangerAlert}"
)
self.__logger.info(
f"learning speed={student.learningSpeed}, encourage speed={student.encourageSpeed}, encourage progress={student.encourageProgress}, rouse progress={student.rouseProgress}")
f"learning speed={student.learningSpeed}, encourage speed={student.encourageSpeed}, encourage progress={student.encourageProgress}, rouse progress={student.rouseProgress}"
)
studentBuff = ""
for buff in student.buff:
studentBuff += buff.name + ", "
@@ -340,18 +345,23 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
for tricker in self.__logic.GetTrickers():
self.__logger.info("******Tricker Info******")
self.__logger.info(
f"playerID={tricker.playerID}, GUID={tricker.guid}, x={tricker.x}, y={tricker.y}")
f"playerID={tricker.playerID}, GUID={tricker.guid}, x={tricker.x}, y={tricker.y}"
)
self.__logger.info(
f"speed={tricker.speed}, view range={tricker.viewRange}, radius={tricker.radius}")
f"speed={tricker.speed}, view range={tricker.viewRange}, radius={tricker.radius}"
)
self.__logger.info(
f"score={tricker.score}, facing direction={tricker.facingDirection}, skill time={tricker.timeUntilSkillAvailable}")
f"score={tricker.score}, facing direction={tricker.facingDirection}, skill time={tricker.timeUntilSkillAvailable}"
)
trickerProp = ""
for prop in tricker.prop:
trickerProp += prop.name + ", "
self.__logger.info(
f"state={tricker.playerState.name}, bullet={tricker.bulletType.name}, prop={trickerProp}")
f"state={tricker.playerState.name}, bullet={tricker.bulletType.name}, prop={trickerProp}"
)
self.__logger.info(
f"type={tricker.trickerType.name}, trick desire={tricker.trickDesire}, class volume={tricker.classVolume}")
f"type={tricker.trickerType.name}, trick desire={tricker.trickDesire}, class volume={tricker.classVolume}"
)
trickerBuff = ""
for buff in tricker.buff:
trickerBuff += buff.name + ", "
@@ -362,27 +372,34 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
for prop in self.__logic.GetProps():
self.__logger.info("******Prop Info******")
self.__logger.info(
f"GUID={prop.guid}, x={prop.x}, y={prop.y}, facing direction={prop.facingDirection}")
f"GUID={prop.guid}, x={prop.x}, y={prop.y}, facing direction={prop.facingDirection}"
)
self.__logger.info("*********************")

def PrintSelfInfo(self) -> None:
student = cast(THUAI6.Student, self.__logic.GetSelfInfo())
self.__logger.info("******Student Info******")
self.__logger.info(
f"playerID={student.playerID}, GUID={student.guid}, x={student.x}, y={student.y}")
f"playerID={student.playerID}, GUID={student.guid}, x={student.x}, y={student.y}"
)
self.__logger.info(
f"speed={student.speed}, view range={student.viewRange}, radius={student.radius}")
f"speed={student.speed}, view range={student.viewRange}, radius={student.radius}"
)
self.__logger.info(
f"score={student.score}, facing direction={student.facingDirection}, skill time={student.timeUntilSkillAvailable}")
f"score={student.score}, facing direction={student.facingDirection}, skill time={student.timeUntilSkillAvailable}"
)
studentProp = ""
for prop in student.prop:
studentProp += prop.name + ", "
self.__logger.info(
f"state={student.playerState.name}, bullet={student.bulletType.name}, prop={studentProp}")
f"state={student.playerState.name}, bullet={student.bulletType.name}, prop={studentProp}"
)
self.__logger.info(
f"type={student.studentType.name}, determination={student.determination}, addiction={student.addiction}, danger alert={student.dangerAlert}")
f"type={student.studentType.name}, determination={student.determination}, addiction={student.addiction}, danger alert={student.dangerAlert}"
)
self.__logger.info(
f"learning speed={student.learningSpeed}, encourage speed={student.encourageSpeed}, encourage progress={student.encourageProgress}, rouse progress={student.rouseProgress}")
f"learning speed={student.learningSpeed}, encourage speed={student.encourageSpeed}, encourage progress={student.encourageProgress}, rouse progress={student.rouseProgress}"
)
studentBuff = ""
for buff in student.buff:
studentBuff += buff.name + ", "
@@ -392,53 +409,47 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
# 人类阵营的特殊函数

def Graduate(self) -> Future[bool]:
self.__logger.info(
f"Graduate: called at {self.__GetTime()}ms")
self.__logger.info(f"Graduate: called at {self.__GetTime()}ms")

def logGraduate() -> bool:
result = self.__logic.Graduate()
if not result:
self.__logger.warning(
f"Graduate: failed at {self.__GetTime()}ms")
self.__logger.warning(f"Graduate: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logGraduate)

def StartLearning(self) -> Future[bool]:
self.__logger.info(
f"StartLearning: called at {self.__GetTime()}ms")
self.__logger.info(f"StartLearning: called at {self.__GetTime()}ms")

def logStart() -> bool:
result = self.__logic.StartLearning()
if not result:
self.__logger.warning(
f"StartLearning: failed at {self.__GetTime()}ms")
self.__logger.warning(f"StartLearning: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logStart)

def StartEncourageMate(self, mateID: int) -> Future[bool]:
self.__logger.info(
f"StartEncourageMate: called at {self.__GetTime()}ms")
self.__logger.info(f"StartEncourageMate: called at {self.__GetTime()}ms")

def logStartEncourageMate() -> bool:
result = self.__logic.StartEncourageMate(mateID)
if not result:
self.__logger.warning(
f"StartEncourageMate: failed at {self.__GetTime()}ms")
f"StartEncourageMate: failed at {self.__GetTime()}ms"
)
return result

return self.__pool.submit(logStartEncourageMate)

def StartRouseMate(self, mateID: int) -> Future[bool]:
self.__logger.info(
f"StartRouseMate: called at {self.__GetTime()}ms")
self.__logger.info(f"StartRouseMate: called at {self.__GetTime()}ms")

def logStartRouseMate() -> bool:
result = self.__logic.StartRouseMate(mateID)
if not result:
self.__logger.warning(
f"StartRouseMate: failed at {self.__GetTime()}ms")
self.__logger.warning(f"StartRouseMate: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logStartRouseMate)
@@ -449,7 +460,9 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):
# Timer用

def __GetTime(self) -> float:
return (datetime.datetime.now() - self.__startPoint) / datetime.timedelta(milliseconds=1)
return (datetime.datetime.now() - self.__startPoint) / datetime.timedelta(
milliseconds=1
)

def StartTimer(self) -> None:
self.__startPoint = datetime.datetime.now()
@@ -464,21 +477,33 @@ class StudentDebugAPI(IStudentAPI, IGameTimer):


class TrickerDebugAPI(ITrickerAPI, IGameTimer):

def __init__(self, logic: ILogic, file: bool, screen: bool, warnOnly: bool, playerID: int) -> None:
def __init__(
self, logic: ILogic, file: bool, screen: bool, warnOnly: bool, playerID: int
) -> None:
self.__logic = logic
self.__pool = ThreadPoolExecutor(20)
self.__logger = logging.getLogger("api " + str(playerID))
self.__logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s", '%H:%M:%S')
"[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s",
"%H:%M:%S",
)
# 确保文件存在
if not os.path.exists(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"):
os.makedirs(os.path.dirname(os.path.dirname(
os.path.realpath(__file__))) + "/logs")

fileHandler = logging.FileHandler(os.path.dirname(
os.path.dirname(os.path.realpath(__file__))) + "/logs/api-" + str(playerID) + "-log.txt", mode="w+", encoding="utf-8")
if not os.path.exists(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"
):
os.makedirs(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"
)

fileHandler = logging.FileHandler(
os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+ "/logs/api-"
+ str(playerID)
+ "-log.txt",
mode="w+",
encoding="utf-8",
)
screenHandler = logging.StreamHandler()
if file:
fileHandler.setLevel(logging.DEBUG)
@@ -496,13 +521,13 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):

def Move(self, timeInMilliseconds: int, angle: float) -> Future[bool]:
self.__logger.info(
f"Move: timeInMilliseconds = {timeInMilliseconds}, angle = {angle}, called at {self.__GetTime()}ms")
f"Move: timeInMilliseconds = {timeInMilliseconds}, angle = {angle}, called at {self.__GetTime()}ms"
)

def logMove() -> bool:
result = self.__logic.Move(timeInMilliseconds, angle)
if not result:
self.__logger.warning(
f"Move: failed at {self.__GetTime()}ms")
self.__logger.warning(f"Move: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logMove)
@@ -524,14 +549,12 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):
# 道具和技能相关

def Attack(self, angle: float) -> Future[bool]:
self.__logger.info(
f"Attack: angle = {angle}, called at {self.__GetTime()}ms")
self.__logger.info(f"Attack: angle = {angle}, called at {self.__GetTime()}ms")

def logAttack() -> bool:
result = self.__logic.Attack(angle)
if not result:
self.__logger.warning(
f"Attack: failed at {self.__GetTime()}ms")
self.__logger.warning(f"Attack: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logAttack)
@@ -540,131 +563,119 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):

def PickProp(self, propType: THUAI6.PropType) -> Future[bool]:
self.__logger.info(
f"PickProp: prop = {propType.name}, called at {self.__GetTime()}ms")
f"PickProp: prop = {propType.name}, called at {self.__GetTime()}ms"
)

def logPick() -> bool:
result = self.__logic.PickProp(propType)
if not result:
self.__logger.warning(
f"PickProp: failed at {self.__GetTime()}ms")
self.__logger.warning(f"PickProp: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logPick)

def UseProp(self, propType: THUAI6.PropType) -> Future[bool]:
self.__logger.info(
f"UseProp: prop = {propType.name}, called at {self.__GetTime()}ms")
f"UseProp: prop = {propType.name}, called at {self.__GetTime()}ms"
)

def logUse() -> bool:
result = self.__logic.UseProp(propType)
if not result:
self.__logger.warning(
f"UseProp: failed at {self.__GetTime()}ms")
self.__logger.warning(f"UseProp: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logUse)

def ThrowProp(self, propType: THUAI6.PropType) -> Future[bool]:
self.__logger.info(
f"ThrowProp: prop = {propType.name}, called at {self.__GetTime()}ms")
f"ThrowProp: prop = {propType.name}, called at {self.__GetTime()}ms"
)

def logThrow() -> bool:
result = self.__logic.ThrowProp(propType)
if not result:
self.__logger.warning(
f"ThrowProp: failed at {self.__GetTime()}ms")
self.__logger.warning(f"ThrowProp: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logThrow)

def UseSkill(self, skillID: int) -> Future[bool]:
self.__logger.info(
f"UseSkill: skillID = {skillID}, called at {self.__GetTime()}ms")
f"UseSkill: skillID = {skillID}, called at {self.__GetTime()}ms"
)

def logUse() -> bool:
result = self.__logic.UseSkill(skillID)
if not result:
self.__logger.warning(
f"UseSkill: failed at {self.__GetTime()}ms")
self.__logger.warning(f"UseSkill: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logUse)

# 与地图交互相关
def OpenDoor(self) -> Future[bool]:
self.__logger.info(
f"OpenDoor: called at {self.__GetTime()}ms")
self.__logger.info(f"OpenDoor: called at {self.__GetTime()}ms")

def logOpen() -> bool:
result = self.__logic.OpenDoor()
if not result:
self.__logger.warning(
f"OpenDoor: failed at {self.__GetTime()}ms")
self.__logger.warning(f"OpenDoor: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logOpen)

def CloseDoor(self) -> Future[bool]:
self.__logger.info(
f"CloseDoor: called at {self.__GetTime()}ms")
self.__logger.info(f"CloseDoor: called at {self.__GetTime()}ms")

def logClose() -> bool:
result = self.__logic.CloseDoor()
if not result:
self.__logger.warning(
f"CloseDoor: failed at {self.__GetTime()}ms")
self.__logger.warning(f"CloseDoor: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logClose)

def SkipWindow(self) -> Future[bool]:
self.__logger.info(
f"SkipWindow: called at {self.__GetTime()}ms")
self.__logger.info(f"SkipWindow: called at {self.__GetTime()}ms")

def logSkip() -> bool:
result = self.__logic.SkipWindow()
if not result:
self.__logger.warning(
f"SkipWindow: failed at {self.__GetTime()}ms")
self.__logger.warning(f"SkipWindow: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logSkip)

def StartOpenGate(self) -> Future[bool]:
self.__logger.info(
f"StartOpenGate: called at {self.__GetTime()}ms")
self.__logger.info(f"StartOpenGate: called at {self.__GetTime()}ms")

def logStart() -> bool:
result = self.__logic.StartOpenGate()
if not result:
self.__logger.warning(
f"StartOpenGate: failed at {self.__GetTime()}ms")
self.__logger.warning(f"StartOpenGate: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logStart)

def StartOpenChest(self) -> Future[bool]:
self.__logger.info(
f"StartOpenChest: called at {self.__GetTime()}ms")
self.__logger.info(f"StartOpenChest: called at {self.__GetTime()}ms")

def logStart() -> bool:
result = self.__logic.StartOpenChest()
if not result:
self.__logger.warning(
f"StartOpenChest: failed at {self.__GetTime()}ms")
self.__logger.warning(f"StartOpenChest: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logStart)

def EndAllAction(self) -> Future[bool]:
self.__logger.info(
f"EndAllAction: called at {self.__GetTime()}ms")
self.__logger.info(f"EndAllAction: called at {self.__GetTime()}ms")

def logEnd() -> bool:
result = self.__logic.EndAllAction()
if not result:
self.__logger.warning(
f"EndAllAction: failed at {self.__GetTime()}ms")
self.__logger.warning(f"EndAllAction: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logEnd)
@@ -673,40 +684,35 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):

def SendMessage(self, toID: int, message: Union[str, bytes]) -> Future[bool]:
self.__logger.info(
f"SendMessage: toID = {toID}, message = {message}, called at {self.__GetTime()}ms")
f"SendMessage: toID = {toID}, message = {message}, called at {self.__GetTime()}ms"
)

def logSend() -> bool:
result = self.__logic.SendMessage(toID, message)
if not result:
self.__logger.warning(
f"SendMessage: failed at {self.__GetTime()}ms")
self.__logger.warning(f"SendMessage: failed at {self.__GetTime()}ms")
return result

return self.__pool.submit(logSend)

def HaveMessage(self) -> bool:
self.__logger.info(
f"HaveMessage: called at {self.__GetTime()}ms")
self.__logger.info(f"HaveMessage: called at {self.__GetTime()}ms")
result = self.__logic.HaveMessage()
if not result:
self.__logger.warning(
f"HaveMessage: failed at {self.__GetTime()}ms")
self.__logger.warning(f"HaveMessage: failed at {self.__GetTime()}ms")
return result

def GetMessage(self) -> Tuple[int, Union[str, bytes]]:
self.__logger.info(
f"GetMessage: called at {self.__GetTime()}ms")
self.__logger.info(f"GetMessage: called at {self.__GetTime()}ms")
result = self.__logic.GetMessage()
if result[0] == -1:
self.__logger.warning(
f"GetMessage: failed at {self.__GetTime()}ms")
self.__logger.warning(f"GetMessage: failed at {self.__GetTime()}ms")
return result

# 等待下一帧

def Wait(self) -> bool:
self.__logger.info(
f"Wait: called at {self.__GetTime()}ms")
self.__logger.info(f"Wait: called at {self.__GetTime()}ms")
if self.__logic.GetCounter() == -1:
return False
else:
@@ -760,7 +766,13 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):
return self.__logic.GetGameInfo()

def HaveView(self, gridX: int, gridY: int) -> bool:
return self.__logic.HaveView(gridX, gridY, self.GetSelfInfo().x, self.GetSelfInfo().y, self.GetSelfInfo().viewRange)
return self.__logic.HaveView(
gridX,
gridY,
self.GetSelfInfo().x,
self.GetSelfInfo().y,
self.GetSelfInfo().viewRange,
)

# 用于DEBUG的输出函数,仅在DEBUG模式下有效

@@ -771,20 +783,26 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):
for student in self.__logic.GetStudents():
self.__logger.info("******Student Info******")
self.__logger.info(
f"playerID={student.playerID}, GUID={student.guid}, x={student.x}, y={student.y}")
f"playerID={student.playerID}, GUID={student.guid}, x={student.x}, y={student.y}"
)
self.__logger.info(
f"speed={student.speed}, view range={student.viewRange}, radius={student.radius}")
f"speed={student.speed}, view range={student.viewRange}, radius={student.radius}"
)
self.__logger.info(
f"score={student.score}, facing direction={student.facingDirection}, skill time={student.timeUntilSkillAvailable}")
f"score={student.score}, facing direction={student.facingDirection}, skill time={student.timeUntilSkillAvailable}"
)
studentProp = ""
for prop in student.prop:
studentProp += prop.name + ", "
self.__logger.info(
f"state={student.playerState.name}, bullet={student.bulletType.name}, prop={studentProp}")
f"state={student.playerState.name}, bullet={student.bulletType.name}, prop={studentProp}"
)
self.__logger.info(
f"type={student.studentType.name}, determination={student.determination}, addiction={student.addiction}, danger alert={student.dangerAlert}")
f"type={student.studentType.name}, determination={student.determination}, addiction={student.addiction}, danger alert={student.dangerAlert}"
)
self.__logger.info(
f"learning speed={student.learningSpeed}, encourage speed={student.encourageSpeed}, encourage progress={student.encourageProgress}, rouse progress={student.rouseProgress}")
f"learning speed={student.learningSpeed}, encourage speed={student.encourageSpeed}, encourage progress={student.encourageProgress}, rouse progress={student.rouseProgress}"
)
studentBuff = ""
for buff in student.buff:
studentBuff += buff.name + ", "
@@ -795,18 +813,23 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):
for tricker in self.__logic.GetTrickers():
self.__logger.info("******Tricker Info******")
self.__logger.info(
f"playerID={tricker.playerID}, GUID={tricker.guid}, x={tricker.x}, y={tricker.y}")
f"playerID={tricker.playerID}, GUID={tricker.guid}, x={tricker.x}, y={tricker.y}"
)
self.__logger.info(
f"speed={tricker.speed}, view range={tricker.viewRange}, radius={tricker.radius}")
f"speed={tricker.speed}, view range={tricker.viewRange}, radius={tricker.radius}"
)
self.__logger.info(
f"score={tricker.score}, facing direction={tricker.facingDirection}, skill time={tricker.timeUntilSkillAvailable}")
f"score={tricker.score}, facing direction={tricker.facingDirection}, skill time={tricker.timeUntilSkillAvailable}"
)
trickerProp = ""
for prop in tricker.prop:
trickerProp += prop.name + ", "
self.__logger.info(
f"state={tricker.playerState.name}, bullet={tricker.bulletType.name}, prop={trickerProp}")
f"state={tricker.playerState.name}, bullet={tricker.bulletType.name}, prop={trickerProp}"
)
self.__logger.info(
f"type={tricker.trickerType.name}, trick desire={tricker.trickDesire}, class volume={tricker.classVolume}")
f"type={tricker.trickerType.name}, trick desire={tricker.trickDesire}, class volume={tricker.classVolume}"
)
trickerBuff = ""
for buff in tricker.buff:
trickerBuff += buff.name + ", "
@@ -817,25 +840,31 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):
for prop in self.__logic.GetProps():
self.__logger.info("******Prop Info******")
self.__logger.info(
f"GUID={prop.guid}, x={prop.x}, y={prop.y}, facing direction={prop.facingDirection}")
f"GUID={prop.guid}, x={prop.x}, y={prop.y}, facing direction={prop.facingDirection}"
)
self.__logger.info("*********************")

def PrintSelfInfo(self) -> None:
tricker = cast(THUAI6.Tricker, self.__logic.GetSelfInfo())
self.__logger.info("******Tricker Info******")
self.__logger.info(
f"playerID={tricker.playerID}, GUID={tricker.guid}, x={tricker.x}, y={tricker.y}")
f"playerID={tricker.playerID}, GUID={tricker.guid}, x={tricker.x}, y={tricker.y}"
)
self.__logger.info(
f"speed={tricker.speed}, view range={tricker.viewRange}, radius={tricker.radius}")
f"speed={tricker.speed}, view range={tricker.viewRange}, radius={tricker.radius}"
)
self.__logger.info(
f"score={tricker.score}, facing direction={tricker.facingDirection}, skill time={tricker.timeUntilSkillAvailable}")
f"score={tricker.score}, facing direction={tricker.facingDirection}, skill time={tricker.timeUntilSkillAvailable}"
)
trickerProp = ""
for prop in tricker.prop:
trickerProp += prop.name + ", "
self.__logger.info(
f"state={tricker.playerState.name}, bullet={tricker.bulletType.name}, prop={trickerProp}")
f"state={tricker.playerState.name}, bullet={tricker.bulletType.name}, prop={trickerProp}"
)
self.__logger.info(
f"type={tricker.trickerType.name}, trick desire={tricker.trickDesire}, class volume={tricker.classVolume}")
f"type={tricker.trickerType.name}, trick desire={tricker.trickDesire}, class volume={tricker.classVolume}"
)
trickerBuff = ""
for buff in tricker.buff:
trickerBuff += buff.name + ", "
@@ -850,7 +879,9 @@ class TrickerDebugAPI(ITrickerAPI, IGameTimer):
# Timer用

def __GetTime(self) -> float:
return (datetime.datetime.now() - self.__startPoint) / datetime.timedelta(milliseconds=1)
return (datetime.datetime.now() - self.__startPoint) / datetime.timedelta(
milliseconds=1
)

def StartTimer(self) -> None:
self.__startPoint = datetime.datetime.now()


+ 3
- 6
CAPI/python/PyAPI/Interface.py View File

@@ -5,7 +5,6 @@ import PyAPI.structures as THUAI6


class ILogic(metaclass=ABCMeta):

# IAPI统一可用的接口

@abstractmethod
@@ -155,12 +154,13 @@ class ILogic(metaclass=ABCMeta):
pass

@abstractmethod
def HaveView(self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int) -> bool:
def HaveView(
self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int
) -> bool:
pass


class IAPI(metaclass=ABCMeta):

# 选手可执行的操作
# 指挥本角色进行移动,`timeInMilliseconds` 为移动时间,单位为毫秒;`angleInRadian` 表示移动的方向,单位是弧度,使用极坐标——竖直向下方向为 x 轴,水平向右方向为 y 轴

@@ -346,7 +346,6 @@ class IAPI(metaclass=ABCMeta):


class IStudentAPI(IAPI, metaclass=ABCMeta):

# 人类阵营的特殊函数

@abstractmethod
@@ -371,7 +370,6 @@ class IStudentAPI(IAPI, metaclass=ABCMeta):


class ITrickerAPI(IAPI, metaclass=ABCMeta):

# 屠夫阵营的特殊函数

@abstractmethod
@@ -390,7 +388,6 @@ class IAI(metaclass=ABCMeta):


class IGameTimer(metaclass=ABCMeta):

# 用于计时的接口

@abstractmethod


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

@@ -15,6 +15,7 @@ class State:
self.mapInfo = THUAI6.GameMap()
self.gameInfo = THUAI6.GameInfo()
self.guids = []

teamScore: int
self: Union[THUAI6.Student, THUAI6.Tricker]



+ 59
- 55
CAPI/python/PyAPI/constants.py View File

@@ -10,18 +10,18 @@ class NoInstance:
class Constants(NoInstance):
frameDuration = 50 # 每帧毫秒数
numOfGridPerCell = 1000 # 单位坐标数
rows = 50 # 地图行数
cols = 50 # 地图列数
rows = 50 # 地图行数
cols = 50 # 地图列数

numOfClassroom = 10 # 教室数量
numOfChest = 8 # 宝箱数量
numOfChest = 8 # 宝箱数量

maxClassroomProgress = 10000000 # 教室最大进度
maxDoorProgress = 10000000 # 开关门最大进度
maxChestProgress = 10000000 # 宝箱最大进度
maxGateProgress = 18000 # 大门最大进度
maxDoorProgress = 10000000 # 开关门最大进度
maxChestProgress = 10000000 # 宝箱最大进度
maxGateProgress = 18000 # 大门最大进度

numOfRequiredClassroomForGate = 7 # 打开大门需要完成的教室数量
numOfRequiredClassroomForGate = 7 # 打开大门需要完成的教室数量
numOfRequiredClassroomForHiddenGate = 3 # 打开隐藏门需要完成的教室数量

# 人物属性相关
@@ -52,16 +52,16 @@ class Constants(NoInstance):
# 攻击相关

basicApOfTricker = 1500000
basicCD = 3000 # 初始子弹冷却
basicCastTime = 500 # 基本前摇时间
basicBackswing = 800 # 基本后摇时间
basicCD = 3000 # 初始子弹冷却
basicCastTime = 500 # 基本前摇时间
basicBackswing = 800 # 基本后摇时间
basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长
basicStunnedTimeOfStudent = 4300

basicBulletMoveSpeed = 7400 # 基本子弹移动速度
basicBulletMoveSpeed = 7400 # 基本子弹移动速度
basicRemoteAttackRange = 6000 # 基本远程攻击范围
basicAttackShortRange = 2200 # 基本近程攻击范围
basicBulletBombRange = 2000 # 基本子弹爆炸范围
basicAttackShortRange = 2200 # 基本近程攻击范围
basicBulletBombRange = 2000 # 基本子弹爆炸范围

# 道具相关

@@ -96,10 +96,10 @@ class Assassin:
concealment = 1.5 * Constants.basicConcealment
alertnessRadius = (int)(1.3 * Constants.basicTrickerAlertnessRadius)
viewRange = (int)(1.2 * Constants.basicTrickerViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
1.0 * Constants.basicTrickerSpeedOfClimbingThroughWindows)
1.0 * Constants.basicTrickerSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -108,10 +108,10 @@ class Klee:
concealment = 1.0 * Constants.basicConcealment
alertnessRadius = (int)(1.0 * Constants.basicTrickerAlertnessRadius)
viewRange = (int)(1.0 * Constants.basicTrickerViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
1.0 * Constants.basicTrickerSpeedOfClimbingThroughWindows)
1.0 * Constants.basicTrickerSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.1 * Constants.basicSpeedOfOpenChest)


@@ -120,10 +120,10 @@ class ANoisyPerson:
concealment = 0.8 * Constants.basicConcealment
alertnessRadius = (int)(0.9 * Constants.basicTrickerAlertnessRadius)
viewRange = (int)(1.0 * Constants.basicTrickerViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
1.1 * Constants.basicTrickerSpeedOfClimbingThroughWindows)
1.1 * Constants.basicTrickerSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.1 * Constants.basicSpeedOfOpenChest)


@@ -132,10 +132,10 @@ class Idol:
concealment = 0.75 * Constants.basicConcealment
alertnessRadius = (int)(1.0 * Constants.basicTrickerAlertnessRadius)
viewRange = (int)(1.1 * Constants.basicTrickerViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
1.0 * Constants.basicTrickerSpeedOfClimbingThroughWindows)
1.0 * Constants.basicTrickerSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -148,10 +148,10 @@ class Athlete:
concealment = 0.9 * Constants.basicConcealment
alertnessRadius = (int)(1.0 * Constants.basicStudentAlertnessRadius)
viewRange = (int)(1.1 * Constants.basicStudentViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
1.2 * Constants.basicStudentSpeedOfClimbingThroughWindows)
1.2 * Constants.basicStudentSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -164,10 +164,10 @@ class Teacher:
concealment = 0.5 * Constants.basicConcealment
alertnessRadius = (int)(0.5 * Constants.basicStudentAlertnessRadius)
viewRange = (int)(0.9 * Constants.basicStudentViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
0.5 * Constants.basicStudentSpeedOfClimbingThroughWindows)
0.5 * Constants.basicStudentSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -180,10 +180,10 @@ class StraightAStudent:
concealment = 0.9 * Constants.basicConcealment
alertnessRadius = (int)(0.9 * Constants.basicStudentAlertnessRadius)
viewRange = (int)(0.9 * Constants.basicStudentViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
0.83333 * Constants.basicStudentSpeedOfClimbingThroughWindows)
0.83333 * Constants.basicStudentSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -196,10 +196,10 @@ class Robot:
concealment = 1.0 * Constants.basicConcealment
alertnessRadius = (int)(1.0 * Constants.basicStudentAlertnessRadius)
viewRange = (int)(1.0 * Constants.basicStudentViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
0.0016 * Constants.basicStudentSpeedOfClimbingThroughWindows)
0.0016 * Constants.basicStudentSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -212,10 +212,10 @@ class TechOtaku:
concealment = 1.0 * Constants.basicConcealment
alertnessRadius = (int)(1.0 * Constants.basicStudentAlertnessRadius)
viewRange = (int)(0.9 * Constants.basicStudentViewRange)
speedOfOpeningOrLocking = (int)(
1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(1.0 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
0.75 * Constants.basicStudentSpeedOfClimbingThroughWindows)
0.75 * Constants.basicStudentSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(1.0 * Constants.basicSpeedOfOpenChest)


@@ -228,10 +228,10 @@ class Sunshine:
concealment = 1.0 * Constants.basicConcealment
alertnessRadius = (int)(1.0 * Constants.basicStudentAlertnessRadius)
viewRange = (int)(1.0 * Constants.basicStudentViewRange)
speedOfOpeningOrLocking = (int)(
0.7 * Constants.basicSpeedOfOpeningOrLocking)
speedOfOpeningOrLocking = (int)(0.7 * Constants.basicSpeedOfOpeningOrLocking)
speedOfClimbingThroughWindows = (int)(
1.0 * Constants.basicStudentSpeedOfClimbingThroughWindows)
1.0 * Constants.basicStudentSpeedOfClimbingThroughWindows
)
speedOfOpenChest = (int)(0.9 * Constants.basicSpeedOfOpenChest)


@@ -299,6 +299,7 @@ class SummonGolem:
skillCD = (int)(1.0 * Constants.commonSkillCD)
durationTime = (int)(0.0 * Constants.commonSkillTime)


class CommonAttackOfTricker:
BulletBombRange = 0
BulletAttackRange = Constants.basicAttackShortRange
@@ -310,34 +311,37 @@ class CommonAttackOfTricker:
RecoveryFromHit = Constants.basicRecoveryFromHit
cd = Constants.basicBackswing
maxBulletNum = 1


class FlyingKnife:
BulletBombRange = 0
BulletAttackRange = Constants.basicRemoteAttackRange * 13
ap = Constants.basicApOfTricker* 4 / 5
Speed = Constants.basicBulletMoveSpeed* 25 / 10
ap = Constants.basicApOfTricker * 4 / 5
Speed = Constants.basicBulletMoveSpeed * 25 / 10
IsRemoteAttack = True
CastTime = Constants.basicCastTime * 4 / 5
Backswing =0
RecoveryFromHit =0
Backswing = 0
RecoveryFromHit = 0
cd = Constants.basicBackswing / 2
maxBulletNum = 1


class BombBomb:
BulletBombRange = Constants.basicBulletBombRange
BulletAttackRange = Constants.basicAttackShortRange
ap = Constants.basicApOfTricker * 6 / 5
Speed = Constants.basicBulletMoveSpeed* 30 / 37
Speed = Constants.basicBulletMoveSpeed * 30 / 37
IsRemoteAttack = False
CastTime = BulletAttackRange * 1000 / Speed
Backswing =Constants.basicRecoveryFromHit
RecoveryFromHit =Constants.basicRecoveryFromHit
Backswing = Constants.basicRecoveryFromHit
RecoveryFromHit = Constants.basicRecoveryFromHit
cd = Constants.basicCD
maxBulletNum = 1


class JumpyDumpty:
BulletBombRange = Constants.basicBulletBombRange / 2
BulletAttackRange = Constants.basicRemoteAttackRange * 2
ap = (int)(Constants.basicApOfTricker* 0.6)
Speed = Constants.basicBulletMoveSpeed* 43 / 37
ap = (int)(Constants.basicApOfTricker * 0.6)
Speed = Constants.basicBulletMoveSpeed * 43 / 37
IsRemoteAttack = False

+ 225
- 79
CAPI/python/PyAPI/logic.py View File

@@ -20,7 +20,6 @@ from PyAPI.Interface import ILogic, IGameTimer

class Logic(ILogic):
def __init__(self, playerID: int, playerType: THUAI6.PlayerType) -> None:

# ID
self.__playerID: int = playerID

@@ -103,7 +102,12 @@ class Logic(ILogic):

def GetPlaceType(self, x: int, y: int) -> THUAI6.PlaceType:
with self.__mtxState:
if x < 0 or x >= len(self.__currentState.gameMap) or y < 0 or y >= len(self.__currentState.gameMap[0]):
if (
x < 0
or x >= len(self.__currentState.gameMap)
or y < 0
or y >= len(self.__currentState.gameMap[0])
):
self.__logger.warning("Invalid position")
return THUAI6.PlaceType.NullPlaceType
self.__logger.debug("Called GetPlaceType")
@@ -149,7 +153,9 @@ class Logic(ILogic):
with self.__mtxState:
self.__logger.debug("Called GetHiddenGateState")
if (x, y) in self.__currentState.mapInfo.hiddenGateState:
return copy.deepcopy(self.__currentState.mapInfo.hiddenGateState[(x, y)])
return copy.deepcopy(
self.__currentState.mapInfo.hiddenGateState[(x, y)]
)
else:
self.__logger.warning("HiddenGate not found")
return THUAI6.HiddenGateState.Null
@@ -262,9 +268,13 @@ class Logic(ILogic):
self.__logger.debug("Called EndAllAction")
return self.__comm.EndAllAction(self.__playerID)

def HaveView(self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int) -> bool:
def HaveView(
self, gridX: int, gridY: int, selfX: int, selfY: int, viewRange: int
) -> bool:
with self.__mtxState:
return AssistFunction.HaveView(viewRange, selfX, selfY, gridX, gridY, self.__currentState.gameMap)
return AssistFunction.HaveView(
viewRange, selfX, selfY, gridX, gridY, self.__currentState.gameMap
)

# Logic内部逻辑
def __TryConnection(self) -> bool:
@@ -281,8 +291,7 @@ class Logic(ILogic):
# 读取消息,无消息时此处阻塞
clientMsg = self.__comm.GetMessage2Client()
self.__logger.debug("Get message from server!")
self.__gameState = Proto2THUAI6.gameStateDict[
clientMsg.game_state]
self.__gameState = Proto2THUAI6.gameStateDict[clientMsg.game_state]

if self.__gameState == THUAI6.GameState.GameStart:
# 读取玩家的GUID
@@ -294,8 +303,7 @@ class Logic(ILogic):
for row in obj.map_message.row:
col: List[THUAI6.PlaceType] = []
for place in row.col:
col.append(
Proto2THUAI6.placeTypeDict[place])
col.append(Proto2THUAI6.placeTypeDict[place])
gameMap.append(col)
self.__currentState.gameMap = gameMap
self.__bufferState.gameMap = gameMap
@@ -330,127 +338,238 @@ class Logic(ILogic):
if item.WhichOneof("message_of_obj") == "student_message":
if item.student_message.player_id == self.__playerID:
self.__bufferState.self = Proto2THUAI6.Protobuf2THUAI6Student(
item.student_message)
self.__bufferState.students.append(
self.__bufferState.self)
item.student_message
)
self.__bufferState.students.append(self.__bufferState.self)
else:
self.__bufferState.students.append(
Proto2THUAI6.Protobuf2THUAI6Student(item.student_message))
Proto2THUAI6.Protobuf2THUAI6Student(item.student_message)
)
self.__logger.debug("Add Student!")
else:
for item in message.obj_message:
if item.WhichOneof("message_of_obj") == "tricker_message":
if item.tricker_message.player_id == self.__playerID:
self.__bufferState.self = Proto2THUAI6.Protobuf2THUAI6Tricker(
item.tricker_message)
self.__bufferState.trickers.append(
self.__bufferState.self)
item.tricker_message
)
self.__bufferState.trickers.append(self.__bufferState.self)
else:
self.__bufferState.trickers.append(
Proto2THUAI6.Protobuf2THUAI6Tricker(item.tricker_message))
Proto2THUAI6.Protobuf2THUAI6Tricker(item.tricker_message)
)
self.__logger.debug("Add Tricker!")

def __LoadBufferCase(self, item: Message2Clients.MessageOfObj) -> None:
if self.__playerType == THUAI6.PlayerType.StudentPlayer and item.WhichOneof("message_of_obj") == "tricker_message":
if (
self.__playerType == THUAI6.PlayerType.StudentPlayer
and item.WhichOneof("message_of_obj") == "tricker_message"
):
if MessageType.TRICKER_INVISIBLE in item.tricker_message.buff:
return
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.tricker_message.x, item.tricker_message.y, self.__bufferState.gameMap):
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.tricker_message.x,
item.tricker_message.y,
self.__bufferState.gameMap,
):
self.__bufferState.trickers.append(
Proto2THUAI6.Protobuf2THUAI6Tricker(item.tricker_message))
Proto2THUAI6.Protobuf2THUAI6Tricker(item.tricker_message)
)
self.__logger.debug("Add Tricker!")
elif self.__playerType == THUAI6.PlayerType.TrickerPlayer and item.WhichOneof("message_of_obj") == "student_message":
elif (
self.__playerType == THUAI6.PlayerType.TrickerPlayer
and item.WhichOneof("message_of_obj") == "student_message"
):
if THUAI6.TrickerBuffType.Clairaudience in self.__bufferState.self.buff:
self.__bufferState.students.append(
Proto2THUAI6.Protobuf2THUAI6Student(item.student_message))
Proto2THUAI6.Protobuf2THUAI6Student(item.student_message)
)
self.__logger.debug("Add Student!")
return
if MessageType.STUDENT_INVISIBLE in item.student_message.buff:
return
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.student_message.x, item.student_message.y, self.__bufferState.gameMap):
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.student_message.x,
item.student_message.y,
self.__bufferState.gameMap,
):
self.__bufferState.students.append(
Proto2THUAI6.Protobuf2THUAI6Student(item.student_message))
Proto2THUAI6.Protobuf2THUAI6Student(item.student_message)
)
self.__logger.debug("Add Student!")
elif item.WhichOneof("message_of_obj") == "prop_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.prop_message.x, item.prop_message.y, self.__bufferState.gameMap):
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.prop_message.x,
item.prop_message.y,
self.__bufferState.gameMap,
):
self.__bufferState.props.append(
Proto2THUAI6.Protobuf2THUAI6Prop(item.prop_message))
Proto2THUAI6.Protobuf2THUAI6Prop(item.prop_message)
)
self.__logger.debug("Add Prop!")
elif item.WhichOneof("message_of_obj") == "bullet_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.bullet_message.x, item.bullet_message.y, self.__bufferState.gameMap):
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.bullet_message.x,
item.bullet_message.y,
self.__bufferState.gameMap,
):
self.__bufferState.bullets.append(
Proto2THUAI6.Protobuf2THUAI6Bullet(item.bullet_message))
Proto2THUAI6.Protobuf2THUAI6Bullet(item.bullet_message)
)
self.__logger.debug("Add Bullet!")
elif item.WhichOneof("message_of_obj") == "classroom_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.classroom_message.x, item.classroom_message.y, self.__bufferState.gameMap):
pos = (AssistFunction.GridToCell(
item.classroom_message.x), AssistFunction.GridToCell(item.classroom_message.y))
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.classroom_message.x,
item.classroom_message.y,
self.__bufferState.gameMap,
):
pos = (
AssistFunction.GridToCell(item.classroom_message.x),
AssistFunction.GridToCell(item.classroom_message.y),
)
if pos not in self.__bufferState.mapInfo.classroomState:
self.__bufferState.mapInfo.classroomState[pos] = item.classroom_message.progress
self.__bufferState.mapInfo.classroomState[
pos
] = item.classroom_message.progress
self.__logger.debug("Add Classroom!")
else:
self.__bufferState.mapInfo.classroomState[pos] = item.classroom_message.progress
self.__bufferState.mapInfo.classroomState[
pos
] = item.classroom_message.progress
self.__logger.debug("Update Classroom!")
elif item.WhichOneof("message_of_obj") == "chest_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.chest_message.x, item.chest_message.y, self.__bufferState.gameMap):
pos = (AssistFunction.GridToCell(
item.chest_message.x), AssistFunction.GridToCell(item.chest_message.y))
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.chest_message.x,
item.chest_message.y,
self.__bufferState.gameMap,
):
pos = (
AssistFunction.GridToCell(item.chest_message.x),
AssistFunction.GridToCell(item.chest_message.y),
)
if pos not in self.__bufferState.mapInfo.chestState:
self.__bufferState.mapInfo.chestState[pos] = item.chest_message.progress
self.__logger.debug(
f"Add Chest at {pos[0]}, {pos[1]}")
self.__bufferState.mapInfo.chestState[
pos
] = item.chest_message.progress
self.__logger.debug(f"Add Chest at {pos[0]}, {pos[1]}")
else:
self.__bufferState.mapInfo.chestState[pos] = item.chest_message.progress
self.__logger.debug(
f"Update Chest at {pos[0]}, {pos[1]}")
self.__bufferState.mapInfo.chestState[
pos
] = item.chest_message.progress
self.__logger.debug(f"Update Chest at {pos[0]}, {pos[1]}")
elif item.WhichOneof("message_of_obj") == "door_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.door_message.x, item.door_message.y, self.__bufferState.gameMap):
pos = (AssistFunction.GridToCell(
item.door_message.x), AssistFunction.GridToCell(item.door_message.y))
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.door_message.x,
item.door_message.y,
self.__bufferState.gameMap,
):
pos = (
AssistFunction.GridToCell(item.door_message.x),
AssistFunction.GridToCell(item.door_message.y),
)
if pos not in self.__bufferState.mapInfo.doorState:
self.__bufferState.mapInfo.doorState[pos] = item.door_message.is_open
self.__bufferState.mapInfo.doorProgress[pos] = item.door_message.progress
self.__bufferState.mapInfo.doorState[
pos
] = item.door_message.is_open
self.__bufferState.mapInfo.doorProgress[
pos
] = item.door_message.progress
self.__logger.debug("Add Door!")
else:
self.__bufferState.mapInfo.doorState[pos] = item.door_message.is_open
self.__bufferState.mapInfo.doorProgress[pos] = item.door_message.progress
self.__bufferState.mapInfo.doorState[
pos
] = item.door_message.is_open
self.__bufferState.mapInfo.doorProgress[
pos
] = item.door_message.progress
self.__logger.debug("Update Door!")
elif item.WhichOneof("message_of_obj") == "hidden_gate_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.hidden_gate_message.x, item.hidden_gate_message.y, self.__bufferState.gameMap):
pos = (AssistFunction.GridToCell(
item.hidden_gate_message.x), AssistFunction.GridToCell(item.hidden_gate_message.y))
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.hidden_gate_message.x,
item.hidden_gate_message.y,
self.__bufferState.gameMap,
):
pos = (
AssistFunction.GridToCell(item.hidden_gate_message.x),
AssistFunction.GridToCell(item.hidden_gate_message.y),
)
if pos not in self.__bufferState.mapInfo.hiddenGateState:
self.__bufferState.mapInfo.hiddenGateState[pos] = Proto2THUAI6.Bool2HiddenGateState(
item.hidden_gate_message.opened)
self.__bufferState.mapInfo.hiddenGateState[
pos
] = Proto2THUAI6.Bool2HiddenGateState(
item.hidden_gate_message.opened
)
self.__logger.debug("Add HiddenGate!")
else:
self.__bufferState.mapInfo.hiddenGateState[pos] = Proto2THUAI6.Bool2HiddenGateState(
item.hidden_gate_message.opened)
self.__bufferState.mapInfo.hiddenGateState[
pos
] = Proto2THUAI6.Bool2HiddenGateState(
item.hidden_gate_message.opened
)
self.__logger.debug("Update HiddenGate!")
elif item.WhichOneof("message_of_obj") == "gate_message":
if AssistFunction.HaveView(self.__bufferState.self.viewRange, self.__bufferState.self.x, self.__bufferState.self.y, item.gate_message.x, item.gate_message.y, self.__bufferState.gameMap):
pos = (AssistFunction.GridToCell(
item.gate_message.x), AssistFunction.GridToCell(item.gate_message.y))
if AssistFunction.HaveView(
self.__bufferState.self.viewRange,
self.__bufferState.self.x,
self.__bufferState.self.y,
item.gate_message.x,
item.gate_message.y,
self.__bufferState.gameMap,
):
pos = (
AssistFunction.GridToCell(item.gate_message.x),
AssistFunction.GridToCell(item.gate_message.y),
)
if pos not in self.__bufferState.mapInfo.gateState:
self.__bufferState.mapInfo.gateState[pos] = item.gate_message.progress
self.__bufferState.mapInfo.gateState[
pos
] = item.gate_message.progress
self.__logger.debug("Add Gate!")
else:
self.__bufferState.mapInfo.gateState[pos] = item.gate_message.progress
self.__bufferState.mapInfo.gateState[
pos
] = item.gate_message.progress
self.__logger.debug("Update Gate!")
elif item.WhichOneof("message_of_obj") == "news_message":
if item.news_message.to_id == self.__playerID:
if item.news_message.WhichOneof("news") == "text_message":
self.__messageQueue.put(
(item.news_message.from_id, item.news_message.text_message))
(item.news_message.from_id, item.news_message.text_message)
)
self.__logger.debug("Add News!")
elif item.news_message.WhichOneof("news") == "binary_message":
self.__messageQueue.put(
(item.news_message.from_id, item.news_message.binary_message))
(item.news_message.from_id, item.news_message.binary_message)
)
self.__logger.debug("Add News!")
else:
self.__logger.error("Unknown News!")
else:
self.__logger.debug(
"Unknown Message!")
self.__logger.debug("Unknown Message!")

def __LoadBuffer(self, message: Message2Clients.MessageToClient) -> None:
with self.__cvBuffer:
@@ -470,14 +589,18 @@ class Logic(ILogic):
self.__bufferState.guids.append(obj.tricker_message.guid)

self.__bufferState.gameInfo = Proto2THUAI6.Protobuf2THUAI6GameInfo(
message.all_message)
message.all_message
)

self.__LoadBufferSelf(message)
for item in message.obj_message:
self.__LoadBufferCase(item)
if Setting.asynchronous():
with self.__mtxState:
self.__currentState, self.__bufferState = self.__bufferState, self.__currentState
self.__currentState, self.__bufferState = (
self.__bufferState,
self.__currentState,
)
self.__counterState = self.__counterBuffer
self.__logger.info("Update state!")
self.__freshed = True
@@ -496,7 +619,10 @@ class Logic(ILogic):
with self.__cvBuffer:
self.__cvBuffer.wait_for(lambda: self.__bufferUpdated)
with self.__mtxState:
self.__bufferState, self.__currentState = self.__currentState, self.__bufferState
self.__bufferState, self.__currentState = (
self.__currentState,
self.__bufferState,
)
self.__counterState = self.__counterBuffer
self.__bufferUpdated = False
self.__logger.info("Update state!")
@@ -506,12 +632,21 @@ class Logic(ILogic):
with self.__cvBuffer:
self.__cvBuffer.wait_for(lambda: self.__freshed)

def Main(self, createAI: Callable, IP: str, port: str, file: bool, screen: bool, warnOnly: bool) -> None:

def Main(
self,
createAI: Callable,
IP: str,
port: str,
file: bool,
screen: bool,
warnOnly: bool,
) -> None:
# 建立日志组件
self.__logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s", '%H:%M:%S')
"[%(name)s] [%(asctime)s.%(msecs)03d] [%(levelname)s] %(message)s",
"%H:%M:%S",
)
# 确保文件存在
# if not os.path.exists(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/logs"):
# os.makedirs(os.path.dirname(os.path.dirname(
@@ -519,13 +654,21 @@ class Logic(ILogic):

if platform.system().lower() == "windows":
os.system(
f"mkdir \"{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}\\logs\"")
f'mkdir "{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}\\logs"'
)
else:
os.system(
f"mkdir -p \"{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}/logs\"")

fileHandler = logging.FileHandler(os.path.dirname(
os.path.dirname(os.path.realpath(__file__))) + "/logs/logic" + str(self.__playerID) + "-log.txt", "w+", encoding="utf-8")
f'mkdir -p "{os.path.dirname(os.path.dirname(os.path.realpath(__file__)))}/logs"'
)

fileHandler = logging.FileHandler(
os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+ "/logs/logic"
+ str(self.__playerID)
+ "-log.txt",
"w+",
encoding="utf-8",
)
screenHandler = logging.StreamHandler()
if file:
fileHandler.setLevel(logging.DEBUG)
@@ -555,13 +698,15 @@ class Logic(ILogic):
self.__timer = StudentAPI(self)
else:
self.__timer = StudentDebugAPI(
self, file, screen, warnOnly, self.__playerID)
self, file, screen, warnOnly, self.__playerID
)
elif self.__playerType == THUAI6.PlayerType.TrickerPlayer:
if not file and not screen:
self.__timer = TrickerAPI(self)
else:
self.__timer = TrickerDebugAPI(
self, file, screen, warnOnly, self.__playerID)
self, file, screen, warnOnly, self.__playerID
)

# 构建AI线程
def AIThread():
@@ -583,7 +728,8 @@ class Logic(ILogic):

if self.__TryConnection():
self.__logger.info(
"Connect to the server successfully, AI thread will be started.")
"Connect to the server successfully, AI thread will be started."
)
self.__threadAI = threading.Thread(target=AIThread)
self.__threadAI.start()
self.__ProcessMessage()


+ 47
- 16
CAPI/python/PyAPI/main.py View File

@@ -1,8 +1,8 @@
import os
import sys

sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path.append(os.path.dirname(os.path.dirname(
os.path.realpath(__file__))) + '/proto')
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + "/proto")

from PyAPI.Interface import IAI
from PyAPI.AI import AI
@@ -42,19 +42,50 @@ def THUAI6Main(argv: List[str], AIBuilder: Callable) -> None:
screen: bool = True
warnOnly: bool = False
parser = argparse.ArgumentParser(
description="THUAI6 Python Interface Commandline Parameter Introduction")
parser.add_argument("-I", type=str, required=True,
help="Server`s IP 127.0.0.1 in default", dest="sIP", default="127.0.0.1")
parser.add_argument("-P", type=str, required=True,
help="Server`s Port 8888 in default", dest="sPort", default="8888")
parser.add_argument("-p", type=int, required=True,
help="Player`s ID", dest="pID", choices=[0, 1, 2, 3, 4])
parser.add_argument("-d", action='store_true',
help="Set this flag to save the debug log to ./logs folder", dest="file")
parser.add_argument("-o", action='store_true',
help="Set this flag to print the debug log to the screen", dest="screen")
parser.add_argument("-w", action='store_true',
help="Set this flag to only print warning on the screen", dest="warnOnly")
description="THUAI6 Python Interface Commandline Parameter Introduction"
)
parser.add_argument(
"-I",
type=str,
required=True,
help="Server`s IP 127.0.0.1 in default",
dest="sIP",
default="127.0.0.1",
)
parser.add_argument(
"-P",
type=str,
required=True,
help="Server`s Port 8888 in default",
dest="sPort",
default="8888",
)
parser.add_argument(
"-p",
type=int,
required=True,
help="Player`s ID",
dest="pID",
choices=[0, 1, 2, 3, 4],
)
parser.add_argument(
"-d",
action="store_true",
help="Set this flag to save the debug log to ./logs folder",
dest="file",
)
parser.add_argument(
"-o",
action="store_true",
help="Set this flag to print the debug log to the screen",
dest="screen",
)
parser.add_argument(
"-w",
action="store_true",
help="Set this flag to only print warning on the screen",
dest="warnOnly",
)
args = parser.parse_args()
pID = args.pID
sIP = args.sIP
@@ -79,5 +110,5 @@ def CreateAI(pID: int) -> IAI:
return AI(pID)


if __name__ == '__main__':
if __name__ == "__main__":
THUAI6Main(sys.argv, CreateAI)

+ 115
- 52
CAPI/python/PyAPI/utils.py View File

@@ -15,7 +15,6 @@ class NoInstance:


class AssistFunction(NoInstance):

@staticmethod
def CellToGrid(cell: int) -> int:
return cell * numOfGridPerCell + numOfGridPerCell // 2
@@ -25,14 +24,19 @@ class AssistFunction(NoInstance):
return grid // numOfGridPerCell

@staticmethod
def HaveView(viewRange: int, x: int, y: int, newX: int, newY: int, map: List[List[THUAI6.PlaceType]]) -> bool:
def HaveView(
viewRange: int,
x: int,
y: int,
newX: int,
newY: int,
map: List[List[THUAI6.PlaceType]],
) -> bool:
deltaX: int = newX - x
deltaY: int = newY - y
distance: float = deltaX**2 + deltaY**2
myPlace = map[AssistFunction.GridToCell(
x)][AssistFunction.GridToCell(y)]
newPlace = map[AssistFunction.GridToCell(
newX)][AssistFunction.GridToCell(newY)]
myPlace = map[AssistFunction.GridToCell(x)][AssistFunction.GridToCell(y)]
newPlace = map[AssistFunction.GridToCell(newX)][AssistFunction.GridToCell(newY)]
if myPlace != THUAI6.PlaceType.Grass and newPlace == THUAI6.PlaceType.Grass:
return False
if distance <= viewRange * viewRange:
@@ -47,7 +51,12 @@ class AssistFunction(NoInstance):
for i in range(divide):
selfX += dx
selfY += dy
if map[AssistFunction.GridToCell(int(selfX))][AssistFunction.GridToCell(int(selfY))] != THUAI6.PlaceType.Grass:
if (
map[AssistFunction.GridToCell(int(selfX))][
AssistFunction.GridToCell(int(selfY))
]
!= THUAI6.PlaceType.Grass
):
return False
else:
return True
@@ -55,7 +64,12 @@ class AssistFunction(NoInstance):
for i in range(divide):
selfX += dx
selfY += dy
if map[AssistFunction.GridToCell(int(selfX))][AssistFunction.GridToCell(int(selfY))] == THUAI6.PlaceType.Wall:
if (
map[AssistFunction.GridToCell(int(selfX))][
AssistFunction.GridToCell(int(selfY))
]
== THUAI6.PlaceType.Wall
):
return False
else:
return True
@@ -76,12 +90,14 @@ class Proto2THUAI6(NoInstance):
MessageType.DOOR3: THUAI6.PlaceType.Door3,
MessageType.DOOR5: THUAI6.PlaceType.Door5,
MessageType.DOOR6: THUAI6.PlaceType.Door6,
MessageType.CHEST: THUAI6.PlaceType.Chest, }
MessageType.CHEST: THUAI6.PlaceType.Chest,
}

shapeTypeDict: Final[dict] = {
MessageType.NULL_SHAPE_TYPE: THUAI6.ShapeType.NullShapeType,
MessageType.SQUARE: THUAI6.ShapeType.Square,
MessageType.CIRCLE: THUAI6.ShapeType.Circle}
MessageType.CIRCLE: THUAI6.ShapeType.Circle,
}

propTypeDict: Final[dict] = {
MessageType.NULL_PROP_TYPE: THUAI6.PropType.NullPropType,
@@ -92,12 +108,14 @@ class Proto2THUAI6(NoInstance):
MessageType.ADD_HP_OR_AP: THUAI6.PropType.AddHpOrAp,
MessageType.ADD_LIFE_OR_CLAIRAUDIENCE: THUAI6.PropType.AddLifeOrClairaudience,
MessageType.SHIELD_OR_SPEAR: THUAI6.PropType.ShieldOrSpear,
MessageType.RECOVERY_FROM_DIZZINESS: THUAI6.PropType.RecoveryFromDizziness, }
MessageType.RECOVERY_FROM_DIZZINESS: THUAI6.PropType.RecoveryFromDizziness,
}

playerTypeDict: Final[dict] = {
MessageType.NULL_PLAYER_TYPE: THUAI6.PlayerType.NullPlayerType,
MessageType.STUDENT_PLAYER: THUAI6.PlayerType.StudentPlayer,
MessageType.TRICKER_PLAYER: THUAI6.PlayerType.TrickerPlayer, }
MessageType.TRICKER_PLAYER: THUAI6.PlayerType.TrickerPlayer,
}

studentTypeDict: Final[dict] = {
MessageType.NULL_STUDENT_TYPE: THUAI6.StudentType.NullStudentType,
@@ -106,21 +124,24 @@ class Proto2THUAI6(NoInstance):
MessageType.STRAIGHT_A_STUDENT: THUAI6.StudentType.StraightAStudent,
MessageType.ROBOT: THUAI6.StudentType.Robot,
MessageType.TECH_OTAKU: THUAI6.StudentType.TechOtaku,
MessageType.SUNSHINE: THUAI6.StudentType.Sunshine, }
MessageType.SUNSHINE: THUAI6.StudentType.Sunshine,
}

trickerTypeDict: Final[dict] = {
MessageType.NULL_TRICKER_TYPE: THUAI6.TrickerType.NullTrickerType,
MessageType.ASSASSIN: THUAI6.TrickerType.Assassin,
MessageType.KLEE: THUAI6.TrickerType.Klee,
MessageType.A_NOISY_PERSON: THUAI6.TrickerType.ANoisyPerson,
MessageType.IDOL: THUAI6.TrickerType.Idol, }
MessageType.IDOL: THUAI6.TrickerType.Idol,
}

studentBuffTypeDict: Final[dict] = {
MessageType.NULL_SBUFF_TYPE: THUAI6.StudentBuffType.NullStudentBuffType,
MessageType.STUDENT_ADD_SPEED: THUAI6.StudentBuffType.AddSpeed,
MessageType.ADD_LIFE: THUAI6.StudentBuffType.AddLife,
MessageType.SHIELD: THUAI6.StudentBuffType.Shield,
MessageType.STUDENT_INVISIBLE: THUAI6.StudentBuffType.Invisible, }
MessageType.STUDENT_INVISIBLE: THUAI6.StudentBuffType.Invisible,
}

trickerBuffTypeDict: Final[dict] = {
MessageType.NULL_TBUFF_TYPE: THUAI6.TrickerBuffType.NullTrickerBuffType,
@@ -128,7 +149,8 @@ class Proto2THUAI6(NoInstance):
MessageType.SPEAR: THUAI6.TrickerBuffType.Spear,
MessageType.ADD_AP: THUAI6.TrickerBuffType.AddAp,
MessageType.CLAIRAUDIENCE: THUAI6.TrickerBuffType.Clairaudience,
MessageType.TRICKER_INVISIBLE: THUAI6.TrickerBuffType.Invisible, }
MessageType.TRICKER_INVISIBLE: THUAI6.TrickerBuffType.Invisible,
}

playerStateDict: Final[dict] = {
MessageType.NULL_STATUS: THUAI6.PlayerState.NullState,
@@ -149,13 +171,15 @@ class Proto2THUAI6(NoInstance):
MessageType.CLIMBING: THUAI6.PlayerState.Climbing,
MessageType.OPENING_A_CHEST: THUAI6.PlayerState.OpeningAChest,
MessageType.USING_SPECIAL_SKILL: THUAI6.PlayerState.UsingSpecialSkill,
MessageType.OPENING_A_GATE: THUAI6.PlayerState.OpeningAGate, }
MessageType.OPENING_A_GATE: THUAI6.PlayerState.OpeningAGate,
}

gameStateDict: Final[dict] = {
MessageType.NULL_GAME_STATE: THUAI6.GameState.NullGameState,
MessageType.GAME_START: THUAI6.GameState.GameStart,
MessageType.GAME_RUNNING: THUAI6.GameState.GameRunning,
MessageType.GAME_END: THUAI6.GameState.GameEnd}
MessageType.GAME_END: THUAI6.GameState.GameEnd,
}

bulletTypeDict: Final[dict] = {
MessageType.NULL_BULLET_TYPE: THUAI6.BulletType.NullBulletType,
@@ -163,11 +187,14 @@ class Proto2THUAI6(NoInstance):
MessageType.BOMB_BOMB: THUAI6.BulletType.BombBomb,
MessageType.COMMON_ATTACK_OF_TRICKER: THUAI6.BulletType.CommonAttackOfTricker,
MessageType.JUMPY_DUMPTY: THUAI6.BulletType.JumpyDumpty,
MessageType.ATOM_BOMB: THUAI6.BulletType.AtomBomb, }
MessageType.ATOM_BOMB: THUAI6.BulletType.AtomBomb,
}

# 用于将Proto的对象转为THUAI6的对象
@ staticmethod
def Protobuf2THUAI6Tricker(trickerMsg: Message2Clients.MessageOfTricker) -> THUAI6.Tricker:
@staticmethod
def Protobuf2THUAI6Tricker(
trickerMsg: Message2Clients.MessageOfTricker,
) -> THUAI6.Tricker:
tricker = THUAI6.Tricker()
tricker.x = trickerMsg.x
tricker.y = trickerMsg.y
@@ -192,8 +219,10 @@ class Proto2THUAI6(NoInstance):
tricker.playerType = THUAI6.PlayerType.TrickerPlayer
return tricker

@ staticmethod
def Protobuf2THUAI6Student(studentMsg: Message2Clients.MessageOfStudent) -> THUAI6.Student:
@staticmethod
def Protobuf2THUAI6Student(
studentMsg: Message2Clients.MessageOfStudent,
) -> THUAI6.Student:
student = THUAI6.Student()
student.x = studentMsg.x
student.y = studentMsg.y
@@ -223,7 +252,7 @@ class Proto2THUAI6(NoInstance):
student.playerType = THUAI6.PlayerType.StudentPlayer
return student

@ staticmethod
@staticmethod
def Protobuf2THUAI6Prop(propMsg: Message2Clients.MessageOfProp) -> THUAI6.Prop:
prop = THUAI6.Prop()
prop.x = propMsg.x
@@ -233,7 +262,7 @@ class Proto2THUAI6(NoInstance):
prop.facingDirection = propMsg.facing_direction
return prop

@ staticmethod
@staticmethod
def Protobuf2THUAI6GameInfo(allMsg: Message2Clients.MessageOfAll):
gameInfo = THUAI6.GameInfo()
gameInfo.gameTime = allMsg.game_time
@@ -244,8 +273,10 @@ class Proto2THUAI6(NoInstance):
gameInfo.trickerScore = allMsg.tricker_score
return gameInfo

@ staticmethod
def Protobuf2THUAI6Bullet(bulletMsg: Message2Clients.MessageOfBullet) -> THUAI6.Bullet:
@staticmethod
def Protobuf2THUAI6Bullet(
bulletMsg: Message2Clients.MessageOfBullet,
) -> THUAI6.Bullet:
bullet = THUAI6.Bullet()
bullet.x = bulletMsg.x
bullet.y = bulletMsg.y
@@ -256,8 +287,10 @@ class Proto2THUAI6(NoInstance):
bullet.bombRange = bulletMsg.bomb_range
return bullet

@ staticmethod
def Protobuf2THUAI6BombedBullet(bulletMsg: Message2Clients.MessageOfBombedBullet) -> THUAI6.BombedBullet:
@staticmethod
def Protobuf2THUAI6BombedBullet(
bulletMsg: Message2Clients.MessageOfBombedBullet,
) -> THUAI6.BombedBullet:
bullet = THUAI6.BombedBullet()
bullet.x = bulletMsg.x
bullet.y = bulletMsg.y
@@ -267,7 +300,7 @@ class Proto2THUAI6(NoInstance):
bullet.bombRange = bulletMsg.bomb_range
return bullet

@ staticmethod
@staticmethod
def Bool2HiddenGateState(gateMsg: bool) -> THUAI6.HiddenGateState:
if gateMsg:
return THUAI6.HiddenGateState.Opened
@@ -288,12 +321,14 @@ class THUAI62Proto(NoInstance):
THUAI6.PlaceType.Door5: MessageType.DOOR5,
THUAI6.PlaceType.Door6: MessageType.DOOR6,
THUAI6.PlaceType.Chest: MessageType.CHEST,
THUAI6.PlaceType.Window: MessageType.WINDOW, }
THUAI6.PlaceType.Window: MessageType.WINDOW,
}

playerTypeDict: Final[dict] = {
THUAI6.PlayerType.NullPlayerType: MessageType.NULL_PLAYER_TYPE,
THUAI6.PlayerType.StudentPlayer: MessageType.STUDENT_PLAYER,
THUAI6.PlayerType.TrickerPlayer: MessageType.TRICKER_PLAYER}
THUAI6.PlayerType.TrickerPlayer: MessageType.TRICKER_PLAYER,
}

studentTypeDict: Final[dict] = {
THUAI6.StudentType.NullStudentType: MessageType.NULL_STUDENT_TYPE,
@@ -302,14 +337,16 @@ class THUAI62Proto(NoInstance):
THUAI6.StudentType.StraightAStudent: MessageType.STRAIGHT_A_STUDENT,
THUAI6.StudentType.Robot: MessageType.ROBOT,
THUAI6.StudentType.TechOtaku: MessageType.TECH_OTAKU,
THUAI6.StudentType.Sunshine: MessageType.SUNSHINE, }
THUAI6.StudentType.Sunshine: MessageType.SUNSHINE,
}

trickerTypeDict: Final[dict] = {
THUAI6.TrickerType.NullTrickerType: MessageType.NULL_TRICKER_TYPE,
THUAI6.TrickerType.Assassin: MessageType.ASSASSIN,
THUAI6.TrickerType.Klee: MessageType.KLEE,
THUAI6.TrickerType.ANoisyPerson: MessageType.A_NOISY_PERSON,
THUAI6.TrickerType.Idol: MessageType.IDOL, }
THUAI6.TrickerType.Idol: MessageType.IDOL,
}

propTypeDict: Final[dict] = {
THUAI6.PropType.NullPropType: MessageType.NULL_PROP_TYPE,
@@ -319,44 +356,70 @@ class THUAI62Proto(NoInstance):
THUAI6.PropType.AddHpOrAp: MessageType.ADD_HP_OR_AP,
THUAI6.PropType.AddLifeOrClairaudience: MessageType.ADD_LIFE_OR_CLAIRAUDIENCE,
THUAI6.PropType.AddSpeed: MessageType.ADD_SPEED,
THUAI6.PropType.ShieldOrSpear: MessageType.SHIELD_OR_SPEAR, }
THUAI6.PropType.ShieldOrSpear: MessageType.SHIELD_OR_SPEAR,
}

# 用于将THUAI6的对象转为Proto的对象

@ staticmethod
def THUAI62ProtobufPlayer(playerID: int, playerType: THUAI6.PlayerType, studentType: THUAI6.StudentType, trickerType: THUAI6.TrickerType) -> Message2Server.PlayerMsg:
@staticmethod
def THUAI62ProtobufPlayer(
playerID: int,
playerType: THUAI6.PlayerType,
studentType: THUAI6.StudentType,
trickerType: THUAI6.TrickerType,
) -> Message2Server.PlayerMsg:
if playerType == THUAI6.PlayerType.StudentPlayer:
return Message2Server.PlayerMsg(player_id=playerID, player_type=MessageType.STUDENT_PLAYER, student_type=THUAI62Proto.studentTypeDict[studentType])
return Message2Server.PlayerMsg(
player_id=playerID,
player_type=MessageType.STUDENT_PLAYER,
student_type=THUAI62Proto.studentTypeDict[studentType],
)
else:
return Message2Server.PlayerMsg(player_id=playerID, player_type=MessageType.TRICKER_PLAYER, tricker_type=THUAI62Proto.trickerTypeDict[trickerType])
return Message2Server.PlayerMsg(
player_id=playerID,
player_type=MessageType.TRICKER_PLAYER,
tricker_type=THUAI62Proto.trickerTypeDict[trickerType],
)

@ staticmethod
@staticmethod
def THUAI62ProtobufID(playerID: int) -> Message2Server.IDMsg:
return Message2Server.IDMsg(player_id=playerID)

@ staticmethod
@staticmethod
def THUAI62ProtobufMove(time: int, angle: float, id: int) -> Message2Server.MoveMsg:
return Message2Server.MoveMsg(player_id=id, angle=angle, time_in_milliseconds=time)
return Message2Server.MoveMsg(
player_id=id, angle=angle, time_in_milliseconds=time
)

@ staticmethod
def THUAI62ProtobufTreatAndRescue(playerID: int, mateID: int) -> Message2Server.TreatAndRescueMsg:
@staticmethod
def THUAI62ProtobufTreatAndRescue(
playerID: int, mateID: int
) -> Message2Server.TreatAndRescueMsg:
return Message2Server.TreatAndRescueMsg(player_id=playerID, to_player_id=mateID)

@ staticmethod
@staticmethod
def THUAI62ProtobufProp(prop: THUAI6.PropType, id: int) -> Message2Server.PropMsg:
return Message2Server.PropMsg(player_id=id, prop_type=THUAI62Proto.propTypeDict[prop])
return Message2Server.PropMsg(
player_id=id, prop_type=THUAI62Proto.propTypeDict[prop]
)

@ staticmethod
def THUAI62ProtobufSend(msg: Union[str, bytes], toID: int, id: int) -> Message2Server.SendMsg:
@staticmethod
def THUAI62ProtobufSend(
msg: Union[str, bytes], toID: int, id: int
) -> Message2Server.SendMsg:
if isinstance(msg, str):
return Message2Server.SendMsg(player_id=id, to_player_id=toID, text_message=msg)
return Message2Server.SendMsg(
player_id=id, to_player_id=toID, text_message=msg
)
elif isinstance(msg, bytes):
return Message2Server.SendMsg(player_id=id, to_player_id=toID, binary_message=msg)
return Message2Server.SendMsg(
player_id=id, to_player_id=toID, binary_message=msg
)

@ staticmethod
@staticmethod
def THUAI62ProtobufAttack(angle: float, id: int) -> Message2Server.AttackMsg:
return Message2Server.AttackMsg(player_id=id, angle=angle)

@ staticmethod
@staticmethod
def THUAI62ProtobufSkill(skillID: int, id: int) -> Message2Server.SkillMsg:
return Message2Server.SkillMsg(player_id=id, skill_id=skillID)

+ 3
- 3
docs/游戏机制与平衡性调整更新草案.md View File

@@ -1,12 +1,12 @@
# 游戏机制与平衡性调整更新草案
v1.2
v1.3

## 说明
- 该草案尚未完全确定,请大家不要过分依靠该文档进行修改自己的代码
- 有任何问题都可以在选手群中提出建议和讨论

## 游戏接口
删除structures.h中Player的属性place
- 删除structures.h中Player的属性place

## 游戏规则

@@ -71,7 +71,7 @@ v1.2
- CD:0s,持续时间:0s
- TechOtaku的Robot的PlayerId = TechOtaku的PlayerId + n×5(一局游戏理论人数),其中1<=n<=3(自己的n为0)
- 新造的Robot的PlayerId的n总是尽量小
- 每使用一次UseRobot,TechOtaku就切换一次操控的角色,若之前操控角色的PlayerId =TechOtaku的PlayerId + j×5,其PlayerId变为PlayerId =TechOtaku的PlayerId + ((j+1)mod 4 )×5,若其不可用,则再次进行这样的操作
- 每使用一次UseRobot,TechOtaku就切换一次操控的角色(具体来说,若之前操控角色的PlayerId =TechOtaku的PlayerId + j×5,其PlayerId变为PlayerId =TechOtaku的PlayerId + ((j+1)mod 4 )×5,若其不可用,则自动再次进行这样的操作
修改后:

| 学生职业 | 教师Teacher | 健身狂Athlete |学霸StraightAStudent | 开心果Sunshine | 机器人Robot | 技术宅TechOtaku |


+ 1
- 1
docs/版本更新说明.md View File

@@ -3,7 +3,7 @@
# 说明
- 只说明对于选手较为重要的修改

# 等待更新的更改
# 5月6日更新
- docs:添加了 游戏机制与平衡性调整更新草案.pdf
- docs:添加了 版本更新说明.pdf
- docs&hotfix: 修正了GameRules.pdf中学生翻窗速度的错误

+ 2
- 2
logic/GameClass/GameObj/Bullet/BombedBullet.cs View File

@@ -3,7 +3,7 @@
namespace GameClass.GameObj
{
// 为方便界面组做子弹爆炸特效,现引入“爆炸中的子弹”,在每帧发送给界面组
public sealed class BombedBullet : GameObj
public sealed class BombedBullet : Immovable
{
public override ShapeType Shape => ShapeType.Circle;
public override bool IsRigid => false;
@@ -15,7 +15,7 @@ namespace GameClass.GameObj
{
this.bulletHasBombed = bullet;
this.MappingID = bullet.ID;
this.FacingDirection = bullet.FacingDirection;
this.facingDirection = bullet.FacingDirection;
}
}
}

+ 1
- 1
logic/GameClass/GameObj/Bullet/Bullet.cs View File

@@ -44,7 +44,7 @@ namespace GameClass.GameObj
public Bullet(Character player, int radius, XY Position) :
base(Position, radius, GameObjType.Bullet)
{
this.CanMove = true;
this.canMove = true;
this.moveSpeed = this.Speed;
this.hasSpear = player.TryUseSpear();
this.Parent = player;


+ 1
- 1
logic/GameClass/GameObj/Character/Character.Skill.cs View File

@@ -57,7 +57,7 @@ namespace GameClass.GameObj
protected Character(XY initPos, int initRadius, CharacterType characterType) :
base(initPos, initRadius, GameObjType.Character)
{
this.CanMove = true;
this.canMove = true;
this.score = 0;
this.buffManager = new BuffManager();
this.occupation = OccupationFactory.FindIOccupation(characterType);


+ 14
- 7
logic/GameClass/GameObj/Character/Character.cs View File

@@ -2,9 +2,6 @@
using Preparation.Utility;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Threading;

namespace GameClass.GameObj
{
@@ -58,10 +55,20 @@ namespace GameClass.GameObj
/// 进行一次攻击
/// </summary>
/// <returns>攻击操作发出的子弹</returns>
public Bullet? Attack(XY pos)
public Bullet? Attack(double angle)
{
if (TrySubBulletNum())
return BulletFactory.GetBullet(this, pos);
{
XY res = Position + new XY // 子弹紧贴人物生成。
(
(int)(Math.Abs((Radius + BulletFactory.BulletRadius(BulletOfPlayer)) * Math.Cos(angle))) * ((Math.Cos(angle) > 0) ? 1 : -1),
(int)(Math.Abs((Radius + BulletFactory.BulletRadius(BulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1)
);
Bullet? bullet = BulletFactory.GetBullet(this, res);
if (bullet == null) return null;
facingDirection = new(angle, bullet.BulletAttackRange);
return bullet;
}
else
return null;
}
@@ -362,9 +369,9 @@ namespace GameClass.GameObj
lock (gameObjLock)
{
playerState = playerStateType;
CanMove = false;
canMove = false;
IsResetting = true;
Position = GameData.PosWhoDie;
position = GameData.PosWhoDie;
}
}
#endregion


+ 8
- 41
logic/GameClass/GameObj/GameObj.cs View File

@@ -9,6 +9,8 @@ namespace GameClass.GameObj
/// </summary>
public abstract class GameObj : IGameObj
{
private ReaderWriterLockSlim gameObjReaderWriterLock = new();
public ReaderWriterLockSlim GameObjReaderWriterLock => gameObjReaderWriterLock;
protected readonly object gameObjLock = new();
public object GameLock => gameObjLock;

@@ -22,53 +24,18 @@ namespace GameClass.GameObj
public long ID { get; }

protected XY position;
public virtual XY Position { get; set; }
public abstract XY Position { get; }

private XY facingDirection = new(1, 0);
public XY FacingDirection
{
get
{
lock (gameObjLock)
return facingDirection;
}
set
{
lock (gameObjLock)
facingDirection = value;
}
}
protected XY facingDirection = new(1, 0);
public abstract XY FacingDirection { get; }

protected bool canMove;
public abstract bool CanMove { get; }

public abstract bool IsRigid { get; }

public abstract ShapeType Shape { get; }

private bool canMove;
public bool CanMove
{
get => canMove;
set
{
lock (gameObjLock)
{
canMove = value;
}
}
}

private bool isResetting;
public bool IsResetting
{
get => isResetting;
set
{
lock (gameObjLock)
{
isResetting = value;
}
}
}

public int Radius { get; }

public virtual bool IgnoreCollideExecutor(IGameObj targetObj) => false;


+ 19
- 0
logic/GameClass/GameObj/Immovable.cs View File

@@ -0,0 +1,19 @@
using Preparation.Interface;
using Preparation.Utility;

namespace GameClass.GameObj
{
public abstract class Immovable : GameObj
{

public override XY Position => position;

public override XY FacingDirection => facingDirection;

public override bool CanMove => false;

public Immovable(XY initPos, int initRadius, GameObjType initType) : base(initPos, initRadius, initType)
{
}
}
}

+ 4
- 6
logic/GameClass/GameObj/Map/Chest.cs View File

@@ -1,22 +1,20 @@
using Preparation.Utility;
using System.Collections.Generic;

namespace GameClass.GameObj
{
/// <summary>
/// 箱子
/// </summary>
public class Chest : GameObj
public class Chest : Immovable
{
public Chest(XY initPos) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Chest)
{
this.CanMove = false;
}
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square;

private Prop[] propInChest = new Prop[GameData.maxNumOfPropInChest] { new NullProp(), new NullProp() };
private readonly Prop[] propInChest = new Prop[GameData.maxNumOfPropInChest] { new NullProp(), new NullProp() };
public Prop[] PropInChest => propInChest;

private int openStartTime = 0;
@@ -25,7 +23,7 @@ namespace GameClass.GameObj
public Character? WhoOpen => whoOpen;
public void Open(int startTime, Character character)
{
lock (gameObjLock)
lock (GameObjReaderWriterLock)
{
openStartTime = startTime;
whoOpen = character;
@@ -33,7 +31,7 @@ namespace GameClass.GameObj
}
public void StopOpen()
{
lock (gameObjLock)
lock (GameObjReaderWriterLock)
{
openStartTime = 0;
whoOpen = null;


+ 1
- 2
logic/GameClass/GameObj/Map/Door.cs View File

@@ -6,7 +6,7 @@ namespace GameClass.GameObj
/// <summary>
/// 门
/// </summary>
public class Door : GameObj
public class Door : Immovable
{
public Door(XY initPos, PlaceType placeType) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Door)
@@ -24,7 +24,6 @@ namespace GameClass.GameObj
doorNum = 6;
break;
}
this.CanMove = false;
}

private readonly int doorNum;


+ 1
- 2
logic/GameClass/GameObj/Map/Doorway.cs View File

@@ -6,12 +6,11 @@ namespace GameClass.GameObj
/// <summary>
/// 出口
/// </summary>
public class Doorway : GameObj
public class Doorway : Immovable
{
public Doorway(XY initPos) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Doorway)
{
this.CanMove = false;
}
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square;


+ 1
- 2
logic/GameClass/GameObj/Map/EmergencyExit.cs View File

@@ -6,12 +6,11 @@ namespace GameClass.GameObj
/// <summary>
/// 紧急出口
/// </summary>
public class EmergencyExit : GameObj
public class EmergencyExit : Immovable
{
public EmergencyExit(XY initPos) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.EmergencyExit)
{
this.CanMove = false;
}
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square;


+ 1
- 2
logic/GameClass/GameObj/Map/Generator.cs View File

@@ -5,12 +5,11 @@ namespace GameClass.GameObj
/// <summary>
/// 发电机
/// </summary>
public class Generator : GameObj
public class Generator : Immovable
{
public Generator(XY initPos) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Generator)
{
this.CanMove = false;
}
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square;


+ 0
- 1
logic/GameClass/GameObj/Map/Map.cs View File

@@ -8,7 +8,6 @@ namespace GameClass.GameObj
{
public partial class Map : IMap
{

private readonly Dictionary<uint, XY> birthPointList; // 出生点列表
public Dictionary<uint, XY> BirthPointList => birthPointList;



+ 1
- 2
logic/GameClass/GameObj/Map/Wall.cs View File

@@ -5,12 +5,11 @@ namespace GameClass.GameObj
/// <summary>
/// 墙体
/// </summary>
public class Wall : GameObj
public class Wall : Immovable
{
public Wall(XY initPos) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Wall)
{
this.CanMove = false;
}
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square;


+ 1
- 2
logic/GameClass/GameObj/Map/Window.cs View File

@@ -6,12 +6,11 @@ namespace GameClass.GameObj
/// <summary>
/// 窗
/// </summary>
public class Window : GameObj
public class Window : Immovable
{
public Window(XY initPos) :
base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Window)
{
this.CanMove = false;
}
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square;


+ 76
- 38
logic/GameClass/GameObj/Moveable.cs View File

@@ -4,43 +4,102 @@ using System.Threading;

namespace GameClass.GameObj
{
/// <summary>
/// 一切游戏元素的总基类,与THUAI4不同,继承IMoveable接口(出于一切物体其实都是可运动的指导思想)——LHR
/// </summary>
public abstract class Moveable : GameObj, IMoveable
{
protected readonly object moveObjLock = new();
public object MoveLock => moveObjLock;
private ReaderWriterLockSlim moveReaderWriterLock = new();
public ReaderWriterLockSlim MoveReaderWriterLock => moveReaderWriterLock;

public override XY Position
{
get
{
lock (gameObjLock)
lock (moveObjLock)
return position;
}
set
}

public override XY FacingDirection
{
get
{
lock (gameObjLock)
{
position = value;
}
lock (moveObjLock)
return facingDirection;
}
}

private bool isMoving;
public bool IsMoving
{
get => isMoving;
get
{
lock (moveObjLock)
return isMoving;
}
set
{
lock (gameObjLock)
lock (moveObjLock)
{
isMoving = value;
}
}
}

// 移动,改变坐标
public long MovingSetPos(XY moveVec)
{
if (moveVec.x != 0 || moveVec.y != 0)
lock (moveObjLock)
{
facingDirection = moveVec;
this.position += moveVec;
}
return moveVec * moveVec;
}

public void ReSetPos(XY position)
{
lock (moveObjLock)
{
this.position = position;
}
}

public override bool CanMove
{
get
{
lock (moveReaderWriterLock)
return canMove;
}
}

public void ReSetCanMove(bool value)
{
lock (moveReaderWriterLock)
{
canMove = value;
}
}

private bool isResetting;
public bool IsResetting
{
get
{
lock (moveReaderWriterLock)
return isResetting;
}
set
{
lock (moveReaderWriterLock)
{
isResetting = value;
}
}
}

public bool IsAvailable => !IsMoving && CanMove && !IsResetting; // 是否能接收指令

protected int moveSpeed;
@@ -49,10 +108,14 @@ namespace GameClass.GameObj
/// </summary>
public int MoveSpeed
{
get => moveSpeed;
get
{
lock (moveReaderWriterLock)
return moveSpeed;
}
set
{
lock (gameObjLock)
lock (moveReaderWriterLock)
{
moveSpeed = value;
}
@@ -63,26 +126,6 @@ namespace GameClass.GameObj
/// </summary>
public int OrgMoveSpeed { get; protected set; }

// 移动,改变坐标
public long MovingSetPos(XY moveVec)
{
if (moveVec.x != 0 || moveVec.y != 0)
lock (gameObjLock)
{
FacingDirection = moveVec;
this.Position += moveVec;
}
return moveVec * moveVec;
}

/// <summary>
/// 设置移动速度
/// </summary>
/// <param name="newMoveSpeed">新速度</param>
public void SetMoveSpeed(int newMoveSpeed)
{
MoveSpeed = newMoveSpeed;
}
/* /// <summary>
/// 复活时数据重置
/// </summary>
@@ -98,11 +141,6 @@ namespace GameClass.GameObj
this.Place= place;
}
}*/
/// <summary>
/// 为了使IgnoreCollide多态化并使GameObj能不报错地继承IMoveable
/// 在xfgg点播下设计了这个抽象辅助方法,在具体类中实现
/// </summary>
/// <returns> 依具体类及该方法参数而定,默认为false </returns>
public Moveable(XY initPos, int initRadius, GameObjType initType) : base(initPos, initRadius, initType)
{
}


+ 13
- 3
logic/GameClass/GameObj/ObjOfCharacter.cs View File

@@ -1,5 +1,7 @@
using Preparation.Interface;
using Google.Protobuf.WellKnownTypes;
using Preparation.Interface;
using Preparation.Utility;
using System.Threading;

namespace GameClass.GameObj
{
@@ -8,13 +10,21 @@ namespace GameClass.GameObj
/// </summary>
public abstract class ObjOfCharacter : Moveable, IObjOfCharacter
{
private ReaderWriterLockSlim objOfCharacterReaderWriterLock = new();
public ReaderWriterLockSlim ObjOfCharacterReaderWriterLock => objOfCharacterReaderWriterLock;
private ICharacter? parent = null; // 主人
public ICharacter? Parent
{
get => parent;
get
{
lock (objOfCharacterReaderWriterLock)
{
return parent;
}
}
set
{
lock (gameObjLock)
lock (objOfCharacterReaderWriterLock)
{
parent = value;
}


+ 1
- 2
logic/GameClass/GameObj/OutOfBoundBlock.cs View File

@@ -6,12 +6,11 @@ namespace GameClass.GameObj
/// <summary>
/// 逻辑墙
/// </summary>
public class OutOfBoundBlock : GameObj, IOutOfBound
public class OutOfBoundBlock : Immovable, IOutOfBound
{
public OutOfBoundBlock(XY initPos) :
base(initPos, int.MaxValue, GameObjType.OutOfBoundBlock)
{
this.CanMove = false;
}

public override bool IsRigid => true;


+ 3
- 8
logic/GameClass/GameObj/PickedProp.cs View File

@@ -1,23 +1,18 @@
using Preparation.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GameClass.GameObj
{
// 为方便界面组做道具拾起特效,现引入“被捡起的道具”,在每帧发送给界面组
public class PickedProp : GameObj
public class PickedProp : Immovable
{
public override ShapeType Shape => ShapeType.Circle;
public override bool IsRigid => false;
public long MappingID { get; }
public Prop PropHasPicked;
public readonly Prop propHasPicked;
public PickedProp(Prop prop) :
base(prop.Position, prop.Radius, GameObjType.PickedProp)
{
this.PropHasPicked = prop;
this.propHasPicked = prop;
this.MappingID = prop.ID;
}
}


+ 1
- 1
logic/GameClass/GameObj/Prop.cs View File

@@ -22,7 +22,7 @@ namespace GameClass.GameObj
public Prop(XY initPos, int radius = GameData.PropRadius) :
base(initPos, radius, GameObjType.Prop)
{
this.CanMove = false;
this.canMove = false;
this.moveSpeed = GameData.PropMoveSpeed;
}
}


+ 3
- 3
logic/Gaming/ActionManager.cs View File

@@ -267,7 +267,7 @@ namespace Gaming
{
Prop prop = chestToOpen.PropInChest[i];
chestToOpen.PropInChest[i] = new NullProp();
prop.Position = player.Position;
prop.ReSetPos(player.Position);
gameMap.Add(prop);
}
}
@@ -323,7 +323,7 @@ namespace Gaming
return;
}

player.Position = windowToPlayer + windowForClimb.Position;
player.ReSetPos(windowToPlayer + windowForClimb.Position);
player.MoveSpeed = player.SpeedOfClimbingThroughWindows;

moveEngine.MoveObj(player, (int)(windowToPlayer.Length() * 3.0 * 1000 / player.MoveSpeed), (-1 * windowToPlayer).Angle());
@@ -339,7 +339,7 @@ namespace Gaming
)
.Start();
XY PosJumpOff = windowForClimb.Position - 2 * windowToPlayer;
player.Position = PosJumpOff;
player.ReSetPos(PosJumpOff);
player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed);
windowForClimb.WhoIsClimbing = null;
// gameMap.Remove(addWall);


+ 4
- 10
logic/Gaming/AttackManager.cs View File

@@ -33,7 +33,7 @@ namespace Gaming
Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64);
if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty)
BulletBomb((Bullet)obj, null);
obj.CanMove = false;
obj.ReSetCanMove(false);
}
);
this.characterManager = characterManager;
@@ -66,7 +66,7 @@ namespace Gaming

public bool TryRemoveBullet(Bullet bullet)
{
bullet.CanMove = false;
bullet.ReSetCanMove(false);
if (gameMap.Remove(bullet))
{
if (bullet.BulletBombRange > 0)
@@ -172,20 +172,14 @@ namespace Gaming
Debugger.Output(player, player.CharacterType.ToString() + "Attack in " + player.BulletOfPlayer.ToString());

Debugger.Output(player, player.Position.ToString() + " " + player.Radius.ToString() + " " + BulletFactory.BulletRadius(player.BulletOfPlayer).ToString());
XY res = player.Position + new XY // 子弹紧贴人物生成。
(
(int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Cos(angle))) * ((Math.Cos(angle) > 0) ? 1 : -1),
(int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1)
);

Bullet? bullet = player.Attack(res);
Bullet? bullet = player.Attack(angle);

if (bullet != null)
{
player.FacingDirection = new(angle, bullet.BulletAttackRange);
Debugger.Output(bullet, "Attack in " + bullet.Position.ToString());
bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0;
bullet.CanMove = true;
bullet.ReSetCanMove(true);
gameMap.Add(bullet);
moveEngine.MoveObj(bullet, (int)((bullet.BulletAttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms
if (bullet.CastTime > 0)


+ 1
- 1
logic/Gaming/CharacterManager .cs View File

@@ -407,7 +407,7 @@ namespace Gaming
Prop? prop = player.UseProp(i);
if (prop != null)
{
prop.Position = player.Position;
prop.ReSetPos(player.Position);
gameMap.Add(prop);
}
}


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

@@ -316,7 +316,7 @@ namespace Gaming
{
foreach (Character player in gameMap.GameObjDict[GameObjType.Character])
{
player.CanMove = false;
player.ReSetCanMove(false);
}
}
gameMap.GameObjDict[keyValuePair.Key].Clear();


+ 1
- 1
logic/Gaming/PropManager.cs View File

@@ -124,7 +124,7 @@ namespace Gaming
if (prop.GetPropType() == PropType.Null)
return;

prop.Position = player.Position;
prop.ReSetPos(player.Position);
gameMap.Add(prop);
}



+ 1
- 2
logic/Preparation/Interface/IGameObj.cs View File

@@ -10,8 +10,7 @@ namespace Preparation.Interface
public XY FacingDirection { get; }
public bool IsRigid { get; }
public ShapeType Shape { get; }
public bool CanMove { get; set; }
public bool IsResetting { get; set; } // reviving
public bool CanMove { get; }
public int Radius { get; } // if Square, Radius equals half length of one side
public bool IgnoreCollideExecutor(IGameObj targetObj); // 忽略碰撞,在具体类中实现
}


+ 2
- 0
logic/Preparation/Interface/IMoveable.cs View File

@@ -8,8 +8,10 @@ namespace Preparation.Interface
object MoveLock { get; }
public int MoveSpeed { get; }
public bool IsMoving { get; set; }
public bool IsResetting { get; set; } // reviving
public bool IsAvailable { get; }
public long MovingSetPos(XY moveVec);
public void ReSetCanMove(bool value);
public bool WillCollideWith(IGameObj? targetObj, XY nextPos) // 检查下一位置是否会和目标物碰撞
{
if (targetObj == null)


Loading…
Cancel
Save