#include "logic.h" #include "structures.h" #include #include #include "utils.hpp" #include "Communication.h" extern const bool asynchronous; extern const THUAI6::PlayerType playerType; Logic::Logic(THUAI6::PlayerType type, int64_t ID, THUAI6::ButcherType butcher, THUAI6::HumanType human) : playerType(type), playerID(ID), butcherType(butcher), humanType(human) { currentState = &state[0]; bufferState = &state[1]; } std::vector> Logic::GetButchers() const { std::lock_guard lock(mtxBuffer); std::vector> temp; temp.assign(currentState->butchers.begin(), currentState->butchers.end()); return temp; } std::vector> Logic::GetHumans() const { std::unique_lock lock(mtxBuffer); std::vector> temp; temp.assign(currentState->humans.begin(), currentState->humans.end()); return temp; } std::vector> Logic::GetProps() const { std::unique_lock lock(mtxBuffer); std::vector> temp; temp.assign(currentState->props.begin(), currentState->props.end()); return temp; } std::shared_ptr Logic::HumanGetSelfInfo() const { std::unique_lock lock(mtxBuffer); return currentState->humanSelf; } std::shared_ptr Logic::ButcherGetSelfInfo() const { std::unique_lock lock(mtxBuffer); return currentState->butcherSelf; } std::vector> Logic::GetFullMap() const { std::unique_lock lock(mtxBuffer); return currentState->gamemap; } THUAI6::PlaceType Logic::GetPlaceType(int32_t CellX, int32_t CellY) const { std::unique_lock lock(mtxBuffer); return currentState->gamemap[CellX][CellY]; } bool Logic::Move(int64_t time, double angle) { return pComm->Move(time, angle, playerID); } bool Logic::PickProp(THUAI6::PropType prop) { return pComm->PickProp(prop, playerID); } bool Logic::UseProp() { return pComm->UseProp(playerID); } bool Logic::UseSkill() { return pComm->UseSkill(playerID); } bool Logic::SendMessage(int64_t toID, std::string message) { return pComm->SendMessage(toID, message, playerID); } bool Logic::HaveMessage() { return pComm->HaveMessage(); } std::optional> Logic::GetMessage() { return pComm->GetMessage(); } bool Logic::Escape() { return pComm->Escape(playerID); } bool Logic::StartFixMachine() { return pComm->StartFixMachine(playerID); } bool Logic::EndFixMachine() { return pComm->EndFixMachine(playerID); } bool Logic::StartSaveHuman() { return pComm->StartSaveHuman(playerID); } bool Logic::EndSaveHuman() { return pComm->EndSaveHuman(playerID); } bool Logic::Attack(double angle) { return pComm->Attack(angle, playerID); } bool Logic::CarryHuman() { return pComm->CarryHuman(playerID); } bool Logic::ReleaseHuman() { return pComm->ReleaseHuman(playerID); } bool Logic::HangHuman() { return pComm->HangHuman(playerID); } bool Logic::WaitThread() { Update(); return true; } void Logic::ProcessMessage() { auto messageThread = [&]() { std::cout << "Join Player!" << std::endl; pComm->AddPlayer(playerID, playerType, humanType, butcherType); while (gameState != THUAI6::GameState::GameEnd) { if (pComm->HaveMessage2Client()) { std::cout << "Get Message!" << std::endl; auto clientMsg = pComm->GetMessage2Client(); gameState = Proto2THUAI6::gameStateDict[clientMsg.game_state()]; switch (gameState) { case THUAI6::GameState::GameStart: std::cout << "Game Start!" << std::endl; // 重新读取玩家的guid,guid确保人类在前屠夫在后 playerGUIDs.clear(); for (auto human : clientMsg.human_message()) playerGUIDs.push_back(human.guid()); for (auto butcher : clientMsg.butcher_message()) playerGUIDs.push_back(butcher.guid()); currentState->guids = playerGUIDs; bufferState->guids = playerGUIDs; LoadBuffer(clientMsg); AILoop = true; UnBlockAI(); break; case THUAI6::GameState::GameRunning: // 重新读取玩家的guid,guid确保人类在前屠夫在后 playerGUIDs.clear(); for (auto human : clientMsg.human_message()) playerGUIDs.push_back(human.guid()); for (auto butcher : clientMsg.butcher_message()) playerGUIDs.push_back(butcher.guid()); currentState->guids = playerGUIDs; bufferState->guids = playerGUIDs; LoadBuffer(clientMsg); break; case THUAI6::GameState::GameEnd: AILoop = false; { std::lock_guard lock(mtxBuffer); bufferUpdated = true; counterBuffer = -1; } cvBuffer.notify_one(); std::cout << "Game End!" << std::endl; break; default: std::cerr << "Invalid GameState!" << std::endl; } } } }; std::thread(messageThread).detach(); } void Logic::LoadBuffer(protobuf::MessageToClient& message) { // 将消息读入到buffer中 { std::lock_guard lock(mtxBuffer); // 清空原有信息 bufferState->humans.clear(); bufferState->butchers.clear(); bufferState->props.clear(); std::cout << "Buffer clear!" << std::endl; // 读取新的信息 // 读取消息的选择待补充,之后需要另外判断;具体做法应该是先读到自己,然后按照自己的视野做处理。此处暂时全部读了进来 bufferState->gamemap = Proto2THUAI6::Protobuf2THUAI6Map(message.map_message()); if (playerType == THUAI6::PlayerType::HumanPlayer) { for (const auto& item : message.human_message()) { if (item.player_id() == playerID) { bufferState->humanSelf = Proto2THUAI6::Protobuf2THUAI6Human(item); } bufferState->humans.push_back(Proto2THUAI6::Protobuf2THUAI6Human(item)); } for (const auto& item : message.butcher_message()) { int vr = this->bufferState->humanSelf->viewRange; int deltaX = item.x() - this->bufferState->humanSelf->x; int deltaY = item.y() - this->bufferState->humanSelf->y; double distance = deltaX * deltaX + deltaY * deltaY; if (distance > vr * vr) continue; else { int divide = abs(deltaX) > abs(deltaY) ? abs(deltaX) : abs(deltaY); divide /= 100; double dx = deltaX / divide; double dy = deltaY / divide; double myX = this->bufferState->humanSelf->x; double myY = this->bufferState->humanSelf->y; bool barrier = false; for (int i = 0; i < divide; i++) { myX += dx; myY += dy; if (this->bufferState->gamemap[IAPI::GridToCell(myX)][IAPI::GridToCell(myY)] == THUAI6::PlaceType::Wall) { barrier = true; break; } } if (barrier) continue; bufferState->butchers.push_back(Proto2THUAI6::Protobuf2THUAI6Butcher(item)); std::cout << "Add Butcher!" << std::endl; } } } else { for (const auto& item : message.butcher_message()) { if (item.player_id() == playerID) { bufferState->butcherSelf = Proto2THUAI6::Protobuf2THUAI6Butcher(item); } bufferState->butchers.push_back(Proto2THUAI6::Protobuf2THUAI6Butcher(item)); } for (const auto& item : message.human_message()) { int vr = this->bufferState->butcherSelf->viewRange; int deltaX = item.x() - this->bufferState->butcherSelf->x; int deltaY = item.y() - this->bufferState->butcherSelf->y; double distance = deltaX * deltaX + deltaY * deltaY; if (distance > vr * vr) continue; else { int divide = abs(deltaX) > abs(deltaY) ? abs(deltaX) : abs(deltaY); divide /= 100; double dx = deltaX / divide; double dy = deltaY / divide; double myX = this->bufferState->butcherSelf->x; double myY = this->bufferState->butcherSelf->y; bool barrier = false; for (int i = 0; i < divide; i++) { myX += dx; myY += dy; if (this->bufferState->gamemap[IAPI::GridToCell(myX)][IAPI::GridToCell(myY)] == THUAI6::PlaceType::Wall) { barrier = true; break; } } if (barrier) continue; bufferState->humans.push_back(Proto2THUAI6::Protobuf2THUAI6Human(item)); std::cout << "Add Human!" << std::endl; } } } for (const auto& item : message.prop_message()) bufferState->props.push_back(Proto2THUAI6::Protobuf2THUAI6Prop(item)); if (asynchronous) { { std::lock_guard lock(mtxState); std::swap(currentState, bufferState); } freshed = true; } else bufferUpdated = true; counterBuffer++; } // 唤醒其他线程 cvBuffer.notify_one(); } void Logic::Update() noexcept { if (!asynchronous) { std::unique_lock lock(mtxBuffer); // 缓冲区被更新之后才可以使用 cvBuffer.wait(lock, [&]() { return bufferUpdated; }); std::swap(currentState, bufferState); bufferUpdated = false; counterState = counterBuffer; } } void Logic::Wait() noexcept { freshed = false; { std::unique_lock lock(mtxBuffer); cvBuffer.wait(lock, [&]() { return freshed.load(); }); } } void Logic::UnBlockAI() { { std::lock_guard lock(mtxAI); AIStart = true; } cvAI.notify_one(); } void Logic::UnBlockBuffer() { { std::lock_guard lock(mtxBuffer); bufferUpdated = true; } cvBuffer.notify_one(); } int Logic::GetCounter() const { std::unique_lock lock(mtxState); return counterState; } const std::vector Logic::GetPlayerGUIDs() const { std::unique_lock lock(mtxState); return currentState->guids; } bool Logic::TryConnection() { std::cout << "Trying to connect to server..." << std::endl; bool result = pComm->TryConnection(playerID); return result; } void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool level, std::string filename) { // 建立与服务器之间通信的组件 pComm = std::make_unique(IP, port); // 构造timer if (playerType == THUAI6::PlayerType::HumanPlayer) timer = std::make_unique(*this); else if (playerType == THUAI6::PlayerType::ButcherPlayer) timer = std::make_unique(*this); // 构造AI线程 auto AIThread = [&]() { { std::unique_lock lock(mtxAI); cvAI.wait(lock, [this]() { return AIStart; }); } auto ai = createAI(); while (AILoop) { if (asynchronous) { Wait(); timer->StartTimer(); timer->Play(*ai); timer->EndTimer(); } else { Update(); timer->StartTimer(); timer->Play(*ai); timer->EndTimer(); } } }; tAI = std::thread(AIThread); // 连接服务器 if (TryConnection()) { std::cout << "Connect to the server successfully, AI thread will be start." << std::endl; if (tAI.joinable()) { std::cout << "Join the AI thread." << std::endl; // 首先开启处理消息的线程 ProcessMessage(); tAI.join(); } } else { std::cout << "Connection error!" << std::endl; return; } }