| @@ -5,7 +5,7 @@ jobs: | |||
| runs-on: ubuntu-latest | |||
| steps: | |||
| - uses: actions/checkout@v3 | |||
| - uses: DoozyX/clang-format-lint-action@v0.14 | |||
| - uses: DoozyX/clang-format-lint-action@v0.15 | |||
| with: | |||
| source: '.' | |||
| extensions: 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx,i,ixx,ipp,i++' | |||
| @@ -43,7 +43,7 @@ public: | |||
| virtual bool UseSkill() = 0; | |||
| virtual bool SendMessage(int64_t toID, std::string message) = 0; | |||
| virtual bool HaveMessage() = 0; | |||
| virtual std::pair<int64_t, std::string> GetMessage() = 0; | |||
| virtual std::optional<std::pair<int64_t, std::string>> GetMessage() = 0; | |||
| virtual bool WaitThread() = 0; | |||
| @@ -63,6 +63,8 @@ public: | |||
| virtual bool CarryHuman() = 0; | |||
| virtual bool ReleaseHuman() = 0; | |||
| virtual bool HangHuman() = 0; | |||
| virtual const std::vector<int64_t> GetPlayerGUIDs() const = 0; | |||
| }; | |||
| class IAPI | |||
| @@ -83,10 +85,10 @@ public: | |||
| virtual std::future<bool> UseProp() = 0; | |||
| virtual std::future<bool> UseSkill() = 0; | |||
| // 发送信息、接受信息 | |||
| // 发送信息、接受信息,注意收消息时无消息则返回nullopt | |||
| virtual std::future<bool> SendMessage(int64_t, std::string) = 0; | |||
| [[nodiscard]] virtual std::future<bool> HaveMessage() = 0; | |||
| [[nodiscard]] virtual std::future<std::pair<int64_t, std::string>> GetMessage() = 0; | |||
| [[nodiscard]] virtual std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() = 0; | |||
| // 等待下一帧 | |||
| virtual std::future<bool> Wait() = 0; | |||
| @@ -171,11 +173,9 @@ public: | |||
| } | |||
| void Play(IAI& ai) override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| [[nodiscard]] int GetFrameCount() const override; | |||
| [[nodiscard]] int GetFrameCount() const override | |||
| { | |||
| } | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| std::future<bool> MoveRight(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveUp(int64_t timeInMilliseconds) override; | |||
| @@ -188,11 +188,9 @@ public: | |||
| std::future<bool> SendMessage(int64_t, std::string) override; | |||
| [[nodiscard]] std::future<bool> HaveMessage() override; | |||
| [[nodiscard]] std::future<std::pair<int64_t, std::string>> GetMessage() override; | |||
| [[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override; | |||
| std::future<bool> Wait() override | |||
| { | |||
| } | |||
| std::future<bool> Wait() override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Human>> GetHuman() const override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Butcher>> GetButcher() const override; | |||
| @@ -230,12 +228,9 @@ public: | |||
| } | |||
| void Play(IAI& ai) override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| [[nodiscard]] int GetFrameCount() const override | |||
| { | |||
| } | |||
| [[nodiscard]] int GetFrameCount() const override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| std::future<bool> MoveRight(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveUp(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveLeft(int64_t timeInMilliseconds) override; | |||
| @@ -247,11 +242,9 @@ public: | |||
| std::future<bool> SendMessage(int64_t, std::string) override; | |||
| [[nodiscard]] std::future<bool> HaveMessage() override; | |||
| [[nodiscard]] std::future<std::pair<int64_t, std::string>> GetMessage() override; | |||
| [[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override; | |||
| std::future<bool> Wait() override | |||
| { | |||
| } | |||
| std::future<bool> Wait() override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Human>> GetHuman() const override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Butcher>> GetButcher() const override; | |||
| @@ -280,20 +273,13 @@ public: | |||
| logic(logic) | |||
| { | |||
| } | |||
| void StartTimer() override | |||
| { | |||
| } | |||
| void EndTimer() override | |||
| { | |||
| } | |||
| void StartTimer() override; | |||
| void EndTimer() override; | |||
| void Play(IAI& ai) override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| [[nodiscard]] int GetFrameCount() const override | |||
| { | |||
| } | |||
| [[nodiscard]] int GetFrameCount() const override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| std::future<bool> MoveRight(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveUp(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveLeft(int64_t timeInMilliseconds) override; | |||
| @@ -305,11 +291,9 @@ public: | |||
| std::future<bool> SendMessage(int64_t, std::string) override; | |||
| [[nodiscard]] std::future<bool> HaveMessage() override; | |||
| [[nodiscard]] std::future<std::pair<int64_t, std::string>> GetMessage() override; | |||
| [[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override; | |||
| std::future<bool> Wait() override | |||
| { | |||
| } | |||
| std::future<bool> Wait() override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Human>> GetHuman() const override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Butcher>> GetButcher() const override; | |||
| @@ -329,6 +313,7 @@ public: | |||
| [[nodiscard]] virtual std::shared_ptr<const THUAI6::Human> GetSelfInfo() const override; | |||
| private: | |||
| std::chrono::system_clock::time_point StartPoint; | |||
| ILogic& logic; | |||
| }; | |||
| @@ -339,20 +324,13 @@ public: | |||
| logic(logic) | |||
| { | |||
| } | |||
| void StartTimer() override | |||
| { | |||
| } | |||
| void EndTimer() override | |||
| { | |||
| } | |||
| void StartTimer() override; | |||
| void EndTimer() override; | |||
| void Play(IAI& ai) override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| [[nodiscard]] int GetFrameCount() const override | |||
| { | |||
| } | |||
| [[nodiscard]] int GetFrameCount() const override; | |||
| std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian) override; | |||
| std::future<bool> MoveRight(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveUp(int64_t timeInMilliseconds) override; | |||
| std::future<bool> MoveLeft(int64_t timeInMilliseconds) override; | |||
| @@ -364,11 +342,9 @@ public: | |||
| std::future<bool> SendMessage(int64_t, std::string) override; | |||
| [[nodiscard]] std::future<bool> HaveMessage() override; | |||
| [[nodiscard]] std::future<std::pair<int64_t, std::string>> GetMessage() override; | |||
| [[nodiscard]] std::future<std::optional<std::pair<int64_t, std::string>>> GetMessage() override; | |||
| std::future<bool> Wait() override | |||
| { | |||
| } | |||
| std::future<bool> Wait() override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Human>> GetHuman() const override; | |||
| [[nodiscard]] std::vector<std::shared_ptr<const THUAI6::Butcher>> GetButcher() const override; | |||
| @@ -387,6 +363,7 @@ public: | |||
| [[nodiscard]] std::shared_ptr<const THUAI6::Butcher> GetSelfInfo() const override; | |||
| private: | |||
| std::chrono::system_clock::time_point StartPoint; | |||
| ILogic& logic; | |||
| }; | |||
| @@ -11,6 +11,7 @@ | |||
| #include <thread> | |||
| #include <mutex> | |||
| #include <queue> | |||
| #include "ConcurrentQueue.hpp" | |||
| class Logic; | |||
| @@ -25,7 +26,7 @@ public: | |||
| bool PickProp(THUAI6::PropType prop, int64_t playerID); | |||
| bool UseProp(int64_t playerID); | |||
| bool UseSkill(int64_t playerID); | |||
| std::pair<int64_t, std::string> GetMessage(); | |||
| std::optional<std::pair<int64_t, std::string>> GetMessage(); | |||
| bool HaveMessage(); | |||
| bool SendMessage(int64_t toID, std::string message, int64_t playerID); | |||
| bool Escape(int64_t playerID); | |||
| @@ -52,8 +53,7 @@ private: | |||
| std::unique_ptr<protobuf::AvailableService::Stub> THUAI6Stub; | |||
| bool haveNewMessage = false; | |||
| protobuf::MessageToClient message2Client; | |||
| std::queue<std::pair<int64_t, std::string>> messageQueue; | |||
| std::mutex messageMutex; | |||
| ConcurrentQueue<std::pair<int64_t, std::string>> messageQueue; | |||
| }; | |||
| #endif | |||
| #endif | |||
| @@ -0,0 +1,64 @@ | |||
| #pragma once | |||
| #ifndef CONCURRENT_QUEUE_HPP | |||
| #define CONCURRENT_QUEUE_HPP | |||
| #include <queue> | |||
| #include <mutex> | |||
| #include <utility> | |||
| #include <optional> | |||
| template<typename Elem> | |||
| class ConcurrentQueue | |||
| { | |||
| private: | |||
| using queueType = std::queue<Elem>; | |||
| public: | |||
| using sizeType = typename queueType::size_type; | |||
| using valueType = typename queueType::value_type; | |||
| using reference = typename queueType::reference; | |||
| using constReference = typename queueType::const_reference; | |||
| using containerType = typename queueType::container_type; | |||
| ConcurrentQueue() = default; | |||
| ConcurrentQueue(const ConcurrentQueue&) = delete; | |||
| ~ConcurrentQueue() noexcept = default; | |||
| ConcurrentQueue& operator=(const ConcurrentQueue&) = delete; | |||
| void clear() | |||
| { | |||
| std::scoped_lock<std::mutex> lock(mtx); | |||
| while (!q.empty()) | |||
| q.pop(); | |||
| } | |||
| [[nodiscard]] bool empty() const | |||
| { | |||
| std::scoped_lock<std::mutex> lock(mtx); | |||
| return q.empty(); | |||
| } | |||
| template<typename... Ts> | |||
| void emplace(Ts&&... args) | |||
| { | |||
| std::scoped_lock<std::mutex> lock(mtx); | |||
| q.emplace(std::forward<Ts>(args)...); | |||
| } | |||
| [[nodiscard]] std::optional<valueType> tryPop() | |||
| { | |||
| std::scoped_lock<std::mutex> lock(mtx); | |||
| if (q.empty()) | |||
| return std::nullopt; | |||
| auto out = std::make_optional<valueType>(std::move(q.front())); | |||
| q.pop(); | |||
| return out; | |||
| } | |||
| private: | |||
| mutable std::mutex mtx; | |||
| queueType q; | |||
| }; | |||
| #endif | |||
| @@ -30,7 +30,7 @@ | |||
| class Logic : public ILogic | |||
| { | |||
| private: | |||
| // gRPC客户端的stub,所有与服务端之间的通信操作都需要基于stub完成。 | |||
| // 通信组件 | |||
| std::unique_ptr<Communication> pComm; | |||
| // ID、阵营记录 | |||
| int64_t playerID; | |||
| @@ -43,10 +43,6 @@ private: | |||
| // GUID信息 | |||
| std::vector<int64_t> playerGUIDs; | |||
| // THUAI5中的通信组件可以完全被我们的stub取代,故无须再写 | |||
| std::unique_ptr<IAI> pAI; | |||
| std::unique_ptr<IGameTimer> timer; | |||
| std::thread tAI; // 用于运行AI的线程 | |||
| @@ -70,6 +66,8 @@ private: | |||
| int counterState = 0; | |||
| int counterBuffer = 0; | |||
| THUAI6::GameState gameState = THUAI6::GameState::NullGameState; | |||
| // 是否应该执行player() | |||
| std::atomic_bool AILoop = true; | |||
| @@ -84,8 +82,6 @@ private: | |||
| // 提供给API使用的函数 | |||
| // 获取服务器发来的消息 | |||
| std::vector<std::shared_ptr<const THUAI6::Butcher>> GetButchers() const override; | |||
| std::vector<std::shared_ptr<const THUAI6::Human>> GetHumans() const override; | |||
| std::vector<std::shared_ptr<const THUAI6::Prop>> GetProps() const override; | |||
| @@ -100,9 +96,10 @@ private: | |||
| bool PickProp(THUAI6::PropType prop) override; | |||
| bool UseProp() override; | |||
| bool UseSkill() override; | |||
| bool SendMessage(int64_t toID, std::string message) override; | |||
| bool HaveMessage() override; | |||
| std::pair<int64_t, std::string> GetMessage() override; | |||
| std::optional<std::pair<int64_t, std::string>> GetMessage() override; | |||
| bool Escape() override; | |||
| @@ -121,9 +118,9 @@ private: | |||
| int GetCounter() const override; | |||
| bool TryConnection(); | |||
| const std::vector<int64_t> GetPlayerGUIDs() const override; | |||
| // THUAI5中的一系列用于处理信息的函数可能也不会再用 | |||
| bool TryConnection(); | |||
| void ProcessMessage(); | |||
| @@ -151,7 +148,7 @@ public: | |||
| } | |||
| // Main函数同上 | |||
| void Main(CreateAIFunc createAI, std::string IP, std::string port); | |||
| void Main(CreateAIFunc createAI, std::string IP, std::string port, bool level, std::string filename); | |||
| }; | |||
| #endif | |||
| @@ -8,6 +8,15 @@ | |||
| namespace THUAI6 | |||
| { | |||
| // 游戏状态 | |||
| enum class GameState : unsigned char | |||
| { | |||
| NullGameState = 0, | |||
| GameStart = 1, | |||
| GameRunning = 2, | |||
| GameEnd = 3, | |||
| }; | |||
| // 所有NullXXXType均为错误类型,其余为可能出现的正常类型 | |||
| // 位置标志 | |||
| @@ -85,6 +85,13 @@ namespace Proto2THUAI6 | |||
| {protobuf::HumanState::DEAD, THUAI6::HumanState::Dead}, | |||
| }; | |||
| inline std::map<protobuf::GameState, THUAI6::GameState> gameStateDict{ | |||
| {protobuf::GameState::NULL_GAME_STATE, THUAI6::GameState::NullGameState}, | |||
| {protobuf::GameState::GAME_START, THUAI6::GameState::GameStart}, | |||
| {protobuf::GameState::GAME_RUNNING, THUAI6::GameState::GameRunning}, | |||
| {protobuf::GameState::GAME_END, THUAI6::GameState::GameEnd}, | |||
| }; | |||
| // 用于将Protobuf中的类转换为THUAI6的类 | |||
| inline std::shared_ptr<THUAI6::Butcher> Protobuf2THUAI6Butcher(const protobuf::MessageOfButcher& butcherMsg) | |||
| { | |||
| @@ -2,6 +2,16 @@ | |||
| #include "API.h" | |||
| #define PI 3.14159265358979323846 | |||
| int HumanAPI::GetFrameCount() const | |||
| { | |||
| return logic.GetCounter(); | |||
| } | |||
| int ButcherAPI::GetFrameCount() const | |||
| { | |||
| return logic.GetCounter(); | |||
| } | |||
| std::future<bool> HumanAPI::Move(int64_t timeInMilliseconds, double angleInRadian) | |||
| { | |||
| return std::async(std::launch::async, [&]() | |||
| @@ -114,18 +124,38 @@ std::future<bool> ButcherAPI::HaveMessage() | |||
| { return logic.HaveMessage(); }); | |||
| } | |||
| std::future<std::pair<int64_t, std::string>> HumanAPI::GetMessage() | |||
| std::future<std::optional<std::pair<int64_t, std::string>>> HumanAPI::GetMessage() | |||
| { | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.GetMessage(); }); | |||
| } | |||
| std::future<std::pair<int64_t, std::string>> ButcherAPI::GetMessage() | |||
| std::future<std::optional<std::pair<int64_t, std::string>>> ButcherAPI::GetMessage() | |||
| { | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.GetMessage(); }); | |||
| } | |||
| std::future<bool> HumanAPI::Wait() | |||
| { | |||
| if (logic.GetCounter() == -1) | |||
| return std::async(std::launch::async, [&]() | |||
| { return false; }); | |||
| else | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.WaitThread(); }); | |||
| } | |||
| std::future<bool> ButcherAPI::Wait() | |||
| { | |||
| if (logic.GetCounter() == -1) | |||
| return std::async(std::launch::async, [&]() | |||
| { return false; }); | |||
| else | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.WaitThread(); }); | |||
| } | |||
| std::vector<std::shared_ptr<const THUAI6::Butcher>> HumanAPI::GetButcher() const | |||
| { | |||
| return logic.GetButchers(); | |||
| @@ -178,36 +208,36 @@ std::vector<std::vector<THUAI6::PlaceType>> ButcherAPI::GetFullMap() const | |||
| const std::vector<int64_t> HumanAPI::GetPlayerGUIDs() const | |||
| { | |||
| // todo | |||
| return logic.GetPlayerGUIDs(); | |||
| } | |||
| const std::vector<int64_t> ButcherAPI::GetPlayerGUIDs() const | |||
| { | |||
| // todo | |||
| return logic.GetPlayerGUIDs(); | |||
| } | |||
| std::future<bool> HumanAPI::StartFixMachine() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.StartFixMachine(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.StartFixMachine(); }); | |||
| } | |||
| std::future<bool> HumanAPI::EndFixMachine() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.EndFixMachine(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.EndFixMachine(); }); | |||
| } | |||
| std::future<bool> HumanAPI::StartSaveHuman() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.StartSaveHuman(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.StartSaveHuman(); }); | |||
| } | |||
| std::future<bool> HumanAPI::EndSaveHuman() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.EndSaveHuman(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.EndSaveHuman(); }); | |||
| } | |||
| std::future<bool> HumanAPI::Escape() | |||
| @@ -207,22 +207,13 @@ bool Communication::HaveMessage2Client() | |||
| return haveNewMessage; | |||
| } | |||
| std::pair<int64_t, std::string> Communication::GetMessage() | |||
| std::optional<std::pair<int64_t, std::string>> Communication::GetMessage() | |||
| { | |||
| std::lock_guard<std::mutex> lock(messageMutex); | |||
| if (messageQueue.empty()) | |||
| return std::make_pair(-1, ""); | |||
| else | |||
| { | |||
| auto message = messageQueue.front(); | |||
| messageQueue.pop(); | |||
| return message; | |||
| } | |||
| return messageQueue.tryPop(); | |||
| } | |||
| bool Communication::HaveMessage() | |||
| { | |||
| std::lock_guard<std::mutex> lock(messageMutex); | |||
| return !messageQueue.empty(); | |||
| } | |||
| @@ -236,8 +227,7 @@ void Communication::ReadMessage(int64_t playerID) | |||
| auto reader = THUAI6Stub->GetMessage(&context, request); | |||
| while (reader->Read(&messageReceived)) | |||
| { | |||
| std::lock_guard<std::mutex> lock(messageMutex); | |||
| messageQueue.push(std::make_pair(messageReceived.from_player_id(), messageReceived.message_received())); | |||
| messageQueue.emplace(messageReceived.from_player_id(), messageReceived.message_received()); | |||
| } | |||
| }; | |||
| std::thread(tRead).detach(); | |||
| @@ -245,7 +235,7 @@ void Communication::ReadMessage(int64_t playerID) | |||
| void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, THUAI6::HumanType humanType, THUAI6::ButcherType butcherType) | |||
| { | |||
| auto msgThread = [&]() | |||
| auto tMessage = [&]() | |||
| { | |||
| protobuf::PlayerMsg playerMsg = THUAI62Proto::THUAI62ProtobufPlayer(playerID, playerType, humanType, butcherType); | |||
| grpc::ClientContext context; | |||
| @@ -254,5 +244,5 @@ void Communication::AddPlayer(int64_t playerID, THUAI6::PlayerType playerType, T | |||
| while (MessageReader->Read(&message2Client)) | |||
| haveNewMessage = true; | |||
| }; | |||
| std::thread(msgThread).detach(); | |||
| } | |||
| std::thread(tMessage).detach(); | |||
| } | |||
| @@ -2,6 +2,36 @@ | |||
| #include "API.h" | |||
| #define PI 3.14159265358979323846 | |||
| void HumanDebugAPI::StartTimer() | |||
| { | |||
| StartPoint = std::chrono::system_clock::now(); | |||
| std::time_t t = std::chrono::system_clock::to_time_t(StartPoint); | |||
| } | |||
| void ButcherDebugAPI::StartTimer() | |||
| { | |||
| StartPoint = std::chrono::system_clock::now(); | |||
| std::time_t t = std::chrono::system_clock::to_time_t(StartPoint); | |||
| } | |||
| void HumanDebugAPI::EndTimer() | |||
| { | |||
| } | |||
| void ButcherDebugAPI::EndTimer() | |||
| { | |||
| } | |||
| int HumanDebugAPI::GetFrameCount() const | |||
| { | |||
| return logic.GetCounter(); | |||
| } | |||
| int ButcherDebugAPI::GetFrameCount() const | |||
| { | |||
| return logic.GetCounter(); | |||
| } | |||
| std::future<bool> HumanDebugAPI::Move(int64_t timeInMilliseconds, double angleInRadian) | |||
| { | |||
| return std::async(std::launch::async, [&]() | |||
| @@ -114,18 +144,38 @@ std::future<bool> ButcherDebugAPI::HaveMessage() | |||
| { return logic.HaveMessage(); }); | |||
| } | |||
| std::future<std::pair<int64_t, std::string>> HumanDebugAPI::GetMessage() | |||
| std::future<std::optional<std::pair<int64_t, std::string>>> HumanDebugAPI::GetMessage() | |||
| { | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.GetMessage(); }); | |||
| } | |||
| std::future<std::pair<int64_t, std::string>> ButcherDebugAPI::GetMessage() | |||
| std::future<std::optional<std::pair<int64_t, std::string>>> ButcherDebugAPI::GetMessage() | |||
| { | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.GetMessage(); }); | |||
| } | |||
| std::future<bool> HumanDebugAPI::Wait() | |||
| { | |||
| if (logic.GetCounter() == -1) | |||
| return std::async(std::launch::async, [&]() | |||
| { return false; }); | |||
| else | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.WaitThread(); }); | |||
| } | |||
| std::future<bool> ButcherDebugAPI::Wait() | |||
| { | |||
| if (logic.GetCounter() == -1) | |||
| return std::async(std::launch::async, [&]() | |||
| { return false; }); | |||
| else | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.WaitThread(); }); | |||
| } | |||
| std::vector<std::shared_ptr<const THUAI6::Butcher>> HumanDebugAPI::GetButcher() const | |||
| { | |||
| return logic.GetButchers(); | |||
| @@ -178,36 +228,36 @@ std::vector<std::vector<THUAI6::PlaceType>> ButcherDebugAPI::GetFullMap() const | |||
| const std::vector<int64_t> HumanDebugAPI::GetPlayerGUIDs() const | |||
| { | |||
| // todo | |||
| return logic.GetPlayerGUIDs(); | |||
| } | |||
| const std::vector<int64_t> ButcherDebugAPI::GetPlayerGUIDs() const | |||
| { | |||
| // todo | |||
| return logic.GetPlayerGUIDs(); | |||
| } | |||
| std::future<bool> HumanDebugAPI::StartFixMachine() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.StartFixMachine(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.StartFixMachine(); }); | |||
| } | |||
| std::future<bool> HumanDebugAPI::EndFixMachine() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.EndFixMachine(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.EndFixMachine(); }); | |||
| } | |||
| std::future<bool> HumanDebugAPI::StartSaveHuman() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.StartSaveHuman(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.StartSaveHuman(); }); | |||
| } | |||
| std::future<bool> HumanDebugAPI::EndSaveHuman() | |||
| { | |||
| std::async(std::launch::async, [&]() | |||
| { return logic.EndSaveHuman(); }); | |||
| return std::async(std::launch::async, [&]() | |||
| { return logic.EndSaveHuman(); }); | |||
| } | |||
| std::future<bool> HumanDebugAPI::Escape() | |||
| @@ -96,7 +96,7 @@ bool Logic::HaveMessage() | |||
| return pComm->HaveMessage(); | |||
| } | |||
| std::pair<int64_t, std::string> Logic::GetMessage() | |||
| std::optional<std::pair<int64_t, std::string>> Logic::GetMessage() | |||
| { | |||
| return pComm->GetMessage(); | |||
| } | |||
| @@ -158,13 +158,58 @@ void Logic::ProcessMessage() | |||
| { | |||
| std::cout << "Join Player!" << std::endl; | |||
| pComm->AddPlayer(playerID, playerType, humanType, butcherType); | |||
| while (true) | |||
| while (gameState != THUAI6::GameState::GameEnd) | |||
| { | |||
| if (pComm->HaveMessage2Client()) | |||
| { | |||
| std::cout << "Get Message!" << std::endl; | |||
| auto clientMsg = pComm->GetMessage2Client(); | |||
| LoadBuffer(clientMsg); | |||
| 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<std::mutex> lock(mtxBuffer); | |||
| bufferUpdated = true; | |||
| counterBuffer = -1; | |||
| } | |||
| cvBuffer.notify_one(); | |||
| std::cout << "Game End!" << std::endl; | |||
| break; | |||
| default: | |||
| std::cerr << "Invalid GameState!" << std::endl; | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| @@ -183,34 +228,99 @@ void Logic::LoadBuffer(protobuf::MessageToClient& message) | |||
| bufferState->props.clear(); | |||
| std::cout << "Buffer clear!" << std::endl; | |||
| // 读取新的信息 | |||
| // 读取消息的选择待补充,之后需要另外判断;具体做法应该是先读到自己,然后按照自己的视野做处理。此处暂时全部读了进来 | |||
| for (auto itr = message.human_message().begin(); itr != message.human_message().end(); itr++) | |||
| bufferState->gamemap = Proto2THUAI6::Protobuf2THUAI6Map(message.map_message()); | |||
| if (playerType == THUAI6::PlayerType::HumanPlayer) | |||
| { | |||
| if (itr->player_id() == playerID) | |||
| for (auto item : message.human_message()) | |||
| { | |||
| bufferState->humanSelf = Proto2THUAI6::Protobuf2THUAI6Human(*itr); | |||
| bufferState->humans.push_back(Proto2THUAI6::Protobuf2THUAI6Human(*itr)); | |||
| if (item.player_id() == playerID) | |||
| { | |||
| bufferState->humanSelf = Proto2THUAI6::Protobuf2THUAI6Human(item); | |||
| } | |||
| bufferState->humans.push_back(Proto2THUAI6::Protobuf2THUAI6Human(item)); | |||
| } | |||
| else | |||
| for (auto item : message.butcher_message()) | |||
| { | |||
| bufferState->humans.push_back(Proto2THUAI6::Protobuf2THUAI6Human(*itr)); | |||
| std::cout << "Add Human!" << std::endl; | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| for (auto itr = message.butcher_message().begin(); itr != message.butcher_message().end(); itr++) | |||
| else | |||
| { | |||
| if (itr->player_id() == playerID) | |||
| for (auto item : message.butcher_message()) | |||
| { | |||
| bufferState->butcherSelf = Proto2THUAI6::Protobuf2THUAI6Butcher(*itr); | |||
| bufferState->butchers.push_back(Proto2THUAI6::Protobuf2THUAI6Butcher(*itr)); | |||
| if (item.player_id() == playerID) | |||
| { | |||
| bufferState->butcherSelf = Proto2THUAI6::Protobuf2THUAI6Butcher(item); | |||
| } | |||
| bufferState->butchers.push_back(Proto2THUAI6::Protobuf2THUAI6Butcher(item)); | |||
| } | |||
| for (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; | |||
| } | |||
| } | |||
| else | |||
| bufferState->butchers.push_back(Proto2THUAI6::Protobuf2THUAI6Butcher(*itr)); | |||
| } | |||
| bufferState->gamemap = Proto2THUAI6::Protobuf2THUAI6Map(message.map_message()); | |||
| for (auto item : message.prop_message()) | |||
| bufferState->props.push_back(Proto2THUAI6::Protobuf2THUAI6Prop(item)); | |||
| if (asynchronous) | |||
| { | |||
| { | |||
| @@ -277,6 +387,12 @@ int Logic::GetCounter() const | |||
| return counterState; | |||
| } | |||
| const std::vector<int64_t> Logic::GetPlayerGUIDs() const | |||
| { | |||
| std::unique_lock<std::mutex> lock(mtxState); | |||
| return currentState->guids; | |||
| } | |||
| bool Logic::TryConnection() | |||
| { | |||
| std::cout << "Trying to connect to server..." << std::endl; | |||
| @@ -284,11 +400,8 @@ bool Logic::TryConnection() | |||
| return result; | |||
| } | |||
| void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port) | |||
| void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port, bool level, std::string filename) | |||
| { | |||
| // 构造AI | |||
| pAI = createAI(); | |||
| // 建立与服务器之间通信的组件 | |||
| pComm = std::make_unique<Communication>(IP, port); | |||
| @@ -306,15 +419,24 @@ void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port) | |||
| cvAI.wait(lock, [this]() | |||
| { return AIStart; }); | |||
| } | |||
| std::cout << "AI Start!" << std::endl; | |||
| auto ai = createAI(); | |||
| ProcessMessage(); | |||
| while (AILoop) | |||
| { | |||
| Update(); | |||
| timer->StartTimer(); | |||
| timer->Play(*ai); | |||
| timer->EndTimer(); | |||
| if (asynchronous) | |||
| { | |||
| Wait(); | |||
| timer->StartTimer(); | |||
| timer->Play(*ai); | |||
| timer->EndTimer(); | |||
| } | |||
| else | |||
| { | |||
| Update(); | |||
| timer->StartTimer(); | |||
| timer->Play(*ai); | |||
| timer->EndTimer(); | |||
| } | |||
| } | |||
| }; | |||
| @@ -327,8 +449,8 @@ void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port) | |||
| if (tAI.joinable()) | |||
| { | |||
| std::cout << "Join the AI thread." << std::endl; | |||
| AIStart = true; | |||
| cvAI.notify_one(); | |||
| // 首先开启处理消息的线程 | |||
| ProcessMessage(); | |||
| tAI.join(); | |||
| } | |||
| } | |||
| @@ -337,4 +459,4 @@ void Logic::Main(CreateAIFunc createAI, std::string IP, std::string port) | |||
| std::cout << "Connection error!" << std::endl; | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,27 +1,77 @@ | |||
| #include "AI.h" | |||
| #include "logic.h" | |||
| #include "structures.h" | |||
| #include <tclap/CmdLine.h> | |||
| #ifdef _MSC_VER | |||
| #pragma warning(disable : 4996) | |||
| #endif | |||
| extern const bool asynchronous; | |||
| int THUAI6Main(CreateAIFunc AIBuilder) | |||
| int THUAI6Main(int argc, char** argv, CreateAIFunc AIBuilder) | |||
| { | |||
| // 仅供调试使用 | |||
| int playerID = 123; | |||
| std::string sIP = "183.172.208.84"; | |||
| std::string sPort = "8888"; | |||
| int pID = 114514; | |||
| std::string sIP = "114.51.41.91"; | |||
| std::string sPort = "9810"; | |||
| std::string filename = ""; | |||
| bool level = false; | |||
| extern const THUAI6::PlayerType playerType; | |||
| extern const THUAI6::ButcherType butcherType; | |||
| extern const THUAI6::HumanType humanType; | |||
| THUAI6::PlayerType player = playerType; | |||
| THUAI6::HumanType human = humanType; | |||
| THUAI6::ButcherType butcher = butcherType; | |||
| Logic logic(player, playerID, butcher, human); | |||
| logic.Main(AIBuilder, sIP, sPort); | |||
| // 仅供早期调试使用 | |||
| { | |||
| Logic logic(playerType, pID, butcherType, humanType); | |||
| logic.Main(AIBuilder, sIP, sPort, level, filename); | |||
| return 0; | |||
| } | |||
| // 使用cmdline的版本 | |||
| try | |||
| { | |||
| TCLAP::CmdLine cmd("THUAI6 C++ interface commandline parameter introduction"); | |||
| TCLAP::ValueArg<std::string> serverIP("I", "serverIP", "Server`s IP 127.0.0.1 in default", false, "127.0.0.1", "string"); | |||
| cmd.add(serverIP); | |||
| TCLAP::ValueArg<uint16_t> serverPort("P", "serverPort", "Port the server listens to 7777 in default", false, 7777, "USORT"); | |||
| cmd.add(serverPort); | |||
| std::vector<int> validPlayerIDs{0, 1, 2, 3}; | |||
| TCLAP::ValuesConstraint<int> playerIdConstraint(validPlayerIDs); | |||
| TCLAP::ValueArg<int> playerID("p", "playerID", "Player ID 0,1,2,3 valid only", true, -1, &playerIdConstraint); | |||
| cmd.add(playerID); | |||
| std::string DebugDesc = "Set this flag to use API for debugging.\n" | |||
| "If \"-f\" is not set, the log will be printed on the screen.\n" | |||
| "Or you could specify a file to store it."; | |||
| TCLAP::SwitchArg debug("d", "debug", DebugDesc); | |||
| cmd.add(debug); | |||
| TCLAP::ValueArg<std::string> FileName("f", "filename", "Specify a file to store the log.", false, "", "string"); | |||
| cmd.add(FileName); | |||
| TCLAP::SwitchArg warning("w", "warning", "Warn of some obviously invalid operations (only when \"-d\" is set)."); | |||
| cmd.add(warning); | |||
| cmd.parse(argc, argv); | |||
| pID = playerID.getValue(); | |||
| sIP = serverIP.getValue(); | |||
| sPort = serverPort.getValue(); | |||
| bool d = debug.getValue(); | |||
| bool w = warning.getValue(); | |||
| if (d) | |||
| { | |||
| level = w; | |||
| } | |||
| filename = FileName.getValue(); | |||
| } | |||
| catch (TCLAP::ArgException& e) | |||
| { | |||
| std::cerr << "Parsing error: " << e.error() << " for arg " << e.argId() << std::endl; | |||
| return 1; | |||
| } | |||
| Logic logic(playerType, pID, butcherType, humanType); | |||
| logic.Main(AIBuilder, sIP, sPort, level, filename); | |||
| return 0; | |||
| } | |||
| @@ -30,7 +80,7 @@ std::unique_ptr<IAI> CreateAI() | |||
| return std::make_unique<AI>(); | |||
| } | |||
| int main() | |||
| int main(int argc, char* argv[]) | |||
| { | |||
| return THUAI6Main(CreateAI); | |||
| return THUAI6Main(argc, argv, CreateAI); | |||
| } | |||
| @@ -18,7 +18,7 @@ message(STATUS "Using gRPC ${gRPC_VERSION}") | |||
| add_executable(capi ${CPP_LIST} ${PROTO_CPP_LIST}) | |||
| target_include_directories(capi PUBLIC ${PROJECT_SOURCE_DIR}/proto ${PROJECT_SOURCE_DIR}/API/include) | |||
| target_include_directories(capi PUBLIC ${PROJECT_SOURCE_DIR}/proto ${PROJECT_SOURCE_DIR}/API/include ${PROJECT_SOURCE_DIR}/tclap/include) | |||
| target_link_libraries(capi | |||
| protobuf::libprotobuf | |||
| @@ -158,7 +158,7 @@ namespace protobuf | |||
| ::_pbi::ConstantInitialized | |||
| ) : | |||
| _impl_{ | |||
| /*decltype(_impl_.human_message_)*/ {}, /*decltype(_impl_.butcher_message_)*/ {}, /*decltype(_impl_.prop_message_)*/ {}, /*decltype(_impl_.map_message_)*/ nullptr, /*decltype(_impl_._cached_size_)*/ {}} | |||
| /*decltype(_impl_.human_message_)*/ {}, /*decltype(_impl_.butcher_message_)*/ {}, /*decltype(_impl_.prop_message_)*/ {}, /*decltype(_impl_.map_message_)*/ nullptr, /*decltype(_impl_.game_state_)*/ 0, /*decltype(_impl_._cached_size_)*/ {}} | |||
| { | |||
| } | |||
| struct MessageToClientDefaultTypeInternal | |||
| @@ -340,6 +340,7 @@ const uint32_t TableStruct_Message2Clients_2eproto::offsets[] PROTOBUF_SECTION_V | |||
| PROTOBUF_FIELD_OFFSET(::protobuf::MessageToClient, _impl_.butcher_message_), | |||
| PROTOBUF_FIELD_OFFSET(::protobuf::MessageToClient, _impl_.prop_message_), | |||
| PROTOBUF_FIELD_OFFSET(::protobuf::MessageToClient, _impl_.map_message_), | |||
| PROTOBUF_FIELD_OFFSET(::protobuf::MessageToClient, _impl_.game_state_), | |||
| ~0u, // no _has_bits_ | |||
| PROTOBUF_FIELD_OFFSET(::protobuf::MoveRes, _internal_metadata_), | |||
| ~0u, // no _extensions_ | |||
| @@ -374,9 +375,9 @@ static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protode | |||
| {68, -1, -1, sizeof(::protobuf::MessageOfMap_Row)}, | |||
| {75, -1, -1, sizeof(::protobuf::MessageOfMap)}, | |||
| {82, -1, -1, sizeof(::protobuf::MessageToClient)}, | |||
| {92, -1, -1, sizeof(::protobuf::MoveRes)}, | |||
| {101, -1, -1, sizeof(::protobuf::BoolRes)}, | |||
| {108, -1, -1, sizeof(::protobuf::MsgRes)}, | |||
| {93, -1, -1, sizeof(::protobuf::MoveRes)}, | |||
| {102, -1, -1, sizeof(::protobuf::BoolRes)}, | |||
| {109, -1, -1, sizeof(::protobuf::MsgRes)}, | |||
| }; | |||
| static const ::_pb::Message* const file_default_instances[] = { | |||
| @@ -423,18 +424,19 @@ const char descriptor_table_protodef_Message2Clients_2eproto[] PROTOBUF_SECTION_ | |||
| "\t\n\001y\030\003 \001(\005\022\030\n\020facing_direction\030\004 \001(\001\022\022\n\n" | |||
| "mapping_id\030\005 \001(\003\"`\n\014MessageOfMap\022\'\n\003row\030" | |||
| "\002 \003(\0132\032.protobuf.MessageOfMap.Row\032\'\n\003Row" | |||
| "\022 \n\003col\030\001 \003(\0162\023.protobuf.PlaceType\"\323\001\n\017M" | |||
| "\022 \n\003col\030\001 \003(\0162\023.protobuf.PlaceType\"\374\001\n\017M" | |||
| "essageToClient\022/\n\rhuman_message\030\001 \003(\0132\030." | |||
| "protobuf.MessageOfHuman\0223\n\017butcher_messa" | |||
| "ge\030\002 \003(\0132\032.protobuf.MessageOfButcher\022-\n\014" | |||
| "prop_message\030\003 \003(\0132\027.protobuf.MessageOfP" | |||
| "rop\022+\n\013map_message\030\004 \001(\0132\026.protobuf.Mess" | |||
| "ageOfMap\"J\n\007MoveRes\022\024\n\014actual_speed\030\001 \001(" | |||
| "\003\022\024\n\014actual_angle\030\002 \001(\001\022\023\n\013act_success\030\003" | |||
| " \001(\010\"\036\n\007BoolRes\022\023\n\013act_success\030\001 \001(\010\"P\n\006" | |||
| "MsgRes\022\024\n\014have_message\030\001 \001(\010\022\026\n\016from_pla" | |||
| "yer_id\030\002 \001(\003\022\030\n\020message_received\030\003 \001(\tb\006" | |||
| "proto3"; | |||
| "ageOfMap\022\'\n\ngame_state\030\005 \001(\0162\023.protobuf." | |||
| "GameState\"J\n\007MoveRes\022\024\n\014actual_speed\030\001 \001" | |||
| "(\003\022\024\n\014actual_angle\030\002 \001(\001\022\023\n\013act_success\030" | |||
| "\003 \001(\010\"\036\n\007BoolRes\022\023\n\013act_success\030\001 \001(\010\"P\n" | |||
| "\006MsgRes\022\024\n\014have_message\030\001 \001(\010\022\026\n\016from_pl" | |||
| "ayer_id\030\002 \001(\003\022\030\n\020message_received\030\003 \001(\tb" | |||
| "\006proto3"; | |||
| static const ::_pbi::DescriptorTable* const descriptor_table_Message2Clients_2eproto_deps[1] = { | |||
| &::descriptor_table_MessageType_2eproto, | |||
| }; | |||
| @@ -442,7 +444,7 @@ static ::_pbi::once_flag descriptor_table_Message2Clients_2eproto_once; | |||
| const ::_pbi::DescriptorTable descriptor_table_Message2Clients_2eproto = { | |||
| false, | |||
| false, | |||
| 1646, | |||
| 1687, | |||
| descriptor_table_protodef_Message2Clients_2eproto, | |||
| "Message2Clients.proto", | |||
| &descriptor_table_Message2Clients_2eproto_once, | |||
| @@ -3044,13 +3046,14 @@ namespace protobuf | |||
| MessageToClient* const _this = this; | |||
| (void)_this; | |||
| new (&_impl_) Impl_{ | |||
| decltype(_impl_.human_message_){from._impl_.human_message_}, decltype(_impl_.butcher_message_){from._impl_.butcher_message_}, decltype(_impl_.prop_message_){from._impl_.prop_message_}, decltype(_impl_.map_message_){nullptr}, /*decltype(_impl_._cached_size_)*/ {}}; | |||
| decltype(_impl_.human_message_){from._impl_.human_message_}, decltype(_impl_.butcher_message_){from._impl_.butcher_message_}, decltype(_impl_.prop_message_){from._impl_.prop_message_}, decltype(_impl_.map_message_){nullptr}, decltype(_impl_.game_state_){}, /*decltype(_impl_._cached_size_)*/ {}}; | |||
| _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); | |||
| if (from._internal_has_map_message()) | |||
| { | |||
| _this->_impl_.map_message_ = new ::protobuf::MessageOfMap(*from._impl_.map_message_); | |||
| } | |||
| _this->_impl_.game_state_ = from._impl_.game_state_; | |||
| // @@protoc_insertion_point(copy_constructor:protobuf.MessageToClient) | |||
| } | |||
| @@ -3061,7 +3064,7 @@ namespace protobuf | |||
| (void)arena; | |||
| (void)is_message_owned; | |||
| new (&_impl_) Impl_{ | |||
| decltype(_impl_.human_message_){arena}, decltype(_impl_.butcher_message_){arena}, decltype(_impl_.prop_message_){arena}, decltype(_impl_.map_message_){nullptr}, /*decltype(_impl_._cached_size_)*/ {}}; | |||
| decltype(_impl_.human_message_){arena}, decltype(_impl_.butcher_message_){arena}, decltype(_impl_.prop_message_){arena}, decltype(_impl_.map_message_){nullptr}, decltype(_impl_.game_state_){0}, /*decltype(_impl_._cached_size_)*/ {}}; | |||
| } | |||
| MessageToClient::~MessageToClient() | |||
| @@ -3105,6 +3108,7 @@ namespace protobuf | |||
| delete _impl_.map_message_; | |||
| } | |||
| _impl_.map_message_ = nullptr; | |||
| _impl_.game_state_ = 0; | |||
| _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); | |||
| } | |||
| @@ -3180,6 +3184,17 @@ namespace protobuf | |||
| else | |||
| goto handle_unusual; | |||
| continue; | |||
| // .protobuf.GameState game_state = 5; | |||
| case 5: | |||
| if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 40)) | |||
| { | |||
| uint64_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); | |||
| CHK_(ptr); | |||
| _internal_set_game_state(static_cast<::protobuf::GameState>(val)); | |||
| } | |||
| else | |||
| goto handle_unusual; | |||
| continue; | |||
| default: | |||
| goto handle_unusual; | |||
| } // switch | |||
| @@ -3254,6 +3269,15 @@ namespace protobuf | |||
| InternalWriteMessage(4, _Internal::map_message(this), _Internal::map_message(this).GetCachedSize(), target, stream); | |||
| } | |||
| // .protobuf.GameState game_state = 5; | |||
| if (this->_internal_game_state() != 0) | |||
| { | |||
| target = stream->EnsureSpace(target); | |||
| target = ::_pbi::WireFormatLite::WriteEnumToArray( | |||
| 5, this->_internal_game_state(), target | |||
| ); | |||
| } | |||
| if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) | |||
| { | |||
| target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray( | |||
| @@ -3306,6 +3330,13 @@ namespace protobuf | |||
| ); | |||
| } | |||
| // .protobuf.GameState game_state = 5; | |||
| if (this->_internal_game_state() != 0) | |||
| { | |||
| total_size += 1 + | |||
| ::_pbi::WireFormatLite::EnumSize(this->_internal_game_state()); | |||
| } | |||
| return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); | |||
| } | |||
| @@ -3335,6 +3366,10 @@ namespace protobuf | |||
| from._internal_map_message() | |||
| ); | |||
| } | |||
| if (from._internal_game_state() != 0) | |||
| { | |||
| _this->_internal_set_game_state(from._internal_game_state()); | |||
| } | |||
| _this->_internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); | |||
| } | |||
| @@ -3359,7 +3394,11 @@ namespace protobuf | |||
| _impl_.human_message_.InternalSwap(&other->_impl_.human_message_); | |||
| _impl_.butcher_message_.InternalSwap(&other->_impl_.butcher_message_); | |||
| _impl_.prop_message_.InternalSwap(&other->_impl_.prop_message_); | |||
| swap(_impl_.map_message_, other->_impl_.map_message_); | |||
| ::PROTOBUF_NAMESPACE_ID::internal::memswap< | |||
| PROTOBUF_FIELD_OFFSET(MessageToClient, _impl_.game_state_) + sizeof(MessageToClient::_impl_.game_state_) - PROTOBUF_FIELD_OFFSET(MessageToClient, _impl_.map_message_)>( | |||
| reinterpret_cast<char*>(&_impl_.map_message_), | |||
| reinterpret_cast<char*>(&other->_impl_.map_message_) | |||
| ); | |||
| } | |||
| ::PROTOBUF_NAMESPACE_ID::Metadata MessageToClient::GetMetadata() const | |||
| @@ -1951,6 +1951,7 @@ namespace protobuf | |||
| kButcherMessageFieldNumber = 2, | |||
| kPropMessageFieldNumber = 3, | |||
| kMapMessageFieldNumber = 4, | |||
| kGameStateFieldNumber = 5, | |||
| }; | |||
| // repeated .protobuf.MessageOfHuman human_message = 1; | |||
| int human_message_size() const; | |||
| @@ -2041,6 +2042,16 @@ namespace protobuf | |||
| ); | |||
| ::protobuf::MessageOfMap* unsafe_arena_release_map_message(); | |||
| // .protobuf.GameState game_state = 5; | |||
| void clear_game_state(); | |||
| ::protobuf::GameState game_state() const; | |||
| void set_game_state(::protobuf::GameState value); | |||
| private: | |||
| ::protobuf::GameState _internal_game_state() const; | |||
| void _internal_set_game_state(::protobuf::GameState value); | |||
| public: | |||
| // @@protoc_insertion_point(class_scope:protobuf.MessageToClient) | |||
| private: | |||
| @@ -2056,6 +2067,7 @@ namespace protobuf | |||
| ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<::protobuf::MessageOfButcher> butcher_message_; | |||
| ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<::protobuf::MessageOfProp> prop_message_; | |||
| ::protobuf::MessageOfMap* map_message_; | |||
| int game_state_; | |||
| mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; | |||
| }; | |||
| union | |||
| @@ -4208,6 +4220,30 @@ namespace protobuf | |||
| // @@protoc_insertion_point(field_set_allocated:protobuf.MessageToClient.map_message) | |||
| } | |||
| // .protobuf.GameState game_state = 5; | |||
| inline void MessageToClient::clear_game_state() | |||
| { | |||
| _impl_.game_state_ = 0; | |||
| } | |||
| inline ::protobuf::GameState MessageToClient::_internal_game_state() const | |||
| { | |||
| return static_cast<::protobuf::GameState>(_impl_.game_state_); | |||
| } | |||
| inline ::protobuf::GameState MessageToClient::game_state() const | |||
| { | |||
| // @@protoc_insertion_point(field_get:protobuf.MessageToClient.game_state) | |||
| return _internal_game_state(); | |||
| } | |||
| inline void MessageToClient::_internal_set_game_state(::protobuf::GameState value) | |||
| { | |||
| _impl_.game_state_ = value; | |||
| } | |||
| inline void MessageToClient::set_game_state(::protobuf::GameState value) | |||
| { | |||
| _internal_set_game_state(value); | |||
| // @@protoc_insertion_point(field_set:protobuf.MessageToClient.game_state) | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // MoveRes | |||
| @@ -23,7 +23,7 @@ namespace _pbi = _pb::internal; | |||
| namespace protobuf | |||
| { | |||
| } // namespace protobuf | |||
| static const ::_pb::EnumDescriptor* file_level_enum_descriptors_MessageType_2eproto[9]; | |||
| static const ::_pb::EnumDescriptor* file_level_enum_descriptors_MessageType_2eproto[10]; | |||
| static constexpr ::_pb::ServiceDescriptor const** file_level_service_descriptors_MessageType_2eproto = nullptr; | |||
| const uint32_t TableStruct_MessageType_2eproto::offsets[1] = {}; | |||
| static constexpr ::_pbi::MigrationSchema* schemas = nullptr; | |||
| @@ -51,12 +51,14 @@ const char descriptor_table_protodef_MessageType_2eproto[] PROTOBUF_SECTION_VARI | |||
| "\020\003\022\016\n\nHUMANTYPE4\020\004*l\n\013ButcherType\022\025\n\021NUL" | |||
| "L_BUTCHER_TYPE\020\000\022\020\n\014BUTCHERTYPE1\020\001\022\020\n\014BU" | |||
| "TCHERTYPE2\020\002\022\020\n\014BUTCHERTYPE3\020\003\022\020\n\014BUTCHE" | |||
| "RTYPE4\020\004b\006proto3"; | |||
| "RTYPE4\020\004*P\n\tGameState\022\023\n\017NULL_GAME_STATE" | |||
| "\020\000\022\016\n\nGAME_START\020\001\022\020\n\014GAME_RUNNING\020\002\022\014\n\010" | |||
| "GAME_END\020\003b\006proto3"; | |||
| static ::_pbi::once_flag descriptor_table_MessageType_2eproto_once; | |||
| const ::_pbi::DescriptorTable descriptor_table_MessageType_2eproto = { | |||
| false, | |||
| false, | |||
| 856, | |||
| 938, | |||
| descriptor_table_protodef_MessageType_2eproto, | |||
| "MessageType.proto", | |||
| &descriptor_table_MessageType_2eproto_once, | |||
| @@ -258,6 +260,25 @@ namespace protobuf | |||
| } | |||
| } | |||
| const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GameState_descriptor() | |||
| { | |||
| ::PROTOBUF_NAMESPACE_ID::internal::AssignDescriptors(&descriptor_table_MessageType_2eproto); | |||
| return file_level_enum_descriptors_MessageType_2eproto[9]; | |||
| } | |||
| bool GameState_IsValid(int value) | |||
| { | |||
| switch (value) | |||
| { | |||
| case 0: | |||
| case 1: | |||
| case 2: | |||
| case 3: | |||
| return true; | |||
| default: | |||
| return false; | |||
| } | |||
| } | |||
| // @@protoc_insertion_point(namespace_scope) | |||
| } // namespace protobuf | |||
| PROTOBUF_NAMESPACE_OPEN | |||
| @@ -337,6 +337,37 @@ namespace protobuf | |||
| ButcherType_descriptor(), name, value | |||
| ); | |||
| } | |||
| enum GameState : int | |||
| { | |||
| NULL_GAME_STATE = 0, | |||
| GAME_START = 1, | |||
| GAME_RUNNING = 2, | |||
| GAME_END = 3, | |||
| GameState_INT_MIN_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::min(), | |||
| GameState_INT_MAX_SENTINEL_DO_NOT_USE_ = std::numeric_limits<int32_t>::max() | |||
| }; | |||
| bool GameState_IsValid(int value); | |||
| constexpr GameState GameState_MIN = NULL_GAME_STATE; | |||
| constexpr GameState GameState_MAX = GAME_END; | |||
| constexpr int GameState_ARRAYSIZE = GameState_MAX + 1; | |||
| const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor* GameState_descriptor(); | |||
| template<typename T> | |||
| inline const std::string& GameState_Name(T enum_t_value) | |||
| { | |||
| static_assert(::std::is_same<T, GameState>::value || ::std::is_integral<T>::value, "Incorrect type passed to function GameState_Name."); | |||
| return ::PROTOBUF_NAMESPACE_ID::internal::NameOfEnum( | |||
| GameState_descriptor(), enum_t_value | |||
| ); | |||
| } | |||
| inline bool GameState_Parse( | |||
| ::PROTOBUF_NAMESPACE_ID::ConstStringParam name, GameState* value | |||
| ) | |||
| { | |||
| return ::PROTOBUF_NAMESPACE_ID::internal::ParseNamedEnum<GameState>( | |||
| GameState_descriptor(), name, value | |||
| ); | |||
| } | |||
| // =================================================================== | |||
| // =================================================================== | |||
| @@ -438,6 +469,15 @@ inline const EnumDescriptor* GetEnumDescriptor<::protobuf::ButcherType>() | |||
| { | |||
| return ::protobuf::ButcherType_descriptor(); | |||
| } | |||
| template<> | |||
| struct is_proto_enum<::protobuf::GameState> : ::std::true_type | |||
| { | |||
| }; | |||
| template<> | |||
| inline const EnumDescriptor* GetEnumDescriptor<::protobuf::GameState>() | |||
| { | |||
| return ::protobuf::GameState_descriptor(); | |||
| } | |||
| PROTOBUF_NAMESPACE_CLOSE | |||
| @@ -0,0 +1,23 @@ | |||
| Copyright (c) 2003 Michael E. Smoot | |||
| Copyright (c) 2004 Daniel Aarno | |||
| Copyright (c) 2017 Google Inc. | |||
| Permission is hereby granted, free of charge, to any person | |||
| obtaining a copy of this software and associated documentation | |||
| files (the "Software"), to deal in the Software without restriction, | |||
| including without limitation the rights to use, copy, modify, merge, | |||
| publish, distribute, sublicense, and/or sell copies of the Software, | |||
| and to permit persons to whom the Software is furnished to do so, | |||
| subject to the following conditions: | |||
| The above copyright notice and this permission notice shall be | |||
| included in all copies or substantial portions of the Software. | |||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |||
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |||
| BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |||
| AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | |||
| IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
| THE SOFTWARE. | |||
| @@ -0,0 +1,723 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: Arg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno . | |||
| * Copyright (c) 2017 Google Inc. | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_ARGUMENT_H | |||
| #define TCLAP_ARGUMENT_H | |||
| #ifdef HAVE_CONFIG_H | |||
| #include <config.h> | |||
| #endif | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <iomanip> | |||
| #include <cstdio> | |||
| #include <tclap/sstream.h> | |||
| #include <tclap/ArgException.h> | |||
| #include <tclap/Visitor.h> | |||
| #include <tclap/CmdLineInterface.h> | |||
| #include <tclap/ArgTraits.h> | |||
| #include <tclap/StandardTraits.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A virtual base class that defines the essential data for all arguments. | |||
| * This class, or one of its existing children, must be subclassed to do | |||
| * anything. | |||
| */ | |||
| class Arg | |||
| { | |||
| private: | |||
| /** | |||
| * Prevent accidental copying. | |||
| */ | |||
| Arg(const Arg& rhs); | |||
| /** | |||
| * Prevent accidental copying. | |||
| */ | |||
| Arg& operator=(const Arg& rhs); | |||
| /** | |||
| * Indicates whether the rest of the arguments should be ignored. | |||
| */ | |||
| static bool& ignoreRestRef() | |||
| { | |||
| static bool ign = false; | |||
| return ign; | |||
| } | |||
| /** | |||
| * The delimiter that separates an argument flag/name from the | |||
| * value. | |||
| */ | |||
| static char& delimiterRef() | |||
| { | |||
| static char delim = ' '; | |||
| return delim; | |||
| } | |||
| protected: | |||
| /** | |||
| * The single char flag used to identify the argument. | |||
| * This value (preceded by a dash {-}), can be used to identify | |||
| * an argument on the command line. The _flag can be blank, | |||
| * in fact this is how unlabeled args work. Unlabeled args must | |||
| * override appropriate functions to get correct handling. Note | |||
| * that the _flag does NOT include the dash as part of the flag. | |||
| */ | |||
| std::string _flag; | |||
| /** | |||
| * A single word namd identifying the argument. | |||
| * This value (preceded by two dashed {--}) can also be used | |||
| * to identify an argument on the command line. Note that the | |||
| * _name does NOT include the two dashes as part of the _name. The | |||
| * _name cannot be blank. | |||
| */ | |||
| std::string _name; | |||
| /** | |||
| * Description of the argument. | |||
| */ | |||
| std::string _description; | |||
| /** | |||
| * Indicating whether the argument is required. | |||
| */ | |||
| bool _required; | |||
| /** | |||
| * Label to be used in usage description. Normally set to | |||
| * "required", but can be changed when necessary. | |||
| */ | |||
| std::string _requireLabel; | |||
| /** | |||
| * Indicates whether a value is required for the argument. | |||
| * Note that the value may be required but the argument/value | |||
| * combination may not be, as specified by _required. | |||
| */ | |||
| bool _valueRequired; | |||
| /** | |||
| * Indicates whether the argument has been set. | |||
| * Indicates that a value on the command line has matched the | |||
| * name/flag of this argument and the values have been set accordingly. | |||
| */ | |||
| bool _alreadySet; | |||
| /** | |||
| * A pointer to a visitor object. | |||
| * The visitor allows special handling to occur as soon as the | |||
| * argument is matched. This defaults to NULL and should not | |||
| * be used unless absolutely necessary. | |||
| */ | |||
| Visitor* _visitor; | |||
| /** | |||
| * Whether this argument can be ignored, if desired. | |||
| */ | |||
| bool _ignoreable; | |||
| /** | |||
| * Indicates that the arg was set as part of an XOR and not on the | |||
| * command line. | |||
| */ | |||
| bool _xorSet; | |||
| bool _acceptsMultipleValues; | |||
| /** | |||
| * Performs the special handling described by the Visitor. | |||
| */ | |||
| void _checkWithVisitor() const; | |||
| /** | |||
| * Primary constructor. YOU (yes you) should NEVER construct an Arg | |||
| * directly, this is a base class that is extended by various children | |||
| * that are meant to be used. Use SwitchArg, ValueArg, MultiArg, | |||
| * UnlabeledValueArg, or UnlabeledMultiArg instead. | |||
| * | |||
| * \param flag - The flag identifying the argument. | |||
| * \param name - The name identifying the argument. | |||
| * \param desc - The description of the argument, used in the usage. | |||
| * \param req - Whether the argument is required. | |||
| * \param valreq - Whether the a value is required for the argument. | |||
| * \param v - The visitor checked by the argument. Defaults to NULL. | |||
| */ | |||
| Arg(const std::string& flag, | |||
| const std::string& name, | |||
| const std::string& desc, | |||
| bool req, | |||
| bool valreq, | |||
| Visitor* v = NULL); | |||
| public: | |||
| /** | |||
| * Destructor. | |||
| */ | |||
| virtual ~Arg(); | |||
| /** | |||
| * Adds this to the specified list of Args. | |||
| * \param argList - The list to add this to. | |||
| */ | |||
| virtual void addToList(std::list<Arg*>& argList) const; | |||
| /** | |||
| * Begin ignoring arguments since the "--" argument was specified. | |||
| */ | |||
| static void beginIgnoring() | |||
| { | |||
| ignoreRestRef() = true; | |||
| } | |||
| /** | |||
| * Whether to ignore the rest. | |||
| */ | |||
| static bool ignoreRest() | |||
| { | |||
| return ignoreRestRef(); | |||
| } | |||
| /** | |||
| * The delimiter that separates an argument flag/name from the | |||
| * value. | |||
| */ | |||
| static char delimiter() | |||
| { | |||
| return delimiterRef(); | |||
| } | |||
| /** | |||
| * The char used as a place holder when SwitchArgs are combined. | |||
| * Currently set to the bell char (ASCII 7). | |||
| */ | |||
| static char blankChar() | |||
| { | |||
| return (char)7; | |||
| } | |||
| /** | |||
| * The char that indicates the beginning of a flag. Defaults to '-', but | |||
| * clients can define TCLAP_FLAGSTARTCHAR to override. | |||
| */ | |||
| #ifndef TCLAP_FLAGSTARTCHAR | |||
| #define TCLAP_FLAGSTARTCHAR '-' | |||
| #endif | |||
| static char flagStartChar() | |||
| { | |||
| return TCLAP_FLAGSTARTCHAR; | |||
| } | |||
| /** | |||
| * The sting that indicates the beginning of a flag. Defaults to "-", but | |||
| * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same | |||
| * as TCLAP_FLAGSTARTCHAR. | |||
| */ | |||
| #ifndef TCLAP_FLAGSTARTSTRING | |||
| #define TCLAP_FLAGSTARTSTRING "-" | |||
| #endif | |||
| static const std::string flagStartString() | |||
| { | |||
| return TCLAP_FLAGSTARTSTRING; | |||
| } | |||
| /** | |||
| * The sting that indicates the beginning of a name. Defaults to "--", but | |||
| * clients can define TCLAP_NAMESTARTSTRING to override. | |||
| */ | |||
| #ifndef TCLAP_NAMESTARTSTRING | |||
| #define TCLAP_NAMESTARTSTRING "--" | |||
| #endif | |||
| static const std::string nameStartString() | |||
| { | |||
| return TCLAP_NAMESTARTSTRING; | |||
| } | |||
| /** | |||
| * The name used to identify the ignore rest argument. | |||
| */ | |||
| static const std::string ignoreNameString() | |||
| { | |||
| return "ignore_rest"; | |||
| } | |||
| /** | |||
| * Sets the delimiter for all arguments. | |||
| * \param c - The character that delimits flags/names from values. | |||
| */ | |||
| static void setDelimiter(char c) | |||
| { | |||
| delimiterRef() = c; | |||
| } | |||
| /** | |||
| * Pure virtual method meant to handle the parsing and value assignment | |||
| * of the string on the command line. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. What is | |||
| * passed in from main. | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args) = 0; | |||
| /** | |||
| * Operator ==. | |||
| * Equality operator. Must be virtual to handle unlabeled args. | |||
| * \param a - The Arg to be compared to this. | |||
| */ | |||
| virtual bool operator==(const Arg& a) const; | |||
| /** | |||
| * Returns the argument flag. | |||
| */ | |||
| const std::string& getFlag() const; | |||
| /** | |||
| * Returns the argument name. | |||
| */ | |||
| const std::string& getName() const; | |||
| /** | |||
| * Returns the argument description. | |||
| */ | |||
| std::string getDescription() const; | |||
| /** | |||
| * Indicates whether the argument is required. | |||
| */ | |||
| virtual bool isRequired() const; | |||
| /** | |||
| * Sets _required to true. This is used by the XorHandler. | |||
| * You really have no reason to ever use it. | |||
| */ | |||
| void forceRequired(); | |||
| /** | |||
| * Sets the _alreadySet value to true. This is used by the XorHandler. | |||
| * You really have no reason to ever use it. | |||
| */ | |||
| void xorSet(); | |||
| /** | |||
| * Indicates whether a value must be specified for argument. | |||
| */ | |||
| bool isValueRequired() const; | |||
| /** | |||
| * Indicates whether the argument has already been set. Only true | |||
| * if the arg has been matched on the command line. | |||
| */ | |||
| bool isSet() const; | |||
| /** | |||
| * Indicates whether the argument can be ignored, if desired. | |||
| */ | |||
| bool isIgnoreable() const; | |||
| /** | |||
| * A method that tests whether a string matches this argument. | |||
| * This is generally called by the processArg() method. This | |||
| * method could be re-implemented by a child to change how | |||
| * arguments are specified on the command line. | |||
| * \param s - The string to be compared to the flag/name to determine | |||
| * whether the arg matches. | |||
| */ | |||
| virtual bool argMatches(const std::string& s) const; | |||
| /** | |||
| * Returns a simple string representation of the argument. | |||
| * Primarily for debugging. | |||
| */ | |||
| virtual std::string toString() const; | |||
| /** | |||
| * Returns a short ID for the usage. | |||
| * \param valueId - The value used in the id. | |||
| */ | |||
| virtual std::string shortID(const std::string& valueId = "val") const; | |||
| /** | |||
| * Returns a long ID for the usage. | |||
| * \param valueId - The value used in the id. | |||
| */ | |||
| virtual std::string longID(const std::string& valueId = "val") const; | |||
| /** | |||
| * Trims a value off of the flag. | |||
| * \param flag - The string from which the flag and value will be | |||
| * trimmed. Contains the flag once the value has been trimmed. | |||
| * \param value - Where the value trimmed from the string will | |||
| * be stored. | |||
| */ | |||
| virtual void trimFlag(std::string& flag, std::string& value) const; | |||
| /** | |||
| * Checks whether a given string has blank chars, indicating that | |||
| * it is a combined SwitchArg. If so, return true, otherwise return | |||
| * false. | |||
| * \param s - string to be checked. | |||
| */ | |||
| bool _hasBlanks(const std::string& s) const; | |||
| /** | |||
| * Sets the requireLabel. Used by XorHandler. You shouldn't ever | |||
| * use this. | |||
| * \param s - Set the requireLabel to this value. | |||
| */ | |||
| void setRequireLabel(const std::string& s); | |||
| /** | |||
| * Used for MultiArgs and XorHandler to determine whether args | |||
| * can still be set. | |||
| */ | |||
| virtual bool allowMore(); | |||
| /** | |||
| * Use by output classes to determine whether an Arg accepts | |||
| * multiple values. | |||
| */ | |||
| virtual bool acceptsMultipleValues(); | |||
| /** | |||
| * Clears the Arg object and allows it to be reused by new | |||
| * command lines. | |||
| */ | |||
| virtual void reset(); | |||
| }; | |||
| /** | |||
| * Typedef of an Arg list iterator. | |||
| */ | |||
| typedef std::list<Arg*>::const_iterator ArgListIterator; | |||
| /** | |||
| * Typedef of an Arg vector iterator. | |||
| */ | |||
| typedef std::vector<Arg*>::const_iterator ArgVectorIterator; | |||
| /** | |||
| * Typedef of a Visitor list iterator. | |||
| */ | |||
| typedef std::list<Visitor*>::const_iterator VisitorListIterator; | |||
| /* | |||
| * Extract a value of type T from it's string representation contained | |||
| * in strVal. The ValueLike parameter used to select the correct | |||
| * specialization of ExtractValue depending on the value traits of T. | |||
| * ValueLike traits use operator>> to assign the value from strVal. | |||
| */ | |||
| template<typename T> | |||
| void | |||
| ExtractValue(T& destVal, const std::string& strVal, ValueLike vl) | |||
| { | |||
| static_cast<void>(vl); // Avoid warning about unused vl | |||
| istringstream is(strVal.c_str()); | |||
| int valuesRead = 0; | |||
| while (is.good()) | |||
| { | |||
| if (is.peek() != EOF) | |||
| #ifdef TCLAP_SETBASE_ZERO | |||
| is >> std::setbase(0) >> destVal; | |||
| #else | |||
| is >> destVal; | |||
| #endif | |||
| else | |||
| break; | |||
| valuesRead++; | |||
| } | |||
| if (is.fail()) | |||
| throw(ArgParseException("Couldn't read argument value " | |||
| "from string '" + | |||
| strVal + "'")); | |||
| if (valuesRead > 1) | |||
| throw(ArgParseException("More than one valid value parsed from " | |||
| "string '" + | |||
| strVal + "'")); | |||
| } | |||
| /* | |||
| * Extract a value of type T from it's string representation contained | |||
| * in strVal. The ValueLike parameter used to select the correct | |||
| * specialization of ExtractValue depending on the value traits of T. | |||
| * StringLike uses assignment (operator=) to assign from strVal. | |||
| */ | |||
| template<typename T> | |||
| void | |||
| ExtractValue(T& destVal, const std::string& strVal, StringLike sl) | |||
| { | |||
| static_cast<void>(sl); // Avoid warning about unused sl | |||
| SetString(destVal, strVal); | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // BEGIN Arg.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| inline Arg::Arg(const std::string& flag, const std::string& name, const std::string& desc, bool req, bool valreq, Visitor* v) : | |||
| _flag(flag), | |||
| _name(name), | |||
| _description(desc), | |||
| _required(req), | |||
| _requireLabel("required"), | |||
| _valueRequired(valreq), | |||
| _alreadySet(false), | |||
| _visitor(v), | |||
| _ignoreable(true), | |||
| _xorSet(false), | |||
| _acceptsMultipleValues(false) | |||
| { | |||
| if (_flag.length() > 1) | |||
| throw(SpecificationException( | |||
| "Argument flag can only be one character long", toString() | |||
| )); | |||
| if (_name != ignoreNameString() && | |||
| (_flag == Arg::flagStartString() || | |||
| _flag == Arg::nameStartString() || | |||
| _flag == " ")) | |||
| throw(SpecificationException("Argument flag cannot be either '" + Arg::flagStartString() + "' or '" + Arg::nameStartString() + "' or a space.", toString())); | |||
| if ((_name.substr(0, Arg::flagStartString().length()) == Arg::flagStartString()) || | |||
| (_name.substr(0, Arg::nameStartString().length()) == Arg::nameStartString()) || | |||
| (_name.find(" ", 0) != std::string::npos)) | |||
| throw(SpecificationException("Argument name begin with either '" + Arg::flagStartString() + "' or '" + Arg::nameStartString() + "' or space.", toString())); | |||
| } | |||
| inline Arg::~Arg() | |||
| { | |||
| } | |||
| inline std::string Arg::shortID(const std::string& valueId) const | |||
| { | |||
| std::string id = ""; | |||
| if (_flag != "") | |||
| id = Arg::flagStartString() + _flag; | |||
| else | |||
| id = Arg::nameStartString() + _name; | |||
| if (_valueRequired) | |||
| id += std::string(1, Arg::delimiter()) + "<" + valueId + ">"; | |||
| if (!_required) | |||
| id = "[" + id + "]"; | |||
| return id; | |||
| } | |||
| inline std::string Arg::longID(const std::string& valueId) const | |||
| { | |||
| std::string id = ""; | |||
| if (_flag != "") | |||
| { | |||
| id += Arg::flagStartString() + _flag; | |||
| if (_valueRequired) | |||
| id += std::string(1, Arg::delimiter()) + "<" + valueId + ">"; | |||
| id += ", "; | |||
| } | |||
| id += Arg::nameStartString() + _name; | |||
| if (_valueRequired) | |||
| id += std::string(1, Arg::delimiter()) + "<" + valueId + ">"; | |||
| return id; | |||
| } | |||
| inline bool Arg::operator==(const Arg& a) const | |||
| { | |||
| if ((_flag != "" && _flag == a._flag) || _name == a._name) | |||
| return true; | |||
| else | |||
| return false; | |||
| } | |||
| inline std::string Arg::getDescription() const | |||
| { | |||
| std::string desc = ""; | |||
| if (_required) | |||
| desc = "(" + _requireLabel + ") "; | |||
| // if ( _valueRequired ) | |||
| // desc += "(value required) "; | |||
| desc += _description; | |||
| return desc; | |||
| } | |||
| inline const std::string& Arg::getFlag() const | |||
| { | |||
| return _flag; | |||
| } | |||
| inline const std::string& Arg::getName() const | |||
| { | |||
| return _name; | |||
| } | |||
| inline bool Arg::isRequired() const | |||
| { | |||
| return _required; | |||
| } | |||
| inline bool Arg::isValueRequired() const | |||
| { | |||
| return _valueRequired; | |||
| } | |||
| inline bool Arg::isSet() const | |||
| { | |||
| if (_alreadySet && !_xorSet) | |||
| return true; | |||
| else | |||
| return false; | |||
| } | |||
| inline bool Arg::isIgnoreable() const | |||
| { | |||
| return _ignoreable; | |||
| } | |||
| inline void Arg::setRequireLabel(const std::string& s) | |||
| { | |||
| _requireLabel = s; | |||
| } | |||
| inline bool Arg::argMatches(const std::string& argFlag) const | |||
| { | |||
| if ((argFlag == Arg::flagStartString() + _flag && _flag != "") || | |||
| argFlag == Arg::nameStartString() + _name) | |||
| return true; | |||
| else | |||
| return false; | |||
| } | |||
| inline std::string Arg::toString() const | |||
| { | |||
| std::string s = ""; | |||
| if (_flag != "") | |||
| s += Arg::flagStartString() + _flag + " "; | |||
| s += "(" + Arg::nameStartString() + _name + ")"; | |||
| return s; | |||
| } | |||
| inline void Arg::_checkWithVisitor() const | |||
| { | |||
| if (_visitor != NULL) | |||
| _visitor->visit(); | |||
| } | |||
| /** | |||
| * Implementation of trimFlag. | |||
| */ | |||
| inline void Arg::trimFlag(std::string& flag, std::string& value) const | |||
| { | |||
| int stop = 0; | |||
| for (int i = 0; static_cast<unsigned int>(i) < flag.length(); i++) | |||
| if (flag[i] == Arg::delimiter()) | |||
| { | |||
| stop = i; | |||
| break; | |||
| } | |||
| if (stop > 1) | |||
| { | |||
| value = flag.substr(stop + 1); | |||
| flag = flag.substr(0, stop); | |||
| } | |||
| } | |||
| /** | |||
| * Implementation of _hasBlanks. | |||
| */ | |||
| inline bool Arg::_hasBlanks(const std::string& s) const | |||
| { | |||
| for (int i = 1; static_cast<unsigned int>(i) < s.length(); i++) | |||
| if (s[i] == Arg::blankChar()) | |||
| return true; | |||
| return false; | |||
| } | |||
| inline void Arg::forceRequired() | |||
| { | |||
| _required = true; | |||
| } | |||
| inline void Arg::xorSet() | |||
| { | |||
| _alreadySet = true; | |||
| _xorSet = true; | |||
| } | |||
| /** | |||
| * Overridden by Args that need to added to the end of the list. | |||
| */ | |||
| inline void Arg::addToList(std::list<Arg*>& argList) const | |||
| { | |||
| argList.push_front(const_cast<Arg*>(this)); | |||
| } | |||
| inline bool Arg::allowMore() | |||
| { | |||
| return false; | |||
| } | |||
| inline bool Arg::acceptsMultipleValues() | |||
| { | |||
| return _acceptsMultipleValues; | |||
| } | |||
| inline void Arg::reset() | |||
| { | |||
| _xorSet = false; | |||
| _alreadySet = false; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // END Arg.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,206 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: ArgException.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2017 Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_ARG_EXCEPTION_H | |||
| #define TCLAP_ARG_EXCEPTION_H | |||
| #include <string> | |||
| #include <exception> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A simple class that defines and argument exception. Should be caught | |||
| * whenever a CmdLine is created and parsed. | |||
| */ | |||
| class ArgException : public std::exception | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param text - The text of the exception. | |||
| * \param id - The text identifying the argument source. | |||
| * \param td - Text describing the type of ArgException it is. | |||
| * of the exception. | |||
| */ | |||
| ArgException(const std::string& text = "undefined exception", const std::string& id = "undefined", const std::string& td = "Generic ArgException") : | |||
| std::exception(), | |||
| _errorText(text), | |||
| _argId(id), | |||
| _typeDescription(td) | |||
| { | |||
| } | |||
| /** | |||
| * Destructor. | |||
| */ | |||
| virtual ~ArgException() throw() | |||
| { | |||
| } | |||
| /** | |||
| * Returns the error text. | |||
| */ | |||
| std::string error() const | |||
| { | |||
| return (_errorText); | |||
| } | |||
| /** | |||
| * Returns the argument id. | |||
| */ | |||
| std::string argId() const | |||
| { | |||
| if (_argId == "undefined") | |||
| return " "; | |||
| else | |||
| return ("Argument: " + _argId); | |||
| } | |||
| /** | |||
| * Returns the arg id and error text. | |||
| */ | |||
| const char* what() const throw() | |||
| { | |||
| static std::string ex; | |||
| ex = _argId + " -- " + _errorText; | |||
| return ex.c_str(); | |||
| } | |||
| /** | |||
| * Returns the type of the exception. Used to explain and distinguish | |||
| * between different child exceptions. | |||
| */ | |||
| std::string typeDescription() const | |||
| { | |||
| return _typeDescription; | |||
| } | |||
| private: | |||
| /** | |||
| * The text of the exception message. | |||
| */ | |||
| std::string _errorText; | |||
| /** | |||
| * The argument related to this exception. | |||
| */ | |||
| std::string _argId; | |||
| /** | |||
| * Describes the type of the exception. Used to distinguish | |||
| * between different child exceptions. | |||
| */ | |||
| std::string _typeDescription; | |||
| }; | |||
| /** | |||
| * Thrown from within the child Arg classes when it fails to properly | |||
| * parse the argument it has been passed. | |||
| */ | |||
| class ArgParseException : public ArgException | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param text - The text of the exception. | |||
| * \param id - The text identifying the argument source | |||
| * of the exception. | |||
| */ | |||
| ArgParseException(const std::string& text = "undefined exception", const std::string& id = "undefined") : | |||
| ArgException(text, id, std::string("Exception found while parsing ") + std::string("the value the Arg has been passed.")) | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * Thrown from CmdLine when the arguments on the command line are not | |||
| * properly specified, e.g. too many arguments, required argument missing, etc. | |||
| */ | |||
| class CmdLineParseException : public ArgException | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param text - The text of the exception. | |||
| * \param id - The text identifying the argument source | |||
| * of the exception. | |||
| */ | |||
| CmdLineParseException(const std::string& text = "undefined exception", const std::string& id = "undefined") : | |||
| ArgException(text, id, std::string("Exception found when the values ") + std::string("on the command line do not meet ") + std::string("the requirements of the defined ") + std::string("Args.")) | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. | |||
| * same flag as another Arg, same name, etc. | |||
| */ | |||
| class SpecificationException : public ArgException | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param text - The text of the exception. | |||
| * \param id - The text identifying the argument source | |||
| * of the exception. | |||
| */ | |||
| SpecificationException(const std::string& text = "undefined exception", const std::string& id = "undefined") : | |||
| ArgException(text, id, std::string("Exception found when an Arg object ") + std::string("is improperly defined by the ") + std::string("developer.")) | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * Thrown when TCLAP thinks the program should exit. | |||
| * | |||
| * For example after parse error this exception will be thrown (and | |||
| * normally caught). This allows any resource to be clened properly | |||
| * before exit. | |||
| * | |||
| * If exception handling is disabled (CmdLine::setExceptionHandling), | |||
| * this exception will propagate to the call site, allowing the | |||
| * program to catch it and avoid program termination, or do it's own | |||
| * cleanup. See for example, https://sourceforge.net/p/tclap/bugs/29. | |||
| */ | |||
| class ExitException | |||
| { | |||
| public: | |||
| ExitException(int estat) : | |||
| _estat(estat) | |||
| { | |||
| } | |||
| int getExitStatus() const | |||
| { | |||
| return _estat; | |||
| } | |||
| private: | |||
| int _estat; | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,139 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: ArgTraits.h | |||
| * | |||
| * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . | |||
| * Copyright (c) 2017 Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| // This is an internal tclap file, you should probably not have to | |||
| // include this directly | |||
| #ifndef TCLAP_ARGTRAITS_H | |||
| #define TCLAP_ARGTRAITS_H | |||
| namespace TCLAP | |||
| { | |||
| // We use two empty structs to get compile type specialization | |||
| // function to work | |||
| /** | |||
| * A value like argument value type is a value that can be set using | |||
| * operator>>. This is the default value type. | |||
| */ | |||
| struct ValueLike | |||
| { | |||
| typedef ValueLike ValueCategory; | |||
| virtual ~ValueLike() | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * A string like argument value type is a value that can be set using | |||
| * operator=(string). Useful if the value type contains spaces which | |||
| * will be broken up into individual tokens by operator>>. | |||
| */ | |||
| struct StringLike | |||
| { | |||
| virtual ~StringLike() | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * A class can inherit from this object to make it have string like | |||
| * traits. This is a compile time thing and does not add any overhead | |||
| * to the inherenting class. | |||
| */ | |||
| struct StringLikeTrait | |||
| { | |||
| typedef StringLike ValueCategory; | |||
| virtual ~StringLikeTrait() | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * A class can inherit from this object to make it have value like | |||
| * traits. This is a compile time thing and does not add any overhead | |||
| * to the inherenting class. | |||
| */ | |||
| struct ValueLikeTrait | |||
| { | |||
| typedef ValueLike ValueCategory; | |||
| virtual ~ValueLikeTrait() | |||
| { | |||
| } | |||
| }; | |||
| /** | |||
| * Arg traits are used to get compile type specialization when parsing | |||
| * argument values. Using an ArgTraits you can specify the way that | |||
| * values gets assigned to any particular type during parsing. The two | |||
| * supported types are StringLike and ValueLike. ValueLike is the | |||
| * default and means that operator>> will be used to assign values to | |||
| * the type. | |||
| */ | |||
| template<typename T> | |||
| class ArgTraits | |||
| { | |||
| // This is a bit silly, but what we want to do is: | |||
| // 1) If there exists a specialization of ArgTraits for type X, | |||
| // use it. | |||
| // | |||
| // 2) If no specialization exists but X has the typename | |||
| // X::ValueCategory, use the specialization for X::ValueCategory. | |||
| // | |||
| // 3) If neither (1) nor (2) defines the trait, use the default | |||
| // which is ValueLike. | |||
| // This is the "how": | |||
| // | |||
| // test<T>(0) (where 0 is the NULL ptr) will match | |||
| // test(typename C::ValueCategory*) iff type T has the | |||
| // corresponding typedef. If it does not test(...) will be | |||
| // matched. This allows us to determine if T::ValueCategory | |||
| // exists by checking the sizeof for the test function (return | |||
| // value must have different sizeof). | |||
| template<typename C> | |||
| static short test(typename C::ValueCategory*); | |||
| template<typename C> | |||
| static long test(...); | |||
| static const bool hasTrait = sizeof(test<T>(0)) == sizeof(short); | |||
| template<typename C, bool> | |||
| struct DefaultArgTrait | |||
| { | |||
| typedef ValueLike ValueCategory; | |||
| }; | |||
| template<typename C> | |||
| struct DefaultArgTrait<C, true> | |||
| { | |||
| typedef typename C::ValueCategory ValueCategory; | |||
| }; | |||
| public: | |||
| typedef typename DefaultArgTrait<T, hasTrait>::ValueCategory ValueCategory; | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,651 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: CmdLine.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_CMDLINE_H | |||
| #define TCLAP_CMDLINE_H | |||
| #include <tclap/SwitchArg.h> | |||
| #include <tclap/MultiSwitchArg.h> | |||
| #include <tclap/UnlabeledValueArg.h> | |||
| #include <tclap/UnlabeledMultiArg.h> | |||
| #include <tclap/XorHandler.h> | |||
| #include <tclap/HelpVisitor.h> | |||
| #include <tclap/VersionVisitor.h> | |||
| #include <tclap/IgnoreRestVisitor.h> | |||
| #include <tclap/CmdLineOutput.h> | |||
| #include <tclap/StdOutput.h> | |||
| #include <tclap/Constraint.h> | |||
| #include <tclap/ValuesConstraint.h> | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <iomanip> | |||
| #include <algorithm> | |||
| #include <stdlib.h> // Needed for exit(), which isn't defined in some envs. | |||
| namespace TCLAP | |||
| { | |||
| template<typename T> | |||
| void DelPtr(T ptr) | |||
| { | |||
| delete ptr; | |||
| } | |||
| template<typename C> | |||
| void ClearContainer(C& c) | |||
| { | |||
| typedef typename C::value_type value_type; | |||
| std::for_each(c.begin(), c.end(), DelPtr<value_type>); | |||
| c.clear(); | |||
| } | |||
| /** | |||
| * The base class that manages the command line definition and passes | |||
| * along the parsing to the appropriate Arg classes. | |||
| */ | |||
| class CmdLine : public CmdLineInterface | |||
| { | |||
| protected: | |||
| /** | |||
| * The list of arguments that will be tested against the | |||
| * command line. | |||
| */ | |||
| std::list<Arg*> _argList; | |||
| /** | |||
| * The name of the program. Set to argv[0]. | |||
| */ | |||
| std::string _progName; | |||
| /** | |||
| * A message used to describe the program. Used in the usage output. | |||
| */ | |||
| std::string _message; | |||
| /** | |||
| * The version to be displayed with the --version switch. | |||
| */ | |||
| std::string _version; | |||
| /** | |||
| * The number of arguments that are required to be present on | |||
| * the command line. This is set dynamically, based on the | |||
| * Args added to the CmdLine object. | |||
| */ | |||
| int _numRequired; | |||
| /** | |||
| * The character that is used to separate the argument flag/name | |||
| * from the value. Defaults to ' ' (space). | |||
| */ | |||
| char _delimiter; | |||
| /** | |||
| * The handler that manages xoring lists of args. | |||
| */ | |||
| XorHandler _xorHandler; | |||
| /** | |||
| * A list of Args to be explicitly deleted when the destructor | |||
| * is called. At the moment, this only includes the three default | |||
| * Args. | |||
| */ | |||
| std::list<Arg*> _argDeleteOnExitList; | |||
| /** | |||
| * A list of Visitors to be explicitly deleted when the destructor | |||
| * is called. At the moment, these are the Visitors created for the | |||
| * default Args. | |||
| */ | |||
| std::list<Visitor*> _visitorDeleteOnExitList; | |||
| /** | |||
| * Object that handles all output for the CmdLine. | |||
| */ | |||
| CmdLineOutput* _output; | |||
| /** | |||
| * Should CmdLine handle parsing exceptions internally? | |||
| */ | |||
| bool _handleExceptions; | |||
| /** | |||
| * Throws an exception listing the missing args. | |||
| */ | |||
| void missingArgsException(); | |||
| /** | |||
| * Checks whether a name/flag string matches entirely matches | |||
| * the Arg::blankChar. Used when multiple switches are combined | |||
| * into a single argument. | |||
| * \param s - The message to be used in the usage. | |||
| */ | |||
| bool _emptyCombined(const std::string& s); | |||
| /** | |||
| * Perform a delete ptr; operation on ptr when this object is deleted. | |||
| */ | |||
| void deleteOnExit(Arg* ptr); | |||
| /** | |||
| * Perform a delete ptr; operation on ptr when this object is deleted. | |||
| */ | |||
| void deleteOnExit(Visitor* ptr); | |||
| private: | |||
| /** | |||
| * Prevent accidental copying. | |||
| */ | |||
| CmdLine(const CmdLine& rhs); | |||
| CmdLine& operator=(const CmdLine& rhs); | |||
| /** | |||
| * Encapsulates the code common to the constructors | |||
| * (which is all of it). | |||
| */ | |||
| void _constructor(); | |||
| /** | |||
| * Is set to true when a user sets the output object. We use this so | |||
| * that we don't delete objects that are created outside of this lib. | |||
| */ | |||
| bool _userSetOutput; | |||
| /** | |||
| * Whether or not to automatically create help and version switches. | |||
| */ | |||
| bool _helpAndVersion; | |||
| /** | |||
| * Whether or not to ignore unmatched args. | |||
| */ | |||
| bool _ignoreUnmatched; | |||
| public: | |||
| /** | |||
| * Command line constructor. Defines how the arguments will be | |||
| * parsed. | |||
| * \param message - The message to be used in the usage | |||
| * output. | |||
| * \param delimiter - The character that is used to separate | |||
| * the argument flag/name from the value. Defaults to ' ' (space). | |||
| * \param version - The version number to be used in the | |||
| * --version switch. | |||
| * \param helpAndVersion - Whether or not to create the Help and | |||
| * Version switches. Defaults to true. | |||
| */ | |||
| CmdLine(const std::string& message, const char delimiter = ' ', const std::string& version = "none", bool helpAndVersion = true); | |||
| /** | |||
| * Deletes any resources allocated by a CmdLine object. | |||
| */ | |||
| virtual ~CmdLine(); | |||
| /** | |||
| * Adds an argument to the list of arguments to be parsed. | |||
| * \param a - Argument to be added. | |||
| */ | |||
| void add(Arg& a); | |||
| /** | |||
| * An alternative add. Functionally identical. | |||
| * \param a - Argument to be added. | |||
| */ | |||
| void add(Arg* a); | |||
| /** | |||
| * Add two Args that will be xor'd. If this method is used, add does | |||
| * not need to be called. | |||
| * \param a - Argument to be added and xor'd. | |||
| * \param b - Argument to be added and xor'd. | |||
| */ | |||
| void xorAdd(Arg& a, Arg& b); | |||
| /** | |||
| * Add a list of Args that will be xor'd. If this method is used, | |||
| * add does not need to be called. | |||
| * \param xors - List of Args to be added and xor'd. | |||
| */ | |||
| void xorAdd(const std::vector<Arg*>& xors); | |||
| /** | |||
| * Parses the command line. | |||
| * \param argc - Number of arguments. | |||
| * \param argv - Array of arguments. | |||
| */ | |||
| void parse(int argc, const char* const* argv); | |||
| /** | |||
| * Parses the command line. | |||
| * \param args - A vector of strings representing the args. | |||
| * args[0] is still the program name. | |||
| */ | |||
| void parse(std::vector<std::string>& args); | |||
| /** | |||
| * | |||
| */ | |||
| CmdLineOutput* getOutput(); | |||
| /** | |||
| * | |||
| */ | |||
| void setOutput(CmdLineOutput* co); | |||
| /** | |||
| * | |||
| */ | |||
| std::string& getVersion(); | |||
| /** | |||
| * | |||
| */ | |||
| std::string& getProgramName(); | |||
| /** | |||
| * | |||
| */ | |||
| std::list<Arg*>& getArgList(); | |||
| /** | |||
| * | |||
| */ | |||
| XorHandler& getXorHandler(); | |||
| /** | |||
| * | |||
| */ | |||
| char getDelimiter(); | |||
| /** | |||
| * | |||
| */ | |||
| std::string& getMessage(); | |||
| /** | |||
| * | |||
| */ | |||
| bool hasHelpAndVersion(); | |||
| /** | |||
| * Disables or enables CmdLine's internal parsing exception handling. | |||
| * | |||
| * @param state Should CmdLine handle parsing exceptions internally? | |||
| */ | |||
| void setExceptionHandling(const bool state); | |||
| /** | |||
| * Returns the current state of the internal exception handling. | |||
| * | |||
| * @retval true Parsing exceptions are handled internally. | |||
| * @retval false Parsing exceptions are propagated to the caller. | |||
| */ | |||
| bool getExceptionHandling() const; | |||
| /** | |||
| * Allows the CmdLine object to be reused. | |||
| */ | |||
| void reset(); | |||
| /** | |||
| * Allows unmatched args to be ignored. By default false. | |||
| * | |||
| * @param ignore If true the cmdline will ignore any unmatched args | |||
| * and if false it will behave as normal. | |||
| */ | |||
| void ignoreUnmatched(const bool ignore); | |||
| }; | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // Begin CmdLine.cpp | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| inline CmdLine::CmdLine(const std::string& m, char delim, const std::string& v, bool help) : | |||
| _argList(std::list<Arg*>()), | |||
| _progName("not_set_yet"), | |||
| _message(m), | |||
| _version(v), | |||
| _numRequired(0), | |||
| _delimiter(delim), | |||
| _xorHandler(XorHandler()), | |||
| _argDeleteOnExitList(std::list<Arg*>()), | |||
| _visitorDeleteOnExitList(std::list<Visitor*>()), | |||
| _output(0), | |||
| _handleExceptions(true), | |||
| _userSetOutput(false), | |||
| _helpAndVersion(help), | |||
| _ignoreUnmatched(false) | |||
| { | |||
| _constructor(); | |||
| } | |||
| inline CmdLine::~CmdLine() | |||
| { | |||
| ClearContainer(_argDeleteOnExitList); | |||
| ClearContainer(_visitorDeleteOnExitList); | |||
| if (!_userSetOutput) | |||
| { | |||
| delete _output; | |||
| _output = 0; | |||
| } | |||
| } | |||
| inline void CmdLine::_constructor() | |||
| { | |||
| _output = new StdOutput; | |||
| Arg::setDelimiter(_delimiter); | |||
| Visitor* v; | |||
| if (_helpAndVersion) | |||
| { | |||
| v = new HelpVisitor(this, &_output); | |||
| SwitchArg* help = new SwitchArg("h", "help", "Displays usage information and exits.", false, v); | |||
| add(help); | |||
| deleteOnExit(help); | |||
| deleteOnExit(v); | |||
| v = new VersionVisitor(this, &_output); | |||
| SwitchArg* vers = new SwitchArg("", "version", "Displays version information and exits.", false, v); | |||
| add(vers); | |||
| deleteOnExit(vers); | |||
| deleteOnExit(v); | |||
| } | |||
| v = new IgnoreRestVisitor(); | |||
| SwitchArg* ignore = new SwitchArg(Arg::flagStartString(), Arg::ignoreNameString(), "Ignores the rest of the labeled arguments following this flag.", false, v); | |||
| add(ignore); | |||
| deleteOnExit(ignore); | |||
| deleteOnExit(v); | |||
| } | |||
| inline void CmdLine::xorAdd(const std::vector<Arg*>& ors) | |||
| { | |||
| _xorHandler.add(ors); | |||
| for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++) | |||
| { | |||
| (*it)->forceRequired(); | |||
| (*it)->setRequireLabel("OR required"); | |||
| add(*it); | |||
| } | |||
| } | |||
| inline void CmdLine::xorAdd(Arg& a, Arg& b) | |||
| { | |||
| std::vector<Arg*> ors; | |||
| ors.push_back(&a); | |||
| ors.push_back(&b); | |||
| xorAdd(ors); | |||
| } | |||
| inline void CmdLine::add(Arg& a) | |||
| { | |||
| add(&a); | |||
| } | |||
| inline void CmdLine::add(Arg* a) | |||
| { | |||
| for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) | |||
| if (*a == *(*it)) | |||
| throw(SpecificationException( | |||
| "Argument with same flag/name already exists!", | |||
| a->longID() | |||
| )); | |||
| a->addToList(_argList); | |||
| if (a->isRequired()) | |||
| _numRequired++; | |||
| } | |||
| inline void CmdLine::parse(int argc, const char* const* argv) | |||
| { | |||
| // this step is necessary so that we have easy access to | |||
| // mutable strings. | |||
| std::vector<std::string> args; | |||
| for (int i = 0; i < argc; i++) | |||
| args.push_back(argv[i]); | |||
| parse(args); | |||
| } | |||
| inline void CmdLine::parse(std::vector<std::string>& args) | |||
| { | |||
| bool shouldExit = false; | |||
| int estat = 0; | |||
| try | |||
| { | |||
| if (args.empty()) | |||
| { | |||
| // https://sourceforge.net/p/tclap/bugs/30/ | |||
| throw CmdLineParseException("The args vector must not be empty, " | |||
| "the first entry should contain the " | |||
| "program's name."); | |||
| } | |||
| _progName = args.front(); | |||
| args.erase(args.begin()); | |||
| int requiredCount = 0; | |||
| for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) | |||
| { | |||
| bool matched = false; | |||
| for (ArgListIterator it = _argList.begin(); | |||
| it != _argList.end(); | |||
| it++) | |||
| { | |||
| if ((*it)->processArg(&i, args)) | |||
| { | |||
| requiredCount += _xorHandler.check(*it); | |||
| matched = true; | |||
| break; | |||
| } | |||
| } | |||
| // checks to see if the argument is an empty combined | |||
| // switch and if so, then we've actually matched it | |||
| if (!matched && _emptyCombined(args[i])) | |||
| matched = true; | |||
| if (!matched && !Arg::ignoreRest() && !_ignoreUnmatched) | |||
| throw(CmdLineParseException("Couldn't find match " | |||
| "for argument", | |||
| args[i])); | |||
| } | |||
| if (requiredCount < _numRequired) | |||
| missingArgsException(); | |||
| if (requiredCount > _numRequired) | |||
| throw(CmdLineParseException("Too many arguments!")); | |||
| } | |||
| catch (ArgException& e) | |||
| { | |||
| // If we're not handling the exceptions, rethrow. | |||
| if (!_handleExceptions) | |||
| { | |||
| throw; | |||
| } | |||
| try | |||
| { | |||
| _output->failure(*this, e); | |||
| } | |||
| catch (ExitException& ee) | |||
| { | |||
| estat = ee.getExitStatus(); | |||
| shouldExit = true; | |||
| } | |||
| } | |||
| catch (ExitException& ee) | |||
| { | |||
| // If we're not handling the exceptions, rethrow. | |||
| if (!_handleExceptions) | |||
| { | |||
| throw; | |||
| } | |||
| estat = ee.getExitStatus(); | |||
| shouldExit = true; | |||
| } | |||
| if (shouldExit) | |||
| exit(estat); | |||
| } | |||
| inline bool CmdLine::_emptyCombined(const std::string& s) | |||
| { | |||
| if (s.length() > 0 && s[0] != Arg::flagStartChar()) | |||
| return false; | |||
| for (int i = 1; static_cast<unsigned int>(i) < s.length(); i++) | |||
| if (s[i] != Arg::blankChar()) | |||
| return false; | |||
| return true; | |||
| } | |||
| inline void CmdLine::missingArgsException() | |||
| { | |||
| int count = 0; | |||
| std::string missingArgList; | |||
| for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) | |||
| { | |||
| if ((*it)->isRequired() && !(*it)->isSet()) | |||
| { | |||
| missingArgList += (*it)->getName(); | |||
| missingArgList += ", "; | |||
| count++; | |||
| } | |||
| } | |||
| missingArgList = missingArgList.substr(0, missingArgList.length() - 2); | |||
| std::string msg; | |||
| if (count > 1) | |||
| msg = "Required arguments missing: "; | |||
| else | |||
| msg = "Required argument missing: "; | |||
| msg += missingArgList; | |||
| throw(CmdLineParseException(msg)); | |||
| } | |||
| inline void CmdLine::deleteOnExit(Arg* ptr) | |||
| { | |||
| _argDeleteOnExitList.push_back(ptr); | |||
| } | |||
| inline void CmdLine::deleteOnExit(Visitor* ptr) | |||
| { | |||
| _visitorDeleteOnExitList.push_back(ptr); | |||
| } | |||
| inline CmdLineOutput* CmdLine::getOutput() | |||
| { | |||
| return _output; | |||
| } | |||
| inline void CmdLine::setOutput(CmdLineOutput* co) | |||
| { | |||
| if (!_userSetOutput) | |||
| delete _output; | |||
| _userSetOutput = true; | |||
| _output = co; | |||
| } | |||
| inline std::string& CmdLine::getVersion() | |||
| { | |||
| return _version; | |||
| } | |||
| inline std::string& CmdLine::getProgramName() | |||
| { | |||
| return _progName; | |||
| } | |||
| inline std::list<Arg*>& CmdLine::getArgList() | |||
| { | |||
| return _argList; | |||
| } | |||
| inline XorHandler& CmdLine::getXorHandler() | |||
| { | |||
| return _xorHandler; | |||
| } | |||
| inline char CmdLine::getDelimiter() | |||
| { | |||
| return _delimiter; | |||
| } | |||
| inline std::string& CmdLine::getMessage() | |||
| { | |||
| return _message; | |||
| } | |||
| inline bool CmdLine::hasHelpAndVersion() | |||
| { | |||
| return _helpAndVersion; | |||
| } | |||
| inline void CmdLine::setExceptionHandling(const bool state) | |||
| { | |||
| _handleExceptions = state; | |||
| } | |||
| inline bool CmdLine::getExceptionHandling() const | |||
| { | |||
| return _handleExceptions; | |||
| } | |||
| inline void CmdLine::reset() | |||
| { | |||
| for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++) | |||
| (*it)->reset(); | |||
| _progName.clear(); | |||
| } | |||
| inline void CmdLine::ignoreUnmatched(const bool ignore) | |||
| { | |||
| _ignoreUnmatched = ignore; | |||
| } | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| // End CmdLine.cpp | |||
| /////////////////////////////////////////////////////////////////////////////// | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,152 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: CmdLineInterface.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_COMMANDLINE_INTERFACE_H | |||
| #define TCLAP_COMMANDLINE_INTERFACE_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <algorithm> | |||
| namespace TCLAP | |||
| { | |||
| class Arg; | |||
| class CmdLineOutput; | |||
| class XorHandler; | |||
| /** | |||
| * The base class that manages the command line definition and passes | |||
| * along the parsing to the appropriate Arg classes. | |||
| */ | |||
| class CmdLineInterface | |||
| { | |||
| public: | |||
| /** | |||
| * Destructor | |||
| */ | |||
| virtual ~CmdLineInterface() | |||
| { | |||
| } | |||
| /** | |||
| * Adds an argument to the list of arguments to be parsed. | |||
| * \param a - Argument to be added. | |||
| */ | |||
| virtual void add(Arg& a) = 0; | |||
| /** | |||
| * An alternative add. Functionally identical. | |||
| * \param a - Argument to be added. | |||
| */ | |||
| virtual void add(Arg* a) = 0; | |||
| /** | |||
| * Add two Args that will be xor'd. | |||
| * If this method is used, add does | |||
| * not need to be called. | |||
| * \param a - Argument to be added and xor'd. | |||
| * \param b - Argument to be added and xor'd. | |||
| */ | |||
| virtual void xorAdd(Arg& a, Arg& b) = 0; | |||
| /** | |||
| * Add a list of Args that will be xor'd. If this method is used, | |||
| * add does not need to be called. | |||
| * \param xors - List of Args to be added and xor'd. | |||
| */ | |||
| virtual void xorAdd(const std::vector<Arg*>& xors) = 0; | |||
| /** | |||
| * Parses the command line. | |||
| * \param argc - Number of arguments. | |||
| * \param argv - Array of arguments. | |||
| */ | |||
| virtual void parse(int argc, const char* const* argv) = 0; | |||
| /** | |||
| * Parses the command line. | |||
| * \param args - A vector of strings representing the args. | |||
| * args[0] is still the program name. | |||
| */ | |||
| void parse(std::vector<std::string>& args); | |||
| /** | |||
| * Returns the CmdLineOutput object. | |||
| */ | |||
| virtual CmdLineOutput* getOutput() = 0; | |||
| /** | |||
| * \param co - CmdLineOutput object that we want to use instead. | |||
| */ | |||
| virtual void setOutput(CmdLineOutput* co) = 0; | |||
| /** | |||
| * Returns the version string. | |||
| */ | |||
| virtual std::string& getVersion() = 0; | |||
| /** | |||
| * Returns the program name string. | |||
| */ | |||
| virtual std::string& getProgramName() = 0; | |||
| /** | |||
| * Returns the argList. | |||
| */ | |||
| virtual std::list<Arg*>& getArgList() = 0; | |||
| /** | |||
| * Returns the XorHandler. | |||
| */ | |||
| virtual XorHandler& getXorHandler() = 0; | |||
| /** | |||
| * Returns the delimiter string. | |||
| */ | |||
| virtual char getDelimiter() = 0; | |||
| /** | |||
| * Returns the message string. | |||
| */ | |||
| virtual std::string& getMessage() = 0; | |||
| /** | |||
| * Indicates whether or not the help and version switches were created | |||
| * automatically. | |||
| */ | |||
| virtual bool hasHelpAndVersion() = 0; | |||
| /** | |||
| * Resets the instance as if it had just been constructed so that the | |||
| * instance can be reused. | |||
| */ | |||
| virtual void reset() = 0; | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,74 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: CmdLineOutput.h | |||
| * | |||
| * Copyright (c) 2004, Michael E. Smoot | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_CMDLINEOUTPUT_H | |||
| #define TCLAP_CMDLINEOUTPUT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <iomanip> | |||
| #include <algorithm> | |||
| namespace TCLAP | |||
| { | |||
| class CmdLineInterface; | |||
| class ArgException; | |||
| /** | |||
| * The interface that any output object must implement. | |||
| */ | |||
| class CmdLineOutput | |||
| { | |||
| public: | |||
| /** | |||
| * Virtual destructor. | |||
| */ | |||
| virtual ~CmdLineOutput() | |||
| { | |||
| } | |||
| /** | |||
| * Generates some sort of output for the USAGE. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void usage(CmdLineInterface& c) = 0; | |||
| /** | |||
| * Generates some sort of output for the version. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void version(CmdLineInterface& c) = 0; | |||
| /** | |||
| * Generates some sort of output for a failure. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| * \param e - The ArgException that caused the failure. | |||
| */ | |||
| virtual void failure(CmdLineInterface& c, ArgException& e) = 0; | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,81 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: Constraint.h | |||
| * | |||
| * Copyright (c) 2005, Michael E. Smoot | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_CONSTRAINT_H | |||
| #define TCLAP_CONSTRAINT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <iomanip> | |||
| #include <algorithm> | |||
| #include <stdexcept> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * The interface that defines the interaction between the Arg and Constraint. | |||
| */ | |||
| template<class T> | |||
| class Constraint | |||
| { | |||
| public: | |||
| /** | |||
| * Returns a description of the Constraint. | |||
| */ | |||
| virtual std::string description() const = 0; | |||
| /** | |||
| * Returns the short ID for the Constraint. | |||
| */ | |||
| virtual std::string shortID() const = 0; | |||
| /** | |||
| * The method used to verify that the value parsed from the command | |||
| * line meets the constraint. | |||
| * \param value - The value that will be checked. | |||
| */ | |||
| virtual bool check(const T& value) const = 0; | |||
| /** | |||
| * Destructor. | |||
| * Silences warnings about Constraint being a base class with virtual | |||
| * functions but without a virtual destructor. | |||
| */ | |||
| virtual ~Constraint() | |||
| { | |||
| ; | |||
| } | |||
| static std::string shortID(Constraint<T>* constraint) | |||
| { | |||
| if (!constraint) | |||
| throw std::logic_error("Cannot create a ValueArg with a NULL constraint"); | |||
| return constraint->shortID(); | |||
| } | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,299 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: DocBookOutput.h | |||
| * | |||
| * Copyright (c) 2004, Michael E. Smoot | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_DOCBOOKOUTPUT_H | |||
| #define TCLAP_DOCBOOKOUTPUT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <algorithm> | |||
| #include <tclap/CmdLineInterface.h> | |||
| #include <tclap/CmdLineOutput.h> | |||
| #include <tclap/XorHandler.h> | |||
| #include <tclap/Arg.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A class that generates DocBook output for usage() method for the | |||
| * given CmdLine and its Args. | |||
| */ | |||
| class DocBookOutput : public CmdLineOutput | |||
| { | |||
| public: | |||
| /** | |||
| * Prints the usage to stdout. Can be overridden to | |||
| * produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void usage(CmdLineInterface& c); | |||
| /** | |||
| * Prints the version to stdout. Can be overridden | |||
| * to produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void version(CmdLineInterface& c); | |||
| /** | |||
| * Prints (to stderr) an error message, short usage | |||
| * Can be overridden to produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| * \param e - The ArgException that caused the failure. | |||
| */ | |||
| virtual void failure(CmdLineInterface& c, ArgException& e); | |||
| DocBookOutput() : | |||
| theDelimiter('=') | |||
| { | |||
| } | |||
| protected: | |||
| /** | |||
| * Substitutes the char r for string x in string s. | |||
| * \param s - The string to operate on. | |||
| * \param r - The char to replace. | |||
| * \param x - What to replace r with. | |||
| */ | |||
| void substituteSpecialChars(std::string& s, char r, std::string& x); | |||
| void removeChar(std::string& s, char r); | |||
| void basename(std::string& s); | |||
| void printShortArg(Arg* it); | |||
| void printLongArg(Arg* it); | |||
| char theDelimiter; | |||
| }; | |||
| inline void DocBookOutput::version(CmdLineInterface& _cmd) | |||
| { | |||
| std::cout << _cmd.getVersion() << std::endl; | |||
| } | |||
| inline void DocBookOutput::usage(CmdLineInterface& _cmd) | |||
| { | |||
| std::list<Arg*> argList = _cmd.getArgList(); | |||
| std::string progName = _cmd.getProgramName(); | |||
| std::string xversion = _cmd.getVersion(); | |||
| theDelimiter = _cmd.getDelimiter(); | |||
| XorHandler xorHandler = _cmd.getXorHandler(); | |||
| const std::vector<std::vector<Arg*>> xorList = xorHandler.getXorList(); | |||
| basename(progName); | |||
| std::cout << "<?xml version='1.0'?>" << std::endl; | |||
| std::cout << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"" << std::endl; | |||
| std::cout << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">" << std::endl | |||
| << std::endl; | |||
| std::cout << "<refentry>" << std::endl; | |||
| std::cout << "<refmeta>" << std::endl; | |||
| std::cout << "<refentrytitle>" << progName << "</refentrytitle>" << std::endl; | |||
| std::cout << "<manvolnum>1</manvolnum>" << std::endl; | |||
| std::cout << "</refmeta>" << std::endl; | |||
| std::cout << "<refnamediv>" << std::endl; | |||
| std::cout << "<refname>" << progName << "</refname>" << std::endl; | |||
| std::cout << "<refpurpose>" << _cmd.getMessage() << "</refpurpose>" << std::endl; | |||
| std::cout << "</refnamediv>" << std::endl; | |||
| std::cout << "<refsynopsisdiv>" << std::endl; | |||
| std::cout << "<cmdsynopsis>" << std::endl; | |||
| std::cout << "<command>" << progName << "</command>" << std::endl; | |||
| // xor | |||
| for (int i = 0; (unsigned int)i < xorList.size(); i++) | |||
| { | |||
| std::cout << "<group choice='req'>" << std::endl; | |||
| for (ArgVectorIterator it = xorList[i].begin(); | |||
| it != xorList[i].end(); | |||
| it++) | |||
| printShortArg((*it)); | |||
| std::cout << "</group>" << std::endl; | |||
| } | |||
| // rest of args | |||
| for (ArgListIterator it = argList.begin(); it != argList.end(); it++) | |||
| if (!xorHandler.contains((*it))) | |||
| printShortArg((*it)); | |||
| std::cout << "</cmdsynopsis>" << std::endl; | |||
| std::cout << "</refsynopsisdiv>" << std::endl; | |||
| std::cout << "<refsect1>" << std::endl; | |||
| std::cout << "<title>Description</title>" << std::endl; | |||
| std::cout << "<para>" << std::endl; | |||
| std::cout << _cmd.getMessage() << std::endl; | |||
| std::cout << "</para>" << std::endl; | |||
| std::cout << "</refsect1>" << std::endl; | |||
| std::cout << "<refsect1>" << std::endl; | |||
| std::cout << "<title>Options</title>" << std::endl; | |||
| std::cout << "<variablelist>" << std::endl; | |||
| for (ArgListIterator it = argList.begin(); it != argList.end(); it++) | |||
| printLongArg((*it)); | |||
| std::cout << "</variablelist>" << std::endl; | |||
| std::cout << "</refsect1>" << std::endl; | |||
| std::cout << "<refsect1>" << std::endl; | |||
| std::cout << "<title>Version</title>" << std::endl; | |||
| std::cout << "<para>" << std::endl; | |||
| std::cout << xversion << std::endl; | |||
| std::cout << "</para>" << std::endl; | |||
| std::cout << "</refsect1>" << std::endl; | |||
| std::cout << "</refentry>" << std::endl; | |||
| } | |||
| inline void DocBookOutput::failure(CmdLineInterface& _cmd, ArgException& e) | |||
| { | |||
| static_cast<void>(_cmd); // unused | |||
| std::cout << e.what() << std::endl; | |||
| throw ExitException(1); | |||
| } | |||
| inline void DocBookOutput::substituteSpecialChars(std::string& s, char r, std::string& x) | |||
| { | |||
| size_t p; | |||
| while ((p = s.find_first_of(r)) != std::string::npos) | |||
| { | |||
| s.erase(p, 1); | |||
| s.insert(p, x); | |||
| } | |||
| } | |||
| inline void DocBookOutput::removeChar(std::string& s, char r) | |||
| { | |||
| size_t p; | |||
| while ((p = s.find_first_of(r)) != std::string::npos) | |||
| { | |||
| s.erase(p, 1); | |||
| } | |||
| } | |||
| inline void DocBookOutput::basename(std::string& s) | |||
| { | |||
| size_t p = s.find_last_of('/'); | |||
| if (p != std::string::npos) | |||
| { | |||
| s.erase(0, p + 1); | |||
| } | |||
| } | |||
| inline void DocBookOutput::printShortArg(Arg* a) | |||
| { | |||
| std::string lt = "<"; | |||
| std::string gt = ">"; | |||
| std::string id = a->shortID(); | |||
| substituteSpecialChars(id, '<', lt); | |||
| substituteSpecialChars(id, '>', gt); | |||
| removeChar(id, '['); | |||
| removeChar(id, ']'); | |||
| std::string choice = "opt"; | |||
| if (a->isRequired()) | |||
| choice = "plain"; | |||
| std::cout << "<arg choice='" << choice << '\''; | |||
| if (a->acceptsMultipleValues()) | |||
| std::cout << " rep='repeat'"; | |||
| std::cout << '>'; | |||
| if (!a->getFlag().empty()) | |||
| std::cout << a->flagStartChar() << a->getFlag(); | |||
| else | |||
| std::cout << a->nameStartString() << a->getName(); | |||
| if (a->isValueRequired()) | |||
| { | |||
| std::string arg = a->shortID(); | |||
| removeChar(arg, '['); | |||
| removeChar(arg, ']'); | |||
| removeChar(arg, '<'); | |||
| removeChar(arg, '>'); | |||
| removeChar(arg, '.'); | |||
| arg.erase(0, arg.find_last_of(theDelimiter) + 1); | |||
| std::cout << theDelimiter; | |||
| std::cout << "<replaceable>" << arg << "</replaceable>"; | |||
| } | |||
| std::cout << "</arg>" << std::endl; | |||
| } | |||
| inline void DocBookOutput::printLongArg(Arg* a) | |||
| { | |||
| std::string lt = "<"; | |||
| std::string gt = ">"; | |||
| std::string desc = a->getDescription(); | |||
| substituteSpecialChars(desc, '<', lt); | |||
| substituteSpecialChars(desc, '>', gt); | |||
| std::cout << "<varlistentry>" << std::endl; | |||
| if (!a->getFlag().empty()) | |||
| { | |||
| std::cout << "<term>" << std::endl; | |||
| std::cout << "<option>"; | |||
| std::cout << a->flagStartChar() << a->getFlag(); | |||
| std::cout << "</option>" << std::endl; | |||
| std::cout << "</term>" << std::endl; | |||
| } | |||
| std::cout << "<term>" << std::endl; | |||
| std::cout << "<option>"; | |||
| std::cout << a->nameStartString() << a->getName(); | |||
| if (a->isValueRequired()) | |||
| { | |||
| std::string arg = a->shortID(); | |||
| removeChar(arg, '['); | |||
| removeChar(arg, ']'); | |||
| removeChar(arg, '<'); | |||
| removeChar(arg, '>'); | |||
| removeChar(arg, '.'); | |||
| arg.erase(0, arg.find_last_of(theDelimiter) + 1); | |||
| std::cout << theDelimiter; | |||
| std::cout << "<replaceable>" << arg << "</replaceable>"; | |||
| } | |||
| std::cout << "</option>" << std::endl; | |||
| std::cout << "</term>" << std::endl; | |||
| std::cout << "<listitem>" << std::endl; | |||
| std::cout << "<para>" << std::endl; | |||
| std::cout << desc << std::endl; | |||
| std::cout << "</para>" << std::endl; | |||
| std::cout << "</listitem>" << std::endl; | |||
| std::cout << "</varlistentry>" << std::endl; | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,83 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: HelpVisitor.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_HELP_VISITOR_H | |||
| #define TCLAP_HELP_VISITOR_H | |||
| #include <tclap/CmdLineInterface.h> | |||
| #include <tclap/CmdLineOutput.h> | |||
| #include <tclap/Visitor.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A Visitor object that calls the usage method of the given CmdLineOutput | |||
| * object for the specified CmdLine object. | |||
| */ | |||
| class HelpVisitor : public Visitor | |||
| { | |||
| private: | |||
| /** | |||
| * Prevent accidental copying. | |||
| */ | |||
| HelpVisitor(const HelpVisitor& rhs); | |||
| HelpVisitor& operator=(const HelpVisitor& rhs); | |||
| protected: | |||
| /** | |||
| * The CmdLine the output will be generated for. | |||
| */ | |||
| CmdLineInterface* _cmd; | |||
| /** | |||
| * The output object. | |||
| */ | |||
| CmdLineOutput** _out; | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param cmd - The CmdLine the output will be generated for. | |||
| * \param out - The type of output. | |||
| */ | |||
| HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) : | |||
| Visitor(), | |||
| _cmd(cmd), | |||
| _out(out) | |||
| { | |||
| } | |||
| /** | |||
| * Calls the usage method of the CmdLineOutput for the | |||
| * specified CmdLine. | |||
| */ | |||
| void visit() | |||
| { | |||
| (*_out)->usage(*_cmd); | |||
| throw ExitException(0); | |||
| } | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,58 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: IgnoreRestVisitor.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_IGNORE_REST_VISITOR_H | |||
| #define TCLAP_IGNORE_REST_VISITOR_H | |||
| #include <tclap/Visitor.h> | |||
| #include <tclap/Arg.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A Visitor that tells the CmdLine to begin ignoring arguments after | |||
| * this one is parsed. | |||
| */ | |||
| class IgnoreRestVisitor : public Visitor | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| */ | |||
| IgnoreRestVisitor() : | |||
| Visitor() | |||
| { | |||
| } | |||
| /** | |||
| * Sets Arg::_ignoreRest. | |||
| */ | |||
| void visit() | |||
| { | |||
| Arg::beginIgnoring(); | |||
| } | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,29 @@ | |||
| libtclapincludedir = $(includedir)/tclap | |||
| libtclapinclude_HEADERS = \ | |||
| Arg.h \ | |||
| ArgException.h \ | |||
| ArgTraits.h \ | |||
| CmdLine.h \ | |||
| CmdLineInterface.h \ | |||
| CmdLineOutput.h \ | |||
| Constraint.h \ | |||
| DocBookOutput.h \ | |||
| HelpVisitor.h \ | |||
| IgnoreRestVisitor.h \ | |||
| MultiArg.h \ | |||
| MultiSwitchArg.h \ | |||
| OptionalUnlabeledTracker.h \ | |||
| StandardTraits.h \ | |||
| StdOutput.h \ | |||
| SwitchArg.h \ | |||
| UnlabeledMultiArg.h \ | |||
| UnlabeledValueArg.h \ | |||
| ValueArg.h \ | |||
| ValuesConstraint.h \ | |||
| VersionVisitor.h \ | |||
| Visitor.h \ | |||
| XorHandler.h \ | |||
| ZshCompletionOutput.h \ | |||
| sstream.h | |||
| @@ -0,0 +1,394 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: MultiArg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_MULTIPLE_ARGUMENT_H | |||
| #define TCLAP_MULTIPLE_ARGUMENT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/Arg.h> | |||
| #include <tclap/Constraint.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * An argument that allows multiple values of type T to be specified. Very | |||
| * similar to a ValueArg, except a vector of values will be returned | |||
| * instead of just one. | |||
| */ | |||
| template<class T> | |||
| class MultiArg : public Arg | |||
| { | |||
| public: | |||
| typedef std::vector<T> container_type; | |||
| typedef typename container_type::iterator iterator; | |||
| typedef typename container_type::const_iterator const_iterator; | |||
| protected: | |||
| /** | |||
| * The list of values parsed from the CmdLine. | |||
| */ | |||
| std::vector<T> _values; | |||
| /** | |||
| * The description of type T to be used in the usage. | |||
| */ | |||
| std::string _typeDesc; | |||
| /** | |||
| * A list of constraint on this Arg. | |||
| */ | |||
| Constraint<T>* _constraint; | |||
| /** | |||
| * Extracts the value from the string. | |||
| * Attempts to parse string as type T, if this fails an exception | |||
| * is thrown. | |||
| * \param val - The string to be read. | |||
| */ | |||
| void _extractValue(const std::string& val); | |||
| /** | |||
| * Used by XorHandler to decide whether to keep parsing for this arg. | |||
| */ | |||
| bool _allowMore; | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, Visitor* v = NULL); | |||
| /** | |||
| * Constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, CmdLineInterface& parser, Visitor* v = NULL); | |||
| /** | |||
| * Constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, Visitor* v = NULL); | |||
| /** | |||
| * Constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, CmdLineInterface& parser, Visitor* v = NULL); | |||
| /** | |||
| * Handles the processing of the argument. | |||
| * This re-implements the Arg version of this method to set the | |||
| * _value of the argument appropriately. It knows the difference | |||
| * between labeled and unlabeled. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. Passed from main(). | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args); | |||
| /** | |||
| * Returns a vector of type T containing the values parsed from | |||
| * the command line. | |||
| */ | |||
| const std::vector<T>& getValue() const | |||
| { | |||
| return _values; | |||
| } | |||
| /** | |||
| * Returns an iterator over the values parsed from the command | |||
| * line. | |||
| */ | |||
| const_iterator begin() const | |||
| { | |||
| return _values.begin(); | |||
| } | |||
| /** | |||
| * Returns the end of the values parsed from the command | |||
| * line. | |||
| */ | |||
| const_iterator end() const | |||
| { | |||
| return _values.end(); | |||
| } | |||
| /** | |||
| * Returns the a short id string. Used in the usage. | |||
| * \param val - value to be used. | |||
| */ | |||
| virtual std::string shortID(const std::string& val = "val") const; | |||
| /** | |||
| * Returns the a long id string. Used in the usage. | |||
| * \param val - value to be used. | |||
| */ | |||
| virtual std::string longID(const std::string& val = "val") const; | |||
| /** | |||
| * Once we've matched the first value, then the arg is no longer | |||
| * required. | |||
| */ | |||
| virtual bool isRequired() const; | |||
| virtual bool allowMore(); | |||
| virtual void reset(); | |||
| private: | |||
| /** | |||
| * Prevent accidental copying | |||
| */ | |||
| MultiArg<T>(const MultiArg<T>& rhs); | |||
| MultiArg<T>& operator=(const MultiArg<T>& rhs); | |||
| }; | |||
| template<class T> | |||
| MultiArg<T>::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _values(std::vector<T>()), | |||
| _typeDesc(typeDesc), | |||
| _constraint(NULL), | |||
| _allowMore(false) | |||
| { | |||
| _acceptsMultipleValues = true; | |||
| } | |||
| template<class T> | |||
| MultiArg<T>::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, CmdLineInterface& parser, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _values(std::vector<T>()), | |||
| _typeDesc(typeDesc), | |||
| _constraint(NULL), | |||
| _allowMore(false) | |||
| { | |||
| parser.add(this); | |||
| _acceptsMultipleValues = true; | |||
| } | |||
| /** | |||
| * | |||
| */ | |||
| template<class T> | |||
| MultiArg<T>::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _values(std::vector<T>()), | |||
| _typeDesc(Constraint<T>::shortID(constraint)), | |||
| _constraint(constraint), | |||
| _allowMore(false) | |||
| { | |||
| _acceptsMultipleValues = true; | |||
| } | |||
| template<class T> | |||
| MultiArg<T>::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, CmdLineInterface& parser, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _values(std::vector<T>()), | |||
| _typeDesc(Constraint<T>::shortID(constraint)), | |||
| _constraint(constraint), | |||
| _allowMore(false) | |||
| { | |||
| parser.add(this); | |||
| _acceptsMultipleValues = true; | |||
| } | |||
| template<class T> | |||
| bool MultiArg<T>::processArg(int* i, std::vector<std::string>& args) | |||
| { | |||
| if (_ignoreable && Arg::ignoreRest()) | |||
| return false; | |||
| if (_hasBlanks(args[*i])) | |||
| return false; | |||
| std::string flag = args[*i]; | |||
| std::string value = ""; | |||
| trimFlag(flag, value); | |||
| if (argMatches(flag)) | |||
| { | |||
| if (Arg::delimiter() != ' ' && value == "") | |||
| throw(ArgParseException( | |||
| "Couldn't find delimiter for this argument!", | |||
| toString() | |||
| )); | |||
| // always take the first one, regardless of start string | |||
| if (value == "") | |||
| { | |||
| (*i)++; | |||
| if (static_cast<unsigned int>(*i) < args.size()) | |||
| _extractValue(args[*i]); | |||
| else | |||
| throw(ArgParseException("Missing a value for this argument!", toString())); | |||
| } | |||
| else | |||
| _extractValue(value); | |||
| /* | |||
| // continuing taking the args until we hit one with a start string | |||
| while ( (unsigned int)(*i)+1 < args.size() && | |||
| args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && | |||
| args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) | |||
| _extractValue( args[++(*i)] ); | |||
| */ | |||
| _alreadySet = true; | |||
| _checkWithVisitor(); | |||
| return true; | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| /** | |||
| * | |||
| */ | |||
| template<class T> | |||
| std::string MultiArg<T>::shortID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return Arg::shortID(_typeDesc) + " ..."; | |||
| } | |||
| /** | |||
| * | |||
| */ | |||
| template<class T> | |||
| std::string MultiArg<T>::longID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return Arg::longID(_typeDesc) + " (accepted multiple times)"; | |||
| } | |||
| /** | |||
| * Once we've matched the first value, then the arg is no longer | |||
| * required. | |||
| */ | |||
| template<class T> | |||
| bool MultiArg<T>::isRequired() const | |||
| { | |||
| if (_required) | |||
| { | |||
| if (_values.size() > 1) | |||
| return false; | |||
| else | |||
| return true; | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| template<class T> | |||
| void MultiArg<T>::_extractValue(const std::string& val) | |||
| { | |||
| try | |||
| { | |||
| T tmp; | |||
| ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory()); | |||
| _values.push_back(tmp); | |||
| } | |||
| catch (ArgParseException& e) | |||
| { | |||
| throw ArgParseException(e.error(), toString()); | |||
| } | |||
| if (_constraint != NULL) | |||
| if (!_constraint->check(_values.back())) | |||
| throw(CmdLineParseException("Value '" + val + "' does not meet constraint: " + _constraint->description(), toString())); | |||
| } | |||
| template<class T> | |||
| bool MultiArg<T>::allowMore() | |||
| { | |||
| bool am = _allowMore; | |||
| _allowMore = true; | |||
| return am; | |||
| } | |||
| template<class T> | |||
| void MultiArg<T>::reset() | |||
| { | |||
| Arg::reset(); | |||
| _values.clear(); | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,197 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: MultiSwitchArg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_MULTI_SWITCH_ARG_H | |||
| #define TCLAP_MULTI_SWITCH_ARG_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/SwitchArg.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A multiple switch argument. If the switch is set on the command line, then | |||
| * the getValue method will return the number of times the switch appears. | |||
| */ | |||
| class MultiSwitchArg : public SwitchArg | |||
| { | |||
| protected: | |||
| /** | |||
| * The value of the switch. | |||
| */ | |||
| int _value; | |||
| /** | |||
| * Used to support the reset() method so that ValueArg can be | |||
| * reset to their constructed value. | |||
| */ | |||
| int _default; | |||
| public: | |||
| /** | |||
| * MultiSwitchArg constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param init - Optional. The initial/default value of this Arg. | |||
| * Defaults to 0. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| MultiSwitchArg(const std::string& flag, const std::string& name, const std::string& desc, int init = 0, Visitor* v = NULL); | |||
| /** | |||
| * MultiSwitchArg constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param init - Optional. The initial/default value of this Arg. | |||
| * Defaults to 0. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| MultiSwitchArg(const std::string& flag, const std::string& name, const std::string& desc, CmdLineInterface& parser, int init = 0, Visitor* v = NULL); | |||
| /** | |||
| * Handles the processing of the argument. | |||
| * This re-implements the SwitchArg version of this method to set the | |||
| * _value of the argument appropriately. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. Passed | |||
| * in from main(). | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args); | |||
| /** | |||
| * Returns int, the number of times the switch has been set. | |||
| */ | |||
| int getValue() const | |||
| { | |||
| return _value; | |||
| } | |||
| /** | |||
| * Returns the shortID for this Arg. | |||
| */ | |||
| std::string shortID(const std::string& val) const; | |||
| /** | |||
| * Returns the longID for this Arg. | |||
| */ | |||
| std::string longID(const std::string& val) const; | |||
| void reset(); | |||
| }; | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // BEGIN MultiSwitchArg.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, const std::string& name, const std::string& desc, int init, Visitor* v) : | |||
| SwitchArg(flag, name, desc, false, v), | |||
| _value(init), | |||
| _default(init) | |||
| { | |||
| } | |||
| inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, const std::string& name, const std::string& desc, CmdLineInterface& parser, int init, Visitor* v) : | |||
| SwitchArg(flag, name, desc, false, v), | |||
| _value(init), | |||
| _default(init) | |||
| { | |||
| parser.add(this); | |||
| } | |||
| inline bool MultiSwitchArg::processArg(int* i, std::vector<std::string>& args) | |||
| { | |||
| if (_ignoreable && Arg::ignoreRest()) | |||
| return false; | |||
| if (argMatches(args[*i])) | |||
| { | |||
| // so the isSet() method will work | |||
| _alreadySet = true; | |||
| // Matched argument: increment value. | |||
| ++_value; | |||
| _checkWithVisitor(); | |||
| return true; | |||
| } | |||
| else if (combinedSwitchesMatch(args[*i])) | |||
| { | |||
| // so the isSet() method will work | |||
| _alreadySet = true; | |||
| // Matched argument: increment value. | |||
| ++_value; | |||
| // Check for more in argument and increment value. | |||
| while (combinedSwitchesMatch(args[*i])) | |||
| ++_value; | |||
| _checkWithVisitor(); | |||
| return false; | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| inline std::string | |||
| MultiSwitchArg::shortID(const std::string& val) const | |||
| { | |||
| return Arg::shortID(val) + " ..."; | |||
| } | |||
| inline std::string | |||
| MultiSwitchArg::longID(const std::string& val) const | |||
| { | |||
| return Arg::longID(val) + " (accepted multiple times)"; | |||
| } | |||
| inline void | |||
| MultiSwitchArg::reset() | |||
| { | |||
| MultiSwitchArg::_value = MultiSwitchArg::_default; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // END MultiSwitchArg.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,68 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: OptionalUnlabeledTracker.h | |||
| * | |||
| * Copyright (c) 2005, Michael E. Smoot . | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H | |||
| #define TCLAP_OPTIONAL_UNLABELED_TRACKER_H | |||
| #include <string> | |||
| namespace TCLAP | |||
| { | |||
| class OptionalUnlabeledTracker | |||
| { | |||
| public: | |||
| static void check(bool req, const std::string& argName); | |||
| static void gotOptional() | |||
| { | |||
| alreadyOptionalRef() = true; | |||
| } | |||
| static bool& alreadyOptional() | |||
| { | |||
| return alreadyOptionalRef(); | |||
| } | |||
| private: | |||
| static bool& alreadyOptionalRef() | |||
| { | |||
| static bool ct = false; | |||
| return ct; | |||
| } | |||
| }; | |||
| inline void OptionalUnlabeledTracker::check(bool req, const std::string& argName) | |||
| { | |||
| if (OptionalUnlabeledTracker::alreadyOptional()) | |||
| throw(SpecificationException( | |||
| "You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg", | |||
| argName | |||
| )); | |||
| if (!req) | |||
| OptionalUnlabeledTracker::gotOptional(); | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,64 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: StandardTraits.h | |||
| * | |||
| * Copyright (c) 2007, Daniel Aarno, Michael E. Smoot . | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| // This is an internal tclap file, you should probably not have to | |||
| // include this directly | |||
| #ifndef TCLAP_STANDARD_TRAITS_H | |||
| #define TCLAP_STANDARD_TRAITS_H | |||
| #ifdef HAVE_CONFIG_H | |||
| #include <config.h> // To check for long long | |||
| #endif | |||
| // If Microsoft has already typedef'd wchar_t as an unsigned | |||
| // short, then compiles will break because it's as if we're | |||
| // creating ArgTraits twice for unsigned short. Thus... | |||
| #ifdef _MSC_VER | |||
| #ifndef _NATIVE_WCHAR_T_DEFINED | |||
| #define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS | |||
| #endif | |||
| #endif | |||
| namespace TCLAP | |||
| { | |||
| // Integer types (signed, unsigned and bool) and floating point types all | |||
| // have value-like semantics. | |||
| // Strings have string like argument traits. | |||
| template<> | |||
| struct ArgTraits<std::string> | |||
| { | |||
| typedef StringLike ValueCategory; | |||
| }; | |||
| template<typename T> | |||
| void SetString(T& dst, const std::string& src) | |||
| { | |||
| dst = src; | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,296 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: StdOutput.h | |||
| * | |||
| * Copyright (c) 2004, Michael E. Smoot | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_STDCMDLINEOUTPUT_H | |||
| #define TCLAP_STDCMDLINEOUTPUT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <algorithm> | |||
| #include <tclap/CmdLineInterface.h> | |||
| #include <tclap/CmdLineOutput.h> | |||
| #include <tclap/XorHandler.h> | |||
| #include <tclap/Arg.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A class that isolates any output from the CmdLine object so that it | |||
| * may be easily modified. | |||
| */ | |||
| class StdOutput : public CmdLineOutput | |||
| { | |||
| public: | |||
| /** | |||
| * Prints the usage to stdout. Can be overridden to | |||
| * produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void usage(CmdLineInterface& c); | |||
| /** | |||
| * Prints the version to stdout. Can be overridden | |||
| * to produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void version(CmdLineInterface& c); | |||
| /** | |||
| * Prints (to stderr) an error message, short usage | |||
| * Can be overridden to produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| * \param e - The ArgException that caused the failure. | |||
| */ | |||
| virtual void failure(CmdLineInterface& c, ArgException& e); | |||
| protected: | |||
| /** | |||
| * Writes a brief usage message with short args. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| * \param os - The stream to write the message to. | |||
| */ | |||
| void _shortUsage(CmdLineInterface& c, std::ostream& os) const; | |||
| /** | |||
| * Writes a longer usage message with long and short args, | |||
| * provides descriptions and prints message. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| * \param os - The stream to write the message to. | |||
| */ | |||
| void _longUsage(CmdLineInterface& c, std::ostream& os) const; | |||
| /** | |||
| * This function inserts line breaks and indents long strings | |||
| * according the params input. It will only break lines at spaces, | |||
| * commas and pipes. | |||
| * \param os - The stream to be printed to. | |||
| * \param s - The string to be printed. | |||
| * \param maxWidth - The maxWidth allowed for the output line. | |||
| * \param indentSpaces - The number of spaces to indent the first line. | |||
| * \param secondLineOffset - The number of spaces to indent the second | |||
| * and all subsequent lines in addition to indentSpaces. | |||
| */ | |||
| void spacePrint(std::ostream& os, const std::string& s, int maxWidth, int indentSpaces, int secondLineOffset) const; | |||
| }; | |||
| inline void StdOutput::version(CmdLineInterface& _cmd) | |||
| { | |||
| std::string progName = _cmd.getProgramName(); | |||
| std::string xversion = _cmd.getVersion(); | |||
| std::cout << std::endl | |||
| << progName << " version: " | |||
| << xversion << std::endl | |||
| << std::endl; | |||
| } | |||
| inline void StdOutput::usage(CmdLineInterface& _cmd) | |||
| { | |||
| std::cout << std::endl | |||
| << "USAGE: " << std::endl | |||
| << std::endl; | |||
| _shortUsage(_cmd, std::cout); | |||
| std::cout << std::endl | |||
| << std::endl | |||
| << "Where: " << std::endl | |||
| << std::endl; | |||
| _longUsage(_cmd, std::cout); | |||
| std::cout << std::endl; | |||
| } | |||
| inline void StdOutput::failure(CmdLineInterface& _cmd, ArgException& e) | |||
| { | |||
| std::string progName = _cmd.getProgramName(); | |||
| std::cerr << "PARSE ERROR: " << e.argId() << std::endl | |||
| << " " << e.error() << std::endl | |||
| << std::endl; | |||
| if (_cmd.hasHelpAndVersion()) | |||
| { | |||
| std::cerr << "Brief USAGE: " << std::endl; | |||
| _shortUsage(_cmd, std::cerr); | |||
| std::cerr << std::endl | |||
| << "For complete USAGE and HELP type: " | |||
| << std::endl | |||
| << " " << progName << " " | |||
| << Arg::nameStartString() << "help" | |||
| << std::endl | |||
| << std::endl; | |||
| } | |||
| else | |||
| usage(_cmd); | |||
| throw ExitException(1); | |||
| } | |||
| inline void | |||
| StdOutput::_shortUsage(CmdLineInterface& _cmd, std::ostream& os) const | |||
| { | |||
| std::list<Arg*> argList = _cmd.getArgList(); | |||
| std::string progName = _cmd.getProgramName(); | |||
| XorHandler xorHandler = _cmd.getXorHandler(); | |||
| std::vector<std::vector<Arg*>> xorList = xorHandler.getXorList(); | |||
| std::string s = progName + " "; | |||
| // first the xor | |||
| for (int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++) | |||
| { | |||
| s += " {"; | |||
| for (ArgVectorIterator it = xorList[i].begin(); | |||
| it != xorList[i].end(); | |||
| it++) | |||
| s += (*it)->shortID() + "|"; | |||
| s[s.length() - 1] = '}'; | |||
| } | |||
| // then the rest | |||
| for (ArgListIterator it = argList.begin(); it != argList.end(); it++) | |||
| if (!xorHandler.contains((*it))) | |||
| s += " " + (*it)->shortID(); | |||
| // if the program name is too long, then adjust the second line offset | |||
| int secondLineOffset = static_cast<int>(progName.length()) + 2; | |||
| if (secondLineOffset > 75 / 2) | |||
| secondLineOffset = static_cast<int>(75 / 2); | |||
| spacePrint(os, s, 75, 3, secondLineOffset); | |||
| } | |||
| inline void | |||
| StdOutput::_longUsage(CmdLineInterface& _cmd, std::ostream& os) const | |||
| { | |||
| std::list<Arg*> argList = _cmd.getArgList(); | |||
| std::string message = _cmd.getMessage(); | |||
| XorHandler xorHandler = _cmd.getXorHandler(); | |||
| std::vector<std::vector<Arg*>> xorList = xorHandler.getXorList(); | |||
| // first the xor | |||
| for (int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++) | |||
| { | |||
| for (ArgVectorIterator it = xorList[i].begin(); | |||
| it != xorList[i].end(); | |||
| it++) | |||
| { | |||
| spacePrint(os, (*it)->longID(), 75, 3, 3); | |||
| spacePrint(os, (*it)->getDescription(), 75, 5, 0); | |||
| if (it + 1 != xorList[i].end()) | |||
| spacePrint(os, "-- OR --", 75, 9, 0); | |||
| } | |||
| os << std::endl | |||
| << std::endl; | |||
| } | |||
| // then the rest | |||
| for (ArgListIterator it = argList.begin(); it != argList.end(); it++) | |||
| if (!xorHandler.contains((*it))) | |||
| { | |||
| spacePrint(os, (*it)->longID(), 75, 3, 3); | |||
| spacePrint(os, (*it)->getDescription(), 75, 5, 0); | |||
| os << std::endl; | |||
| } | |||
| os << std::endl; | |||
| spacePrint(os, message, 75, 3, 0); | |||
| } | |||
| inline void StdOutput::spacePrint(std::ostream& os, const std::string& s, int maxWidth, int indentSpaces, int secondLineOffset) const | |||
| { | |||
| int len = static_cast<int>(s.length()); | |||
| if ((len + indentSpaces > maxWidth) && maxWidth > 0) | |||
| { | |||
| int allowedLen = maxWidth - indentSpaces; | |||
| int start = 0; | |||
| while (start < len) | |||
| { | |||
| // find the substring length | |||
| // int stringLen = std::min<int>( len - start, allowedLen ); | |||
| // doing it this way to support a VisualC++ 2005 bug | |||
| using namespace std; | |||
| int stringLen = min<int>(len - start, allowedLen); | |||
| // trim the length so it doesn't end in middle of a word | |||
| if (stringLen == allowedLen) | |||
| while (stringLen >= 0 && | |||
| s[stringLen + start] != ' ' && | |||
| s[stringLen + start] != ',' && | |||
| s[stringLen + start] != '|') | |||
| stringLen--; | |||
| // ok, the word is longer than the line, so just split | |||
| // wherever the line ends | |||
| if (stringLen <= 0) | |||
| stringLen = allowedLen; | |||
| // check for newlines | |||
| for (int i = 0; i < stringLen; i++) | |||
| if (s[start + i] == '\n') | |||
| stringLen = i + 1; | |||
| // print the indent | |||
| for (int i = 0; i < indentSpaces; i++) | |||
| os << " "; | |||
| if (start == 0) | |||
| { | |||
| // handle second line offsets | |||
| indentSpaces += secondLineOffset; | |||
| // adjust allowed len | |||
| allowedLen -= secondLineOffset; | |||
| } | |||
| os << s.substr(start, stringLen) << std::endl; | |||
| // so we don't start a line with a space | |||
| while (s[stringLen + start] == ' ' && start < len) | |||
| start++; | |||
| start += stringLen; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| for (int i = 0; i < indentSpaces; i++) | |||
| os << " "; | |||
| os << s << std::endl; | |||
| } | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,258 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: SwitchArg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_SWITCH_ARG_H | |||
| #define TCLAP_SWITCH_ARG_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/Arg.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A simple switch argument. If the switch is set on the command line, then | |||
| * the getValue method will return the opposite of the default value for the | |||
| * switch. | |||
| */ | |||
| class SwitchArg : public Arg | |||
| { | |||
| protected: | |||
| /** | |||
| * The value of the switch. | |||
| */ | |||
| bool _value; | |||
| /** | |||
| * Used to support the reset() method so that ValueArg can be | |||
| * reset to their constructed value. | |||
| */ | |||
| bool _default; | |||
| public: | |||
| /** | |||
| * SwitchArg constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param def - The default value for this Switch. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| SwitchArg(const std::string& flag, const std::string& name, const std::string& desc, bool def = false, Visitor* v = NULL); | |||
| /** | |||
| * SwitchArg constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param def - The default value for this Switch. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| SwitchArg(const std::string& flag, const std::string& name, const std::string& desc, CmdLineInterface& parser, bool def = false, Visitor* v = NULL); | |||
| /** | |||
| * Handles the processing of the argument. | |||
| * This re-implements the Arg version of this method to set the | |||
| * _value of the argument appropriately. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. Passed | |||
| * in from main(). | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args); | |||
| /** | |||
| * Checks a string to see if any of the chars in the string | |||
| * match the flag for this Switch. | |||
| */ | |||
| bool combinedSwitchesMatch(std::string& combined); | |||
| /** | |||
| * Returns bool, whether or not the switch has been set. | |||
| */ | |||
| bool getValue() const | |||
| { | |||
| return _value; | |||
| } | |||
| /** | |||
| * A SwitchArg can be used as a boolean, indicating | |||
| * whether or not the switch has been set. This is the | |||
| * same as calling getValue() | |||
| */ | |||
| operator bool() const | |||
| { | |||
| return _value; | |||
| } | |||
| virtual void reset(); | |||
| private: | |||
| /** | |||
| * Checks to see if we've found the last match in | |||
| * a combined string. | |||
| */ | |||
| bool lastCombined(std::string& combined); | |||
| /** | |||
| * Does the common processing of processArg. | |||
| */ | |||
| void commonProcessing(); | |||
| }; | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // BEGIN SwitchArg.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| inline SwitchArg::SwitchArg(const std::string& flag, const std::string& name, const std::string& desc, bool default_val, Visitor* v) : | |||
| Arg(flag, name, desc, false, false, v), | |||
| _value(default_val), | |||
| _default(default_val) | |||
| { | |||
| } | |||
| inline SwitchArg::SwitchArg(const std::string& flag, const std::string& name, const std::string& desc, CmdLineInterface& parser, bool default_val, Visitor* v) : | |||
| Arg(flag, name, desc, false, false, v), | |||
| _value(default_val), | |||
| _default(default_val) | |||
| { | |||
| parser.add(this); | |||
| } | |||
| inline bool SwitchArg::lastCombined(std::string& combinedSwitches) | |||
| { | |||
| for (unsigned int i = 1; i < combinedSwitches.length(); i++) | |||
| if (combinedSwitches[i] != Arg::blankChar()) | |||
| return false; | |||
| return true; | |||
| } | |||
| inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches) | |||
| { | |||
| // make sure this is actually a combined switch | |||
| if (combinedSwitches.length() > 0 && | |||
| combinedSwitches[0] != Arg::flagStartString()[0]) | |||
| return false; | |||
| // make sure it isn't a long name | |||
| if (combinedSwitches.substr(0, Arg::nameStartString().length()) == | |||
| Arg::nameStartString()) | |||
| return false; | |||
| // make sure the delimiter isn't in the string | |||
| if (combinedSwitches.find_first_of(Arg::delimiter()) != std::string::npos) | |||
| return false; | |||
| // ok, we're not specifying a ValueArg, so we know that we have | |||
| // a combined switch list. | |||
| for (unsigned int i = 1; i < combinedSwitches.length(); i++) | |||
| if (_flag.length() > 0 && | |||
| combinedSwitches[i] == _flag[0] && | |||
| _flag[0] != Arg::flagStartString()[0]) | |||
| { | |||
| // update the combined switches so this one is no longer present | |||
| // this is necessary so that no unlabeled args are matched | |||
| // later in the processing. | |||
| // combinedSwitches.erase(i,1); | |||
| combinedSwitches[i] = Arg::blankChar(); | |||
| return true; | |||
| } | |||
| // none of the switches passed in the list match. | |||
| return false; | |||
| } | |||
| inline void SwitchArg::commonProcessing() | |||
| { | |||
| if (_xorSet) | |||
| throw(CmdLineParseException( | |||
| "Mutually exclusive argument already set!", toString() | |||
| )); | |||
| if (_alreadySet) | |||
| throw(CmdLineParseException("Argument already set!", toString())); | |||
| _alreadySet = true; | |||
| if (_value == true) | |||
| _value = false; | |||
| else | |||
| _value = true; | |||
| _checkWithVisitor(); | |||
| } | |||
| inline bool SwitchArg::processArg(int* i, std::vector<std::string>& args) | |||
| { | |||
| if (_ignoreable && Arg::ignoreRest()) | |||
| return false; | |||
| // if the whole string matches the flag or name string | |||
| if (argMatches(args[*i])) | |||
| { | |||
| commonProcessing(); | |||
| return true; | |||
| } | |||
| // if a substring matches the flag as part of a combination | |||
| else if (combinedSwitchesMatch(args[*i])) | |||
| { | |||
| // check again to ensure we don't misinterpret | |||
| // this as a MultiSwitchArg | |||
| if (combinedSwitchesMatch(args[*i])) | |||
| throw(CmdLineParseException("Argument already set!", toString())); | |||
| commonProcessing(); | |||
| // We only want to return true if we've found the last combined | |||
| // match in the string, otherwise we return true so that other | |||
| // switches in the combination will have a chance to match. | |||
| return lastCombined(args[*i]); | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| inline void SwitchArg::reset() | |||
| { | |||
| Arg::reset(); | |||
| _value = _default; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // End SwitchArg.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,253 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: UnlabeledMultiArg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H | |||
| #define TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/MultiArg.h> | |||
| #include <tclap/OptionalUnlabeledTracker.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * Just like a MultiArg, except that the arguments are unlabeled. Basically, | |||
| * this Arg will slurp up everything that hasn't been matched to another | |||
| * Arg. | |||
| */ | |||
| template<class T> | |||
| class UnlabeledMultiArg : public MultiArg<T> | |||
| { | |||
| // If compiler has two stage name lookup (as gcc >= 3.4 does) | |||
| // this is required to prevent undef. symbols | |||
| using MultiArg<T>::_ignoreable; | |||
| using MultiArg<T>::_hasBlanks; | |||
| using MultiArg<T>::_extractValue; | |||
| using MultiArg<T>::_typeDesc; | |||
| using MultiArg<T>::_name; | |||
| using MultiArg<T>::_description; | |||
| using MultiArg<T>::_alreadySet; | |||
| using MultiArg<T>::toString; | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param name - The name of the Arg. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param ignoreable - Whether or not this argument can be ignored | |||
| * using the "--" flag. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * Constructor. | |||
| * \param name - The name of the Arg. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param ignoreable - Whether or not this argument can be ignored | |||
| * using the "--" flag. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, CmdLineInterface& parser, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * Constructor. | |||
| * \param name - The name of the Arg. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param ignoreable - Whether or not this argument can be ignored | |||
| * using the "--" flag. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * Constructor. | |||
| * \param name - The name of the Arg. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param ignoreable - Whether or not this argument can be ignored | |||
| * using the "--" flag. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, CmdLineInterface& parser, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * Handles the processing of the argument. | |||
| * This re-implements the Arg version of this method to set the | |||
| * _value of the argument appropriately. It knows the difference | |||
| * between labeled and unlabeled. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. Passed from main(). | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args); | |||
| /** | |||
| * Returns the a short id string. Used in the usage. | |||
| * \param val - value to be used. | |||
| */ | |||
| virtual std::string shortID(const std::string& val = "val") const; | |||
| /** | |||
| * Returns the a long id string. Used in the usage. | |||
| * \param val - value to be used. | |||
| */ | |||
| virtual std::string longID(const std::string& val = "val") const; | |||
| /** | |||
| * Operator ==. | |||
| * \param a - The Arg to be compared to this. | |||
| */ | |||
| virtual bool operator==(const Arg& a) const; | |||
| /** | |||
| * Pushes this to back of list rather than front. | |||
| * \param argList - The list this should be added to. | |||
| */ | |||
| virtual void addToList(std::list<Arg*>& argList) const; | |||
| }; | |||
| template<class T> | |||
| UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, bool ignoreable, Visitor* v) : | |||
| MultiArg<T>("", name, desc, req, typeDesc, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(true, toString()); | |||
| } | |||
| template<class T> | |||
| UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, const std::string& typeDesc, CmdLineInterface& parser, bool ignoreable, Visitor* v) : | |||
| MultiArg<T>("", name, desc, req, typeDesc, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(true, toString()); | |||
| parser.add(this); | |||
| } | |||
| template<class T> | |||
| UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, bool ignoreable, Visitor* v) : | |||
| MultiArg<T>("", name, desc, req, constraint, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(true, toString()); | |||
| } | |||
| template<class T> | |||
| UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, const std::string& desc, bool req, Constraint<T>* constraint, CmdLineInterface& parser, bool ignoreable, Visitor* v) : | |||
| MultiArg<T>("", name, desc, req, constraint, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(true, toString()); | |||
| parser.add(this); | |||
| } | |||
| template<class T> | |||
| bool UnlabeledMultiArg<T>::processArg(int* i, std::vector<std::string>& args) | |||
| { | |||
| if (_hasBlanks(args[*i])) | |||
| return false; | |||
| // never ignore an unlabeled multi arg | |||
| // always take the first value, regardless of the start string | |||
| _extractValue(args[(*i)]); | |||
| /* | |||
| // continue taking args until we hit the end or a start string | |||
| while ( (unsigned int)(*i)+1 < args.size() && | |||
| args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 && | |||
| args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) | |||
| _extractValue( args[++(*i)] ); | |||
| */ | |||
| _alreadySet = true; | |||
| return true; | |||
| } | |||
| template<class T> | |||
| std::string UnlabeledMultiArg<T>::shortID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return std::string("<") + _typeDesc + "> ..."; | |||
| } | |||
| template<class T> | |||
| std::string UnlabeledMultiArg<T>::longID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return std::string("<") + _typeDesc + "> (accepted multiple times)"; | |||
| } | |||
| template<class T> | |||
| bool UnlabeledMultiArg<T>::operator==(const Arg& a) const | |||
| { | |||
| if (_name == a.getName() || _description == a.getDescription()) | |||
| return true; | |||
| else | |||
| return false; | |||
| } | |||
| template<class T> | |||
| void UnlabeledMultiArg<T>::addToList(std::list<Arg*>& argList) const | |||
| { | |||
| argList.push_back(const_cast<Arg*>(static_cast<const Arg* const>(this))); | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,283 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: UnlabeledValueArg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H | |||
| #define TCLAP_UNLABELED_VALUE_ARGUMENT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/ValueArg.h> | |||
| #include <tclap/OptionalUnlabeledTracker.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * The basic unlabeled argument that parses a value. | |||
| * This is a template class, which means the type T defines the type | |||
| * that a given object will attempt to parse when an UnlabeledValueArg | |||
| * is reached in the list of args that the CmdLine iterates over. | |||
| */ | |||
| template<class T> | |||
| class UnlabeledValueArg : public ValueArg<T> | |||
| { | |||
| // If compiler has two stage name lookup (as gcc >= 3.4 does) | |||
| // this is required to prevent undef. symbols | |||
| using ValueArg<T>::_ignoreable; | |||
| using ValueArg<T>::_hasBlanks; | |||
| using ValueArg<T>::_extractValue; | |||
| using ValueArg<T>::_typeDesc; | |||
| using ValueArg<T>::_name; | |||
| using ValueArg<T>::_description; | |||
| using ValueArg<T>::_alreadySet; | |||
| using ValueArg<T>::toString; | |||
| public: | |||
| /** | |||
| * UnlabeledValueArg constructor. | |||
| * \param name - A one word name for the argument. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param ignoreable - Allows you to specify that this argument can be | |||
| * ignored if the '--' flag is set. This defaults to false (cannot | |||
| * be ignored) and should generally stay that way unless you have | |||
| * some special need for certain arguments to be ignored. | |||
| * \param v - Optional Visitor. You should leave this blank unless | |||
| * you have a very good reason. | |||
| */ | |||
| UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T value, const std::string& typeDesc, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * UnlabeledValueArg constructor. | |||
| * \param name - A one word name for the argument. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param ignoreable - Allows you to specify that this argument can be | |||
| * ignored if the '--' flag is set. This defaults to false (cannot | |||
| * be ignored) and should generally stay that way unless you have | |||
| * some special need for certain arguments to be ignored. | |||
| * \param v - Optional Visitor. You should leave this blank unless | |||
| * you have a very good reason. | |||
| */ | |||
| UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T value, const std::string& typeDesc, CmdLineInterface& parser, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * UnlabeledValueArg constructor. | |||
| * \param name - A one word name for the argument. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param ignoreable - Allows you to specify that this argument can be | |||
| * ignored if the '--' flag is set. This defaults to false (cannot | |||
| * be ignored) and should generally stay that way unless you have | |||
| * some special need for certain arguments to be ignored. | |||
| * \param v - Optional Visitor. You should leave this blank unless | |||
| * you have a very good reason. | |||
| */ | |||
| UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T value, Constraint<T>* constraint, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * UnlabeledValueArg constructor. | |||
| * \param name - A one word name for the argument. Note that this is used for | |||
| * identification, not as a long flag. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param ignoreable - Allows you to specify that this argument can be | |||
| * ignored if the '--' flag is set. This defaults to false (cannot | |||
| * be ignored) and should generally stay that way unless you have | |||
| * some special need for certain arguments to be ignored. | |||
| * \param v - Optional Visitor. You should leave this blank unless | |||
| * you have a very good reason. | |||
| */ | |||
| UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T value, Constraint<T>* constraint, CmdLineInterface& parser, bool ignoreable = false, Visitor* v = NULL); | |||
| /** | |||
| * Handles the processing of the argument. | |||
| * This re-implements the Arg version of this method to set the | |||
| * _value of the argument appropriately. Handling specific to | |||
| * unlabeled arguments. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args); | |||
| /** | |||
| * Overrides shortID for specific behavior. | |||
| */ | |||
| virtual std::string shortID(const std::string& val = "val") const; | |||
| /** | |||
| * Overrides longID for specific behavior. | |||
| */ | |||
| virtual std::string longID(const std::string& val = "val") const; | |||
| /** | |||
| * Overrides operator== for specific behavior. | |||
| */ | |||
| virtual bool operator==(const Arg& a) const; | |||
| /** | |||
| * Instead of pushing to the front of list, push to the back. | |||
| * \param argList - The list to add this to. | |||
| */ | |||
| virtual void addToList(std::list<Arg*>& argList) const; | |||
| }; | |||
| /** | |||
| * Constructor implementation. | |||
| */ | |||
| template<class T> | |||
| UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T val, const std::string& typeDesc, bool ignoreable, Visitor* v) : | |||
| ValueArg<T>("", name, desc, req, val, typeDesc, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(req, toString()); | |||
| } | |||
| template<class T> | |||
| UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T val, const std::string& typeDesc, CmdLineInterface& parser, bool ignoreable, Visitor* v) : | |||
| ValueArg<T>("", name, desc, req, val, typeDesc, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(req, toString()); | |||
| parser.add(this); | |||
| } | |||
| /** | |||
| * Constructor implementation. | |||
| */ | |||
| template<class T> | |||
| UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T val, Constraint<T>* constraint, bool ignoreable, Visitor* v) : | |||
| ValueArg<T>("", name, desc, req, val, constraint, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(req, toString()); | |||
| } | |||
| template<class T> | |||
| UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, const std::string& desc, bool req, T val, Constraint<T>* constraint, CmdLineInterface& parser, bool ignoreable, Visitor* v) : | |||
| ValueArg<T>("", name, desc, req, val, constraint, v) | |||
| { | |||
| _ignoreable = ignoreable; | |||
| OptionalUnlabeledTracker::check(req, toString()); | |||
| parser.add(this); | |||
| } | |||
| /** | |||
| * Implementation of processArg(). | |||
| */ | |||
| template<class T> | |||
| bool UnlabeledValueArg<T>::processArg(int* i, std::vector<std::string>& args) | |||
| { | |||
| if (_alreadySet) | |||
| return false; | |||
| if (_hasBlanks(args[*i])) | |||
| return false; | |||
| // never ignore an unlabeled arg | |||
| _extractValue(args[*i]); | |||
| _alreadySet = true; | |||
| return true; | |||
| } | |||
| /** | |||
| * Overriding shortID for specific output. | |||
| */ | |||
| template<class T> | |||
| std::string UnlabeledValueArg<T>::shortID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return std::string("<") + _typeDesc + ">"; | |||
| } | |||
| /** | |||
| * Overriding longID for specific output. | |||
| */ | |||
| template<class T> | |||
| std::string UnlabeledValueArg<T>::longID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| // Ideally we would like to be able to use RTTI to return the name | |||
| // of the type required for this argument. However, g++ at least, | |||
| // doesn't appear to return terribly useful "names" of the types. | |||
| return std::string("<") + _typeDesc + ">"; | |||
| } | |||
| /** | |||
| * Overriding operator== for specific behavior. | |||
| */ | |||
| template<class T> | |||
| bool UnlabeledValueArg<T>::operator==(const Arg& a) const | |||
| { | |||
| if (_name == a.getName() || _description == a.getDescription()) | |||
| return true; | |||
| else | |||
| return false; | |||
| } | |||
| template<class T> | |||
| void UnlabeledValueArg<T>::addToList(std::list<Arg*>& argList) const | |||
| { | |||
| argList.push_back(const_cast<Arg*>(static_cast<const Arg* const>(this))); | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,383 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: ValueArg.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_VALUE_ARGUMENT_H | |||
| #define TCLAP_VALUE_ARGUMENT_H | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/Arg.h> | |||
| #include <tclap/Constraint.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * The basic labeled argument that parses a value. | |||
| * This is a template class, which means the type T defines the type | |||
| * that a given object will attempt to parse when the flag/name is matched | |||
| * on the command line. While there is nothing stopping you from creating | |||
| * an unflagged ValueArg, it is unwise and would cause significant problems. | |||
| * Instead use an UnlabeledValueArg. | |||
| */ | |||
| template<class T> | |||
| class ValueArg : public Arg | |||
| { | |||
| protected: | |||
| /** | |||
| * The value parsed from the command line. | |||
| * Can be of any type, as long as the >> operator for the type | |||
| * is defined. | |||
| */ | |||
| T _value; | |||
| /** | |||
| * Used to support the reset() method so that ValueArg can be | |||
| * reset to their constructed value. | |||
| */ | |||
| T _default; | |||
| /** | |||
| * A human readable description of the type to be parsed. | |||
| * This is a hack, plain and simple. Ideally we would use RTTI to | |||
| * return the name of type T, but until there is some sort of | |||
| * consistent support for human readable names, we are left to our | |||
| * own devices. | |||
| */ | |||
| std::string _typeDesc; | |||
| /** | |||
| * A Constraint this Arg must conform to. | |||
| */ | |||
| Constraint<T>* _constraint; | |||
| /** | |||
| * Extracts the value from the string. | |||
| * Attempts to parse string as type T, if this fails an exception | |||
| * is thrown. | |||
| * \param val - value to be parsed. | |||
| */ | |||
| void _extractValue(const std::string& val); | |||
| public: | |||
| /** | |||
| * Labeled ValueArg constructor. | |||
| * You could conceivably call this constructor with a blank flag, | |||
| * but that would make you a bad person. It would also cause | |||
| * an exception to be thrown. If you want an unlabeled argument, | |||
| * use the other constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T value, const std::string& typeDesc, Visitor* v = NULL); | |||
| /** | |||
| * Labeled ValueArg constructor. | |||
| * You could conceivably call this constructor with a blank flag, | |||
| * but that would make you a bad person. It would also cause | |||
| * an exception to be thrown. If you want an unlabeled argument, | |||
| * use the other constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param typeDesc - A short, human readable description of the | |||
| * type that this object expects. This is used in the generation | |||
| * of the USAGE statement. The goal is to be helpful to the end user | |||
| * of the program. | |||
| * \param parser - A CmdLine parser object to add this Arg to | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T value, const std::string& typeDesc, CmdLineInterface& parser, Visitor* v = NULL); | |||
| /** | |||
| * Labeled ValueArg constructor. | |||
| * You could conceivably call this constructor with a blank flag, | |||
| * but that would make you a bad person. It would also cause | |||
| * an exception to be thrown. If you want an unlabeled argument, | |||
| * use the other constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param parser - A CmdLine parser object to add this Arg to. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T value, Constraint<T>* constraint, CmdLineInterface& parser, Visitor* v = NULL); | |||
| /** | |||
| * Labeled ValueArg constructor. | |||
| * You could conceivably call this constructor with a blank flag, | |||
| * but that would make you a bad person. It would also cause | |||
| * an exception to be thrown. If you want an unlabeled argument, | |||
| * use the other constructor. | |||
| * \param flag - The one character flag that identifies this | |||
| * argument on the command line. | |||
| * \param name - A one word name for the argument. Can be | |||
| * used as a long flag on the command line. | |||
| * \param desc - A description of what the argument is for or | |||
| * does. | |||
| * \param req - Whether the argument is required on the command | |||
| * line. | |||
| * \param value - The default value assigned to this argument if it | |||
| * is not present on the command line. | |||
| * \param constraint - A pointer to a Constraint object used | |||
| * to constrain this Arg. | |||
| * \param v - An optional visitor. You probably should not | |||
| * use this unless you have a very good reason. | |||
| */ | |||
| ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T value, Constraint<T>* constraint, Visitor* v = NULL); | |||
| /** | |||
| * Handles the processing of the argument. | |||
| * This re-implements the Arg version of this method to set the | |||
| * _value of the argument appropriately. It knows the difference | |||
| * between labeled and unlabeled. | |||
| * \param i - Pointer the the current argument in the list. | |||
| * \param args - Mutable list of strings. Passed | |||
| * in from main(). | |||
| */ | |||
| virtual bool processArg(int* i, std::vector<std::string>& args); | |||
| /** | |||
| * Returns the value of the argument. | |||
| */ | |||
| const T& getValue() const | |||
| { | |||
| return _value; | |||
| } | |||
| // TODO(macbishop): Non-const variant is deprecated, don't | |||
| // use. Remove in next major. | |||
| T& getValue() | |||
| { | |||
| return _value; | |||
| } | |||
| /** | |||
| * A ValueArg can be used as as its value type (T) This is the | |||
| * same as calling getValue() | |||
| */ | |||
| operator const T&() const | |||
| { | |||
| return getValue(); | |||
| } | |||
| /** | |||
| * Specialization of shortID. | |||
| * \param val - value to be used. | |||
| */ | |||
| virtual std::string shortID(const std::string& val = "val") const; | |||
| /** | |||
| * Specialization of longID. | |||
| * \param val - value to be used. | |||
| */ | |||
| virtual std::string longID(const std::string& val = "val") const; | |||
| virtual void reset(); | |||
| private: | |||
| /** | |||
| * Prevent accidental copying | |||
| */ | |||
| ValueArg<T>(const ValueArg<T>& rhs); | |||
| ValueArg<T>& operator=(const ValueArg<T>& rhs); | |||
| }; | |||
| /** | |||
| * Constructor implementation. | |||
| */ | |||
| template<class T> | |||
| ValueArg<T>::ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T val, const std::string& typeDesc, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _value(val), | |||
| _default(val), | |||
| _typeDesc(typeDesc), | |||
| _constraint(NULL) | |||
| { | |||
| } | |||
| template<class T> | |||
| ValueArg<T>::ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T val, const std::string& typeDesc, CmdLineInterface& parser, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _value(val), | |||
| _default(val), | |||
| _typeDesc(typeDesc), | |||
| _constraint(NULL) | |||
| { | |||
| parser.add(this); | |||
| } | |||
| template<class T> | |||
| ValueArg<T>::ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T val, Constraint<T>* constraint, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _value(val), | |||
| _default(val), | |||
| _typeDesc(Constraint<T>::shortID(constraint)), | |||
| _constraint(constraint) | |||
| { | |||
| } | |||
| template<class T> | |||
| ValueArg<T>::ValueArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, T val, Constraint<T>* constraint, CmdLineInterface& parser, Visitor* v) : | |||
| Arg(flag, name, desc, req, true, v), | |||
| _value(val), | |||
| _default(val), | |||
| _typeDesc(Constraint<T>::shortID(constraint)), // TODO(macbishop): Will crash | |||
| // if constraint is NULL | |||
| _constraint(constraint) | |||
| { | |||
| parser.add(this); | |||
| } | |||
| /** | |||
| * Implementation of processArg(). | |||
| */ | |||
| template<class T> | |||
| bool ValueArg<T>::processArg(int* i, std::vector<std::string>& args) | |||
| { | |||
| if (_ignoreable && Arg::ignoreRest()) | |||
| return false; | |||
| if (_hasBlanks(args[*i])) | |||
| return false; | |||
| std::string flag = args[*i]; | |||
| std::string value = ""; | |||
| trimFlag(flag, value); | |||
| if (argMatches(flag)) | |||
| { | |||
| if (_alreadySet) | |||
| { | |||
| if (_xorSet) | |||
| throw(CmdLineParseException("Mutually exclusive argument" | |||
| " already set!", | |||
| toString())); | |||
| else | |||
| throw(CmdLineParseException("Argument already set!", toString())); | |||
| } | |||
| if (Arg::delimiter() != ' ' && value == "") | |||
| throw(ArgParseException("Couldn't find delimiter for this argument!", toString())); | |||
| if (value == "") | |||
| { | |||
| (*i)++; | |||
| if (static_cast<unsigned int>(*i) < args.size()) | |||
| _extractValue(args[*i]); | |||
| else | |||
| throw(ArgParseException("Missing a value for this argument!", toString())); | |||
| } | |||
| else | |||
| _extractValue(value); | |||
| _alreadySet = true; | |||
| _checkWithVisitor(); | |||
| return true; | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| /** | |||
| * Implementation of shortID. | |||
| */ | |||
| template<class T> | |||
| std::string ValueArg<T>::shortID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return Arg::shortID(_typeDesc); | |||
| } | |||
| /** | |||
| * Implementation of longID. | |||
| */ | |||
| template<class T> | |||
| std::string ValueArg<T>::longID(const std::string& val) const | |||
| { | |||
| static_cast<void>(val); // Ignore input, don't warn | |||
| return Arg::longID(_typeDesc); | |||
| } | |||
| template<class T> | |||
| void ValueArg<T>::_extractValue(const std::string& val) | |||
| { | |||
| try | |||
| { | |||
| ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory()); | |||
| } | |||
| catch (ArgParseException& e) | |||
| { | |||
| throw ArgParseException(e.error(), toString()); | |||
| } | |||
| if (_constraint != NULL) | |||
| if (!_constraint->check(_value)) | |||
| throw(CmdLineParseException("Value '" + val + +"' does not meet constraint: " + _constraint->description(), toString())); | |||
| } | |||
| template<class T> | |||
| void ValueArg<T>::reset() | |||
| { | |||
| Arg::reset(); | |||
| _value = _default; | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,129 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: ValuesConstraint.h | |||
| * | |||
| * Copyright (c) 2005, Michael E. Smoot | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_VALUESCONSTRAINT_H | |||
| #define TCLAP_VALUESCONSTRAINT_H | |||
| #ifdef HAVE_CONFIG_H | |||
| #include <config.h> | |||
| #endif | |||
| #include <string> | |||
| #include <vector> | |||
| #include <tclap/Constraint.h> | |||
| #include <tclap/sstream.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A Constraint that constrains the Arg to only those values specified | |||
| * in the constraint. | |||
| */ | |||
| template<class T> | |||
| class ValuesConstraint : public Constraint<T> | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param allowed - vector of allowed values. | |||
| */ | |||
| ValuesConstraint(std::vector<T> const& allowed); | |||
| /** | |||
| * Virtual destructor. | |||
| */ | |||
| virtual ~ValuesConstraint() | |||
| { | |||
| } | |||
| /** | |||
| * Returns a description of the Constraint. | |||
| */ | |||
| virtual std::string description() const; | |||
| /** | |||
| * Returns the short ID for the Constraint. | |||
| */ | |||
| virtual std::string shortID() const; | |||
| /** | |||
| * The method used to verify that the value parsed from the command | |||
| * line meets the constraint. | |||
| * \param value - The value that will be checked. | |||
| */ | |||
| virtual bool check(const T& value) const; | |||
| protected: | |||
| /** | |||
| * The list of valid values. | |||
| */ | |||
| std::vector<T> _allowed; | |||
| /** | |||
| * The string used to describe the allowed values of this constraint. | |||
| */ | |||
| std::string _typeDesc; | |||
| }; | |||
| template<class T> | |||
| ValuesConstraint<T>::ValuesConstraint(std::vector<T> const& allowed) : | |||
| _allowed(allowed), | |||
| _typeDesc("") | |||
| { | |||
| for (unsigned int i = 0; i < _allowed.size(); i++) | |||
| { | |||
| std::ostringstream os; | |||
| os << _allowed[i]; | |||
| std::string temp(os.str()); | |||
| if (i > 0) | |||
| _typeDesc += "|"; | |||
| _typeDesc += temp; | |||
| } | |||
| } | |||
| template<class T> | |||
| bool ValuesConstraint<T>::check(const T& val) const | |||
| { | |||
| if (std::find(_allowed.begin(), _allowed.end(), val) == _allowed.end()) | |||
| return false; | |||
| else | |||
| return true; | |||
| } | |||
| template<class T> | |||
| std::string ValuesConstraint<T>::shortID() const | |||
| { | |||
| return _typeDesc; | |||
| } | |||
| template<class T> | |||
| std::string ValuesConstraint<T>::description() const | |||
| { | |||
| return _typeDesc; | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,83 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: VersionVisitor.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_VERSION_VISITOR_H | |||
| #define TCLAP_VERSION_VISITOR_H | |||
| #include <tclap/CmdLineInterface.h> | |||
| #include <tclap/CmdLineOutput.h> | |||
| #include <tclap/Visitor.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A Visitor that will call the version method of the given CmdLineOutput | |||
| * for the specified CmdLine object and then exit. | |||
| */ | |||
| class VersionVisitor : public Visitor | |||
| { | |||
| private: | |||
| /** | |||
| * Prevent accidental copying | |||
| */ | |||
| VersionVisitor(const VersionVisitor& rhs); | |||
| VersionVisitor& operator=(const VersionVisitor& rhs); | |||
| protected: | |||
| /** | |||
| * The CmdLine of interest. | |||
| */ | |||
| CmdLineInterface* _cmd; | |||
| /** | |||
| * The output object. | |||
| */ | |||
| CmdLineOutput** _out; | |||
| public: | |||
| /** | |||
| * Constructor. | |||
| * \param cmd - The CmdLine the output is generated for. | |||
| * \param out - The type of output. | |||
| */ | |||
| VersionVisitor(CmdLineInterface* cmd, CmdLineOutput** out) : | |||
| Visitor(), | |||
| _cmd(cmd), | |||
| _out(out) | |||
| { | |||
| } | |||
| /** | |||
| * Calls the version method of the output object using the | |||
| * specified CmdLine. | |||
| */ | |||
| void visit() | |||
| { | |||
| (*_out)->version(*_cmd); | |||
| throw ExitException(0); | |||
| } | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,59 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: Visitor.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2017, Google LLC | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_VISITOR_H | |||
| #define TCLAP_VISITOR_H | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A base class that defines the interface for visitors. | |||
| */ | |||
| class Visitor | |||
| { | |||
| public: | |||
| /** | |||
| * Constructor. Does nothing. | |||
| */ | |||
| Visitor() | |||
| { | |||
| } | |||
| /** | |||
| * Destructor. Does nothing. | |||
| */ | |||
| virtual ~Visitor() | |||
| { | |||
| } | |||
| /** | |||
| * This method (to implemented by children) will be | |||
| * called when the visitor is visited. | |||
| */ | |||
| virtual void visit() = 0; | |||
| }; | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,165 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: XorHandler.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_XORHANDLER_H | |||
| #define TCLAP_XORHANDLER_H | |||
| #include <tclap/Arg.h> | |||
| #include <string> | |||
| #include <vector> | |||
| #include <algorithm> | |||
| #include <iostream> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * This class handles lists of Arg's that are to be XOR'd on the command | |||
| * line. This is used by CmdLine and you shouldn't ever use it. | |||
| */ | |||
| class XorHandler | |||
| { | |||
| protected: | |||
| /** | |||
| * The list of of lists of Arg's to be or'd together. | |||
| */ | |||
| std::vector<std::vector<Arg*>> _orList; | |||
| public: | |||
| /** | |||
| * Constructor. Does nothing. | |||
| */ | |||
| XorHandler() : | |||
| _orList(std::vector<std::vector<Arg*>>()) | |||
| { | |||
| } | |||
| /** | |||
| * Add a list of Arg*'s that will be xor'd together. | |||
| * \param ors - list of Arg* that will be xor'd. | |||
| */ | |||
| void add(const std::vector<Arg*>& ors); | |||
| /** | |||
| * Checks whether the specified Arg is in one of the xor lists and | |||
| * if it does match one, returns the size of the xor list that the | |||
| * Arg matched. If the Arg matches, then it also sets the rest of | |||
| * the Arg's in the list. You shouldn't use this. | |||
| * \param a - The Arg to be checked. | |||
| */ | |||
| int check(const Arg* a); | |||
| /** | |||
| * Returns the XOR specific short usage. | |||
| */ | |||
| std::string shortUsage(); | |||
| /** | |||
| * Prints the XOR specific long usage. | |||
| * \param os - Stream to print to. | |||
| */ | |||
| void printLongUsage(std::ostream& os); | |||
| /** | |||
| * Simply checks whether the Arg is contained in one of the arg | |||
| * lists. | |||
| * \param a - The Arg to be checked. | |||
| */ | |||
| bool contains(const Arg* a); | |||
| const std::vector<std::vector<Arg*>>& getXorList() const; | |||
| }; | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // BEGIN XOR.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| inline void XorHandler::add(const std::vector<Arg*>& ors) | |||
| { | |||
| _orList.push_back(ors); | |||
| } | |||
| inline int XorHandler::check(const Arg* a) | |||
| { | |||
| // iterate over each XOR list | |||
| for (int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++) | |||
| { | |||
| // if the XOR list contains the arg.. | |||
| ArgVectorIterator ait = std::find(_orList[i].begin(), _orList[i].end(), a); | |||
| if (ait != _orList[i].end()) | |||
| { | |||
| // first check to see if a mutually exclusive switch | |||
| // has not already been set | |||
| for (ArgVectorIterator it = _orList[i].begin(); | |||
| it != _orList[i].end(); | |||
| it++) | |||
| if (a != (*it) && (*it)->isSet()) | |||
| throw(CmdLineParseException( | |||
| "Mutually exclusive argument already set!", | |||
| (*it)->toString() | |||
| )); | |||
| // go through and set each arg that is not a | |||
| for (ArgVectorIterator it = _orList[i].begin(); | |||
| it != _orList[i].end(); | |||
| it++) | |||
| if (a != (*it)) | |||
| (*it)->xorSet(); | |||
| // return the number of required args that have now been set | |||
| if ((*ait)->allowMore()) | |||
| return 0; | |||
| else | |||
| return static_cast<int>(_orList[i].size()); | |||
| } | |||
| } | |||
| if (a->isRequired()) | |||
| return 1; | |||
| else | |||
| return 0; | |||
| } | |||
| inline bool XorHandler::contains(const Arg* a) | |||
| { | |||
| for (int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++) | |||
| for (ArgVectorIterator it = _orList[i].begin(); | |||
| it != _orList[i].end(); | |||
| it++) | |||
| if (a == (*it)) | |||
| return true; | |||
| return false; | |||
| } | |||
| inline const std::vector<std::vector<Arg*>>& XorHandler::getXorList() const | |||
| { | |||
| return _orList; | |||
| } | |||
| ////////////////////////////////////////////////////////////////////// | |||
| // END XOR.cpp | |||
| ////////////////////////////////////////////////////////////////////// | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,336 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: ZshCompletionOutput.h | |||
| * | |||
| * Copyright (c) 2006, Oliver Kiddle | |||
| * Copyright (c) 2017 Google Inc. | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H | |||
| #define TCLAP_ZSHCOMPLETIONOUTPUT_H | |||
| #ifdef HAVE_CONFIG_H | |||
| #include <config.h> | |||
| #endif | |||
| #include <string> | |||
| #include <vector> | |||
| #include <list> | |||
| #include <iostream> | |||
| #include <map> | |||
| #include <tclap/CmdLineInterface.h> | |||
| #include <tclap/CmdLineOutput.h> | |||
| #include <tclap/XorHandler.h> | |||
| #include <tclap/Arg.h> | |||
| #include <tclap/sstream.h> | |||
| namespace TCLAP | |||
| { | |||
| /** | |||
| * A class that generates a Zsh completion function as output from the usage() | |||
| * method for the given CmdLine and its Args. | |||
| */ | |||
| class ZshCompletionOutput : public CmdLineOutput | |||
| { | |||
| public: | |||
| ZshCompletionOutput(); | |||
| /** | |||
| * Prints the usage to stdout. Can be overridden to | |||
| * produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void usage(CmdLineInterface& c); | |||
| /** | |||
| * Prints the version to stdout. Can be overridden | |||
| * to produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| */ | |||
| virtual void version(CmdLineInterface& c); | |||
| /** | |||
| * Prints (to stderr) an error message, short usage | |||
| * Can be overridden to produce alternative behavior. | |||
| * \param c - The CmdLine object the output is generated for. | |||
| * \param e - The ArgException that caused the failure. | |||
| */ | |||
| virtual void failure(CmdLineInterface& c, ArgException& e); | |||
| protected: | |||
| void basename(std::string& s); | |||
| void quoteSpecialChars(std::string& s); | |||
| std::string getMutexList(CmdLineInterface& _cmd, Arg* a); | |||
| void printOption(Arg* it, std::string mutex); | |||
| void printArg(Arg* it); | |||
| std::map<std::string, std::string> common; | |||
| char theDelimiter; | |||
| }; | |||
| ZshCompletionOutput::ZshCompletionOutput() : | |||
| common(std::map<std::string, std::string>()), | |||
| theDelimiter('=') | |||
| { | |||
| common["host"] = "_hosts"; | |||
| common["hostname"] = "_hosts"; | |||
| common["file"] = "_files"; | |||
| common["filename"] = "_files"; | |||
| common["user"] = "_users"; | |||
| common["username"] = "_users"; | |||
| common["directory"] = "_directories"; | |||
| common["path"] = "_directories"; | |||
| common["url"] = "_urls"; | |||
| } | |||
| inline void ZshCompletionOutput::version(CmdLineInterface& _cmd) | |||
| { | |||
| std::cout << _cmd.getVersion() << std::endl; | |||
| } | |||
| inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd) | |||
| { | |||
| std::list<Arg*> argList = _cmd.getArgList(); | |||
| std::string progName = _cmd.getProgramName(); | |||
| std::string xversion = _cmd.getVersion(); | |||
| theDelimiter = _cmd.getDelimiter(); | |||
| basename(progName); | |||
| std::cout << "#compdef " << progName << std::endl | |||
| << std::endl | |||
| << "# " << progName << " version " << _cmd.getVersion() << std::endl | |||
| << std::endl | |||
| << "_arguments -s -S"; | |||
| for (ArgListIterator it = argList.begin(); it != argList.end(); it++) | |||
| { | |||
| if ((*it)->shortID().at(0) == '<') | |||
| printArg((*it)); | |||
| else if ((*it)->getFlag() != "-") | |||
| printOption((*it), getMutexList(_cmd, *it)); | |||
| } | |||
| std::cout << std::endl; | |||
| } | |||
| inline void ZshCompletionOutput::failure(CmdLineInterface& _cmd, ArgException& e) | |||
| { | |||
| static_cast<void>(_cmd); // unused | |||
| std::cout << e.what() << std::endl; | |||
| } | |||
| inline void ZshCompletionOutput::quoteSpecialChars(std::string& s) | |||
| { | |||
| size_t idx = s.find_last_of(':'); | |||
| while (idx != std::string::npos) | |||
| { | |||
| s.insert(idx, 1, '\\'); | |||
| idx = s.find_last_of(':', idx); | |||
| } | |||
| idx = s.find_last_of('\''); | |||
| while (idx != std::string::npos) | |||
| { | |||
| s.insert(idx, "'\\'"); | |||
| if (idx == 0) | |||
| idx = std::string::npos; | |||
| else | |||
| idx = s.find_last_of('\'', --idx); | |||
| } | |||
| } | |||
| inline void ZshCompletionOutput::basename(std::string& s) | |||
| { | |||
| size_t p = s.find_last_of('/'); | |||
| if (p != std::string::npos) | |||
| { | |||
| s.erase(0, p + 1); | |||
| } | |||
| } | |||
| inline void ZshCompletionOutput::printArg(Arg* a) | |||
| { | |||
| static int count = 1; | |||
| std::cout << " \\" << std::endl | |||
| << " '"; | |||
| if (a->acceptsMultipleValues()) | |||
| std::cout << '*'; | |||
| else | |||
| std::cout << count++; | |||
| std::cout << ':'; | |||
| if (!a->isRequired()) | |||
| std::cout << ':'; | |||
| std::cout << a->getName() << ':'; | |||
| std::map<std::string, std::string>::iterator compArg = common.find(a->getName()); | |||
| if (compArg != common.end()) | |||
| { | |||
| std::cout << compArg->second; | |||
| } | |||
| else | |||
| { | |||
| std::cout << "_guard \"^-*\" " << a->getName(); | |||
| } | |||
| std::cout << '\''; | |||
| } | |||
| inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex) | |||
| { | |||
| std::string flag = a->flagStartChar() + a->getFlag(); | |||
| std::string name = a->nameStartString() + a->getName(); | |||
| std::string desc = a->getDescription(); | |||
| // remove full stop and capitalization from description as | |||
| // this is the convention for zsh function | |||
| if (!desc.compare(0, 12, "(required) ")) | |||
| { | |||
| desc.erase(0, 12); | |||
| } | |||
| if (!desc.compare(0, 15, "(OR required) ")) | |||
| { | |||
| desc.erase(0, 15); | |||
| } | |||
| size_t len = desc.length(); | |||
| if (len && desc.at(--len) == '.') | |||
| { | |||
| desc.erase(len); | |||
| } | |||
| if (len) | |||
| { | |||
| desc.replace(0, 1, 1, tolower(desc.at(0))); | |||
| } | |||
| std::cout << " \\" << std::endl | |||
| << " '" << mutex; | |||
| if (a->getFlag().empty()) | |||
| { | |||
| std::cout << name; | |||
| } | |||
| else | |||
| { | |||
| std::cout << "'{" << flag << ',' << name << "}'"; | |||
| } | |||
| if (theDelimiter == '=' && a->isValueRequired()) | |||
| std::cout << "=-"; | |||
| quoteSpecialChars(desc); | |||
| std::cout << '[' << desc << ']'; | |||
| if (a->isValueRequired()) | |||
| { | |||
| std::string arg = a->shortID(); | |||
| // Example arg: "[-A <integer>] ..." | |||
| size_t pos = arg.rfind(" ..."); | |||
| if (pos != std::string::npos) | |||
| { | |||
| arg.erase(pos); | |||
| } | |||
| arg.erase(0, arg.find_last_of(theDelimiter) + 1); | |||
| if (arg.at(arg.length() - 1) == ']') | |||
| arg.erase(arg.length() - 1); | |||
| if (arg.at(arg.length() - 1) == ']') | |||
| { | |||
| arg.erase(arg.length() - 1); | |||
| } | |||
| if (arg.at(0) == '<') | |||
| { | |||
| arg.erase(arg.length() - 1); | |||
| arg.erase(0, 1); | |||
| } | |||
| size_t p = arg.find('|'); | |||
| if (p != std::string::npos) | |||
| { | |||
| do | |||
| { | |||
| arg.replace(p, 1, 1, ' '); | |||
| } while ((p = arg.find_first_of('|', p)) != std::string::npos); | |||
| quoteSpecialChars(arg); | |||
| std::cout << ": :(" << arg << ')'; | |||
| } | |||
| else | |||
| { | |||
| std::cout << ':' << arg; | |||
| std::map<std::string, std::string>::iterator compArg = common.find(arg); | |||
| if (compArg != common.end()) | |||
| { | |||
| std::cout << ':' << compArg->second; | |||
| } | |||
| } | |||
| } | |||
| std::cout << '\''; | |||
| } | |||
| inline std::string ZshCompletionOutput::getMutexList(CmdLineInterface& _cmd, Arg* a) | |||
| { | |||
| XorHandler xorHandler = _cmd.getXorHandler(); | |||
| std::vector<std::vector<Arg*>> xorList = xorHandler.getXorList(); | |||
| if (a->getName() == "help" || a->getName() == "version") | |||
| { | |||
| return "(-)"; | |||
| } | |||
| ostringstream list; | |||
| if (a->acceptsMultipleValues()) | |||
| { | |||
| list << '*'; | |||
| } | |||
| for (int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++) | |||
| { | |||
| for (ArgVectorIterator it = xorList[i].begin(); | |||
| it != xorList[i].end(); | |||
| it++) | |||
| if (a == (*it)) | |||
| { | |||
| list << '('; | |||
| for (ArgVectorIterator iu = xorList[i].begin(); | |||
| iu != xorList[i].end(); | |||
| iu++) | |||
| { | |||
| bool notCur = (*iu) != a; | |||
| bool hasFlag = !(*iu)->getFlag().empty(); | |||
| if (iu != xorList[i].begin() && (notCur || hasFlag)) | |||
| list << ' '; | |||
| if (hasFlag) | |||
| list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' '; | |||
| if (notCur || hasFlag) | |||
| list << (*iu)->nameStartString() << (*iu)->getName(); | |||
| } | |||
| list << ')'; | |||
| return list.str(); | |||
| } | |||
| } | |||
| // wasn't found in xor list | |||
| if (!a->getFlag().empty()) | |||
| { | |||
| list << "(" << a->flagStartChar() << a->getFlag() << ' ' << a->nameStartString() << a->getName() << ')'; | |||
| } | |||
| return list.str(); | |||
| } | |||
| } // namespace TCLAP | |||
| #endif | |||
| @@ -0,0 +1,52 @@ | |||
| // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- | |||
| /****************************************************************************** | |||
| * | |||
| * file: sstream.h | |||
| * | |||
| * Copyright (c) 2003, Michael E. Smoot . | |||
| * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno . | |||
| * Copyright (c) 2017 Google Inc. | |||
| * All rights reserved. | |||
| * | |||
| * See the file COPYING in the top directory of this distribution for | |||
| * more information. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS | |||
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |||
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |||
| * DEALINGS IN THE SOFTWARE. | |||
| * | |||
| *****************************************************************************/ | |||
| #ifndef TCLAP_SSTREAM_H | |||
| #define TCLAP_SSTREAM_H | |||
| #if !defined(HAVE_STRSTREAM) | |||
| // Assume sstream is available if strstream is not specified | |||
| // (https://sourceforge.net/p/tclap/bugs/23/) | |||
| #define HAVE_SSTREAM | |||
| #endif | |||
| #if defined(HAVE_SSTREAM) | |||
| #include <sstream> | |||
| namespace TCLAP | |||
| { | |||
| typedef std::istringstream istringstream; | |||
| typedef std::ostringstream ostringstream; | |||
| } // namespace TCLAP | |||
| #elif defined(HAVE_STRSTREAM) | |||
| #include <strstream> | |||
| namespace TCLAP | |||
| { | |||
| typedef std::istrstream istringstream; | |||
| typedef std::ostrstream ostringstream; | |||
| } // namespace TCLAP | |||
| #else | |||
| #error "Need a stringstream (sstream or strstream) to compile!" | |||
| #endif | |||
| #endif // TCLAP_SSTREAM_H | |||
| @@ -1,6 +1,6 @@ | |||
| MIT License | |||
| Copyright (c) 2022 EESAST | |||
| Copyright (c) 2022-2023 EESAST | |||
| Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| of this software and associated documentation files (the "Software"), to deal | |||
| @@ -79,6 +79,7 @@ message MessageToClient | |||
| repeated MessageOfButcher butcher_message = 2; // 是否真正repeated待定 | |||
| repeated MessageOfProp prop_message = 3; | |||
| MessageOfMap map_message = 4; | |||
| GameState game_state = 5; | |||
| } | |||
| message MoveRes // 如果打算设计撞墙保留平行速度分量,且需要返回值则可用这个(大概没啥用) | |||
| @@ -89,32 +89,11 @@ enum ButcherType | |||
| BUTCHERTYPE4 = 4; | |||
| } | |||
| // 取消了大包之后,MessageType的枚举是否有必要保留还有待商榷 | |||
| // enum MessageType | |||
| // { | |||
| // // 公共信息类型 | |||
| // Move = 0; | |||
| // PickProp = 1; | |||
| // UseProp = 2; | |||
| // UseSkill = 3; | |||
| // Map = 4; | |||
| // Send = 5; | |||
| // // 人类限定信息类型 | |||
| // FixMachine = 6; | |||
| // SaveHuman = 7; | |||
| // // 屠夫限定信息类型 | |||
| // Attack = 8; | |||
| // CarryHuman = 9; | |||
| // ReleaseHuman = 10; | |||
| // HangHuman = 11; | |||
| // // 游戏相关信息类型 | |||
| // AddPlayer = 12; | |||
| // InvalidPlayer = 13; | |||
| // ValidPlayer = 14; | |||
| // StartGame = 15; | |||
| // Gaming = 16; | |||
| // EndGame = 17; | |||
| // } | |||
| // 游戏进行状态 | |||
| enum GameState | |||
| { | |||
| NULL_GAME_STATE = 0; | |||
| GAME_START = 1; | |||
| GAME_RUNNING = 2; | |||
| GAME_END = 3; | |||
| } | |||
| @@ -14,11 +14,11 @@ | |||
| </ItemGroup>--> | |||
| <ItemGroup> | |||
| <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | |||
| <PackageReference Include="Google.Protobuf.Tools" Version="3.21.9" /> | |||
| <PackageReference Include="Google.Protobuf" Version="3.21.11" /> | |||
| <PackageReference Include="Google.Protobuf.Tools" Version="3.21.12" /> | |||
| <PackageReference Include="Grpc" Version="2.46.5" /> | |||
| <PackageReference Include="Grpc.Core" Version="2.46.5" /> | |||
| <PackageReference Include="Grpc.Tools" Version="2.50.0"> | |||
| <PackageReference Include="Grpc.Tools" Version="2.51.0"> | |||
| <PrivateAssets>all</PrivateAssets> | |||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
| </PackageReference> | |||
| @@ -399,3 +399,4 @@ FodyWeavers.xsd | |||
| #THUAI playback file | |||
| *.thuaipb | |||
| @@ -8,7 +8,7 @@ | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | |||
| <PackageReference Include="Google.Protobuf" Version="3.21.11" /> | |||
| <PackageReference Include="Grpc" Version="2.46.5" /> | |||
| <PackageReference Include="Grpc.Core" Version="2.46.5" /> | |||
| </ItemGroup> | |||
| @@ -0,0 +1,13 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <TargetFramework>net6.0</TargetFramework> | |||
| <Nullable>enable</Nullable> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\GameEngine\GameEngine.csproj" /> | |||
| <ProjectReference Include="..\Preparation\Preparation.csproj" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,20 @@ | |||
| using Preparation.Utility; | |||
| namespace GameClass.GameObj | |||
| { | |||
| // 为方便界面组做子弹爆炸特效,现引入“爆炸中的子弹”,在每帧发送给界面组 | |||
| public sealed class BombedBullet : GameObj | |||
| { | |||
| public override ShapeType Shape => ShapeType.Circle; | |||
| public override bool IsRigid => false; | |||
| public long MappingID { get; } | |||
| public Bullet bulletHasBombed; | |||
| public BombedBullet(Bullet bullet) : | |||
| base(bullet.Position, bullet.Radius, bullet.Place, GameObjType.BombedBullet) | |||
| { | |||
| this.bulletHasBombed = bullet; | |||
| this.MappingID = bullet.ID; | |||
| this.FacingDirection = bullet.FacingDirection; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,238 @@ | |||
| using Preparation.GameData; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using System; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public abstract class Bullet : ObjOfCharacter | |||
| { | |||
| /// <summary> | |||
| /// //攻击力 | |||
| /// </summary> | |||
| public abstract int AP { get; } | |||
| public abstract int Speed { get; } | |||
| private readonly bool hasSpear; | |||
| /// <summary> | |||
| /// 是否有矛 | |||
| /// </summary> | |||
| public bool HasSpear => hasSpear; | |||
| /// <summary> | |||
| /// 与THUAI4不同的一个攻击判定方案,通过这个函数判断爆炸时能否伤害到target | |||
| /// </summary> | |||
| /// <param name="target">被尝试攻击者</param> | |||
| /// <returns>是否可以攻击到</returns> | |||
| public abstract bool CanAttack(GameObj target); | |||
| protected override bool IgnoreCollideExecutor(IGameObj targetObj) | |||
| { | |||
| if (targetObj.Type == GameObjType.BirthPoint || targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet) | |||
| return true; | |||
| return false; | |||
| } | |||
| public Bullet(Character player, int radius) : | |||
| base(player.Position, radius, PlaceType.Null, GameObjType.Bullet) | |||
| { | |||
| this.CanMove = true; | |||
| this.moveSpeed = this.Speed; | |||
| this.hasSpear = player.HasSpear; | |||
| this.Parent = player; | |||
| } | |||
| public override bool IsRigid => true; // 默认为true | |||
| public override ShapeType Shape => ShapeType.Circle; // 默认为圆形 | |||
| public abstract BulletType TypeOfBullet { get; } | |||
| } | |||
| internal sealed class AtomBomb : Bullet | |||
| { | |||
| public AtomBomb(Character player, int radius = GameData.bulletRadius) : | |||
| base(player, radius) | |||
| { | |||
| } | |||
| public const double BulletBombRange = GameData.basicBulletBombRange / 3 * 7; | |||
| public const double BulletAttackRange = GameData.basicAttackRange / 9 * 7; | |||
| public override int AP => GameData.basicAp / 3 * 7; | |||
| public override int Speed => GameData.basicBulletMoveSpeed / 3 * 2; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| // 圆形攻击范围 | |||
| return XY.Distance(this.Position, target.Position) <= BulletBombRange; | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.AtomBomb; | |||
| } | |||
| internal sealed class OrdinaryBullet : Bullet // 1倍攻击范围,1倍攻击力,一倍速 | |||
| { | |||
| public OrdinaryBullet(Character player, int radius = GameData.bulletRadius) : | |||
| base(player, radius) | |||
| { | |||
| } | |||
| public const double BulletBombRange = GameData.basicBulletBombRange / 6 * 5; | |||
| public const double BulletAttackRange = GameData.basicAttackRange / 2; | |||
| public override int AP => GameData.basicAp / 6 * 5; | |||
| public override int Speed => GameData.basicBulletMoveSpeed / 6 * 5; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| // 圆形攻击范围 | |||
| return XY.Distance(this.Position, target.Position) <= BulletBombRange; | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.OrdinaryBullet; | |||
| } | |||
| internal sealed class FastBullet : Bullet // 1倍攻击范围,0.2倍攻击力,2倍速 | |||
| { | |||
| public FastBullet(Character player, int radius = GameData.bulletRadius) : | |||
| base(player, radius) | |||
| { | |||
| } | |||
| public const double BulletBombRange = GameData.basicBulletBombRange / 4 * 2; | |||
| public const double BulletAttackRange = GameData.basicAttackRange; | |||
| public override int AP => (int)(0.5 * GameData.basicAp); | |||
| public override int Speed => 5 * GameData.basicBulletMoveSpeed / 3; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| // 圆形攻击范围 | |||
| return XY.Distance(this.Position, target.Position) <= BulletBombRange; | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.FastBullet; | |||
| } | |||
| internal sealed class LineBullet : Bullet // 直线爆炸,宽度1格,长度为2倍爆炸范围 | |||
| { | |||
| public LineBullet(Character player, int radius = GameData.bulletRadius) : | |||
| base(player, radius) | |||
| { | |||
| } | |||
| public const double BulletBombRange = GameData.basicBulletBombRange / 3 * 4; | |||
| public const double BulletAttackRange = 0.1 * GameData.basicAttackRange; | |||
| public override int AP => GameData.basicAp / 3 * 2; | |||
| public override int Speed => GameData.basicBulletMoveSpeed / 3; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| double FacingAngle = Math.Atan2(this.FacingDirection.y, this.FacingDirection.x); | |||
| if (Math.Abs(FacingAngle - Math.PI / 2) < 1e-2) | |||
| { | |||
| if (target.Position.y - this.Position.y > BulletBombRange) | |||
| return false; | |||
| if (target.Position.x < this.Position.x + GameData.numOfPosGridPerCell / 2 && target.Position.x > this.Position.x - GameData.numOfPosGridPerCell / 2) | |||
| return true; | |||
| return false; | |||
| } | |||
| else if (Math.Abs(FacingAngle - Math.PI * 3 / 2) < 1e-2) | |||
| { | |||
| if (target.Position.y - this.Position.y < -BulletBombRange) | |||
| return false; | |||
| if (target.Position.x < this.Position.x + GameData.numOfPosGridPerCell / 2 && target.Position.x > this.Position.x - GameData.numOfPosGridPerCell / 2) | |||
| return true; | |||
| return false; | |||
| } | |||
| else if (Math.Abs(FacingAngle) < 1e-2) | |||
| { | |||
| if (target.Position.x - this.Position.x > BulletBombRange) | |||
| return false; | |||
| if (target.Position.y < this.Position.y + GameData.numOfPosGridPerCell / 2 && target.Position.y > this.Position.y - GameData.numOfPosGridPerCell / 2) | |||
| return true; | |||
| return false; | |||
| } | |||
| else if (Math.Abs(FacingAngle - Math.PI) < 1e-2) | |||
| { | |||
| if (target.Position.x - this.Position.x < -BulletBombRange) | |||
| return false; | |||
| if (target.Position.y < this.Position.y + GameData.numOfPosGridPerCell / 2 && target.Position.y > this.Position.y - GameData.numOfPosGridPerCell / 2) | |||
| return true; | |||
| return false; | |||
| } | |||
| double vertical = Math.Tan(FacingAngle + Math.PI / 2); | |||
| bool posValue = vertical * Math.Cos(FacingAngle) - Math.Sin(FacingAngle) > 0; | |||
| double dist; | |||
| dist = vertical * (target.Position.x - this.Position.x) - (target.Position.y - this.Position.y) / Math.Sqrt(1 + vertical * vertical); | |||
| if (Math.Abs(dist) > BulletBombRange) | |||
| return false; | |||
| else if (dist < 0 && posValue) // 位于直线两侧 | |||
| return false; | |||
| vertical = Math.Tan(FacingAngle); | |||
| dist = Math.Abs(vertical * (target.Position.x - this.Position.x) - (target.Position.y - this.Position.y)) / Math.Sqrt(1 + vertical * vertical); | |||
| if (dist > GameData.numOfPosGridPerCell / 2) | |||
| return false; | |||
| return true; | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.LineBullet; | |||
| } | |||
| public static class BulletFactory | |||
| { | |||
| public static Bullet? GetBullet(Character character) | |||
| { | |||
| Bullet? newBullet = null; | |||
| switch (character.BulletOfPlayer) | |||
| { | |||
| case BulletType.AtomBomb: | |||
| newBullet = new AtomBomb(character); | |||
| break; | |||
| case BulletType.LineBullet: | |||
| newBullet = new LineBullet(character); | |||
| break; | |||
| case BulletType.FastBullet: | |||
| newBullet = new FastBullet(character); | |||
| break; | |||
| case BulletType.OrdinaryBullet: | |||
| newBullet = new OrdinaryBullet(character); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| return newBullet; | |||
| } | |||
| public static int BulletRadius(BulletType bulletType) | |||
| { | |||
| switch (bulletType) | |||
| { | |||
| case BulletType.AtomBomb: | |||
| case BulletType.LineBullet: | |||
| case BulletType.FastBullet: | |||
| case BulletType.OrdinaryBullet: | |||
| default: | |||
| return GameData.bulletRadius; | |||
| } | |||
| } | |||
| public static double BulletAttackRange(BulletType bulletType) | |||
| { | |||
| switch (bulletType) | |||
| { | |||
| case BulletType.AtomBomb: | |||
| return AtomBomb.BulletAttackRange; | |||
| case BulletType.LineBullet: | |||
| return LineBullet.BulletAttackRange; | |||
| case BulletType.FastBullet: | |||
| return FastBullet.BulletAttackRange; | |||
| case BulletType.OrdinaryBullet: | |||
| return OrdinaryBullet.BulletAttackRange; | |||
| default: | |||
| return 0; | |||
| } | |||
| } | |||
| public static double BulletBombRange(BulletType bulletType) | |||
| { | |||
| switch (bulletType) | |||
| { | |||
| case BulletType.AtomBomb: | |||
| return AtomBomb.BulletBombRange; | |||
| case BulletType.LineBullet: | |||
| return LineBullet.BulletBombRange; | |||
| case BulletType.FastBullet: | |||
| return FastBullet.BulletBombRange; | |||
| case BulletType.OrdinaryBullet: | |||
| return OrdinaryBullet.BulletBombRange; | |||
| default: | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,176 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Runtime.InteropServices; | |||
| using System.Threading; | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public partial class Character | |||
| { | |||
| private readonly BuffManeger buffManeger; | |||
| /// <summary> | |||
| /// 角色携带的buff管理器 | |||
| /// </summary> | |||
| private class BuffManeger | |||
| { | |||
| [StructLayout(LayoutKind.Explicit, Size = 8)] | |||
| private struct BuffValue // buff参数联合体类型,可能是int或double | |||
| { | |||
| [FieldOffset(0)] | |||
| public int iValue; | |||
| [FieldOffset(0)] | |||
| public double lfValue; | |||
| public BuffValue(int intValue) | |||
| { | |||
| this.lfValue = 0.0; | |||
| this.iValue = intValue; | |||
| } | |||
| public BuffValue(double longFloatValue) | |||
| { | |||
| this.iValue = 0; | |||
| this.lfValue = longFloatValue; | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// buff列表 | |||
| /// </summary> | |||
| private readonly LinkedList<BuffValue>[] buffList; | |||
| private readonly object[] buffListLock; | |||
| private void AddBuff(BuffValue bf, int buffTime, BuffType buffType, Action ReCalculateFunc) | |||
| { | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| LinkedListNode<BuffValue> buffNode; | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| buffNode = buffList[(int)buffType].AddLast(bf); | |||
| } | |||
| ReCalculateFunc(); | |||
| Thread.Sleep(buffTime); | |||
| try | |||
| { | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| buffList[(int)buffType].Remove(buffNode); | |||
| } | |||
| } | |||
| catch | |||
| { | |||
| } | |||
| ReCalculateFunc(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| private int ReCalculateFloatBuff(BuffType buffType, int orgVal, int maxVal, int minVal) | |||
| { | |||
| double times = 1.0; | |||
| lock (buffListLock[(int)buffType]) | |||
| { | |||
| foreach (var add in buffList[(int)buffType]) | |||
| { | |||
| times *= add.lfValue; | |||
| } | |||
| } | |||
| return Math.Max(Math.Min((int)Math.Round(orgVal * times), maxVal), minVal); | |||
| } | |||
| public void AddMoveSpeed(double add, int buffTime, Action<int> SetNewMoveSpeed, int orgMoveSpeed) => AddBuff(new BuffValue(add), buffTime, BuffType.AddSpeed, () => SetNewMoveSpeed(ReCalculateFloatBuff(BuffType.AddSpeed, orgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed))); | |||
| public bool HasFasterSpeed | |||
| { | |||
| get | |||
| { | |||
| lock (buffListLock[(int)BuffType.AddSpeed]) | |||
| { | |||
| return buffList[(int)BuffType.AddSpeed].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| public void AddShield(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Shield, () => | |||
| { }); | |||
| public bool HasShield | |||
| { | |||
| get | |||
| { | |||
| lock (buffListLock[(int)BuffType.Shield]) | |||
| { | |||
| return buffList[(int)BuffType.Shield].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| public void AddLIFE(int totelTime) => AddBuff(new BuffValue(), totelTime, BuffType.AddLIFE, () => | |||
| { }); | |||
| public bool HasLIFE | |||
| { | |||
| get | |||
| { | |||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||
| { | |||
| return buffList[(int)BuffType.AddLIFE].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| public bool TryActivatingLIFE() | |||
| { | |||
| if (HasLIFE) | |||
| { | |||
| lock (buffListLock[(int)BuffType.AddLIFE]) | |||
| { | |||
| buffList[(int)BuffType.AddLIFE].Clear(); | |||
| } | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| public void AddSpear(int spearTime) => AddBuff(new BuffValue(), spearTime, BuffType.Spear, () => | |||
| { }); | |||
| public bool HasSpear | |||
| { | |||
| get | |||
| { | |||
| lock (buffListLock[(int)BuffType.Spear]) | |||
| { | |||
| return buffList[(int)BuffType.Spear].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// 清除所有buff | |||
| /// </summary> | |||
| public void ClearAll() | |||
| { | |||
| for (int i = 0; i < buffList.Length; ++i) | |||
| { | |||
| lock (buffListLock[i]) | |||
| { | |||
| buffList[i].Clear(); | |||
| } | |||
| } | |||
| } | |||
| public BuffManeger() | |||
| { | |||
| var buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||
| buffList = new LinkedList<BuffValue>[buffTypeArray.Length]; | |||
| buffListLock = new object[buffList.Length]; | |||
| int i = 0; | |||
| foreach (BuffType type in buffTypeArray) | |||
| { | |||
| buffList[i] = new LinkedList<BuffValue>(); | |||
| buffListLock[i++] = new object(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,101 @@ | |||
| using GameClass.Skill; | |||
| using Preparation.Utility; | |||
| using System.Collections.Generic; | |||
| using System; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public partial class Character | |||
| { | |||
| private delegate bool CharacterActiveSkill(Character player); // 返回值:是否成功释放了技能 | |||
| private delegate void CharacterPassiveSkill(Character player); | |||
| private readonly CharacterActiveSkill commonSkill; | |||
| private readonly ActiveSkillType commonSkillType; | |||
| public ActiveSkillType CommonSkillType => commonSkillType; | |||
| private readonly CharacterType characterType; | |||
| public CharacterType CharacterType => characterType; | |||
| public bool UseCommonSkill() | |||
| { | |||
| return commonSkill(this); | |||
| } | |||
| private int timeUntilCommonSkillAvailable = 0; // 还剩多少时间可以使用普通技能 | |||
| public int TimeUntilCommonSkillAvailable | |||
| { | |||
| get => timeUntilCommonSkillAvailable; | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| timeUntilCommonSkillAvailable = value < 0 ? 0 : value; | |||
| } | |||
| } | |||
| readonly CharacterPassiveSkill passiveSkill; | |||
| public void UsePassiveSkill() | |||
| { | |||
| passiveSkill(this); | |||
| return; | |||
| } | |||
| public Character(XY initPos, int initRadius, PlaceType initPlace, CharacterType characterType, ActiveSkillType commonSkillType) : | |||
| base(initPos, initRadius, initPlace, GameObjType.Character) | |||
| { | |||
| this.CanMove = true; | |||
| this.score = 0; | |||
| this.propInventory = null; | |||
| this.buffManeger = new BuffManeger(); | |||
| IPassiveSkill pSkill; | |||
| ICommonSkill cSkill; | |||
| switch (passiveSkillType) | |||
| { | |||
| case this.CharacterType.RecoverAfterBattle: | |||
| pSkill = new RecoverAfterBattle(); | |||
| break; | |||
| case this.CharacterType.SpeedUpWhenLeavingGrass: | |||
| pSkill = new SpeedUpWhenLeavingGrass(); | |||
| break; | |||
| case this.CharacterType.Vampire: | |||
| pSkill = new Vampire(); | |||
| break; | |||
| default: | |||
| pSkill = new NoPassiveSkill(); | |||
| break; | |||
| } | |||
| switch (commonSkillType) | |||
| { | |||
| case ActiveSkillType.BecomeAssassin: | |||
| cSkill = new BecomeAssassin(); | |||
| break; | |||
| case ActiveSkillType.BecomeVampire: | |||
| cSkill = new BecomeVampire(); | |||
| break; | |||
| case ActiveSkillType.NuclearWeapon: | |||
| cSkill = new NuclearWeapon(); | |||
| break; | |||
| case ActiveSkillType.SuperFast: | |||
| cSkill = new SuperFast(); | |||
| break; | |||
| default: | |||
| cSkill = new NoCommonSkill(); | |||
| break; | |||
| } | |||
| this.MaxHp = cSkill.MaxHp; | |||
| this.hp = cSkill.MaxHp; | |||
| this.OrgMoveSpeed = cSkill.MoveSpeed; | |||
| this.moveSpeed = cSkill.MoveSpeed; | |||
| this.cd = cSkill.CD; | |||
| this.maxBulletNum = cSkill.MaxBulletNum; | |||
| this.bulletNum = maxBulletNum; | |||
| this.bulletOfPlayer = pSkill.InitBullet; | |||
| this.OriBulletOfPlayer = pSkill.InitBullet; | |||
| this.passiveSkill = pSkill.SkillEffect; | |||
| this.commonSkill = cSkill.SkillEffect; | |||
| this.passiveSkillType = passiveSkillType; | |||
| this.commonSkillType = commonSkillType; | |||
| // UsePassiveSkill(); //创建player时开始被动技能,这一过程也可以放到gamestart时进行 | |||
| // 这可以放在AddPlayer中做 | |||
| Debugger.Output(this, "constructed!"); | |||
| } | |||
| } | |||
| } | |||
| @@ -11,9 +11,8 @@ namespace GameClass.GameObj | |||
| { | |||
| private readonly object beAttackedLock = new(); | |||
| #region 角色的基本属性及方法,包括与道具的交互方法 | |||
| /* | |||
| //THUAI5子弹 | |||
| #region 角色的基本属性及方法,包括与道具的交互方法 | |||
| /// <summary> | |||
| /// 装弹冷却 | |||
| /// </summary> | |||
| @@ -21,8 +20,9 @@ namespace GameClass.GameObj | |||
| public int CD | |||
| { | |||
| get => cd; | |||
| private | |||
| set { | |||
| private | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| cd = value; | |||
| @@ -35,13 +35,14 @@ namespace GameClass.GameObj | |||
| public int MaxBulletNum => maxBulletNum; // 人物最大子弹数 | |||
| protected int bulletNum; | |||
| public int BulletNum => bulletNum; // 目前持有的子弹数 | |||
| */ | |||
| public int MaxHp { get; protected set; } // 最大血量 | |||
| protected int hp; | |||
| public int HP | |||
| { | |||
| get => hp; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| hp = value <= MaxHp ? value : MaxHp; | |||
| } | |||
| @@ -55,13 +56,31 @@ namespace GameClass.GameObj | |||
| get => score; | |||
| } | |||
| // public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer); | |||
| public double AttackRange => BulletFactory.BulletAttackRange(this.BulletOfPlayer); | |||
| private double vampire = 0; // 回血率:0-1之间 | |||
| public double Vampire | |||
| { | |||
| get => vampire; | |||
| set { | |||
| set | |||
| { | |||
| if (value > 1) | |||
| lock (gameObjLock) | |||
| vampire = 1; | |||
| else if (value < 0) | |||
| lock (gameObjLock) | |||
| vampire = 0; | |||
| else | |||
| lock (gameObjLock) | |||
| vampire = value; | |||
| } | |||
| } | |||
| private double oriVampire = 0; | |||
| public double OriVampire | |||
| { | |||
| get => oriVampire; | |||
| set | |||
| { | |||
| if (value > 1) | |||
| lock (gameObjLock) | |||
| vampire = 1; | |||
| @@ -73,26 +92,27 @@ namespace GameClass.GameObj | |||
| vampire = value; | |||
| } | |||
| } | |||
| private double OriVampire { get; } | |||
| /* | |||
| public readonly BulletType OriBulletOfPlayer; | |||
| private BulletType bulletOfPlayer; | |||
| public BulletType BulletOfPlayer | |||
| { | |||
| get => bulletOfPlayer; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| bulletOfPlayer = value; | |||
| } | |||
| } | |||
| */ | |||
| private Prop? propInventory; | |||
| public Prop? PropInventory // 持有的道具 | |||
| { | |||
| get => propInventory; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| propInventory = value; | |||
| @@ -122,7 +142,8 @@ namespace GameClass.GameObj | |||
| public bool IsModifyingProp | |||
| { | |||
| get => isModifyingProp; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isModifyingProp = value; | |||
| @@ -137,14 +158,15 @@ namespace GameClass.GameObj | |||
| public bool IsInvisible | |||
| { | |||
| get => isInvisible; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isInvisible = value; | |||
| } | |||
| } | |||
| } | |||
| /* | |||
| /// <summary> | |||
| /// 进行一次远程攻击 | |||
| /// </summary> | |||
| @@ -196,7 +218,7 @@ namespace GameClass.GameObj | |||
| return false; | |||
| } | |||
| } | |||
| */ | |||
| /// <summary> | |||
| /// 尝试加血 | |||
| /// </summary> | |||
| @@ -265,7 +287,7 @@ namespace GameClass.GameObj | |||
| Debugger.Output(this, " 's score has been subed to: " + score.ToString()); | |||
| } | |||
| } | |||
| /* | |||
| /// <summary> | |||
| /// 遭受攻击 | |||
| /// </summary> | |||
| @@ -326,7 +348,7 @@ namespace GameClass.GameObj | |||
| return hp <= 0; | |||
| } | |||
| } | |||
| */ | |||
| /// <summary> | |||
| /// 角色所属队伍ID | |||
| /// </summary> | |||
| @@ -334,7 +356,8 @@ namespace GameClass.GameObj | |||
| public long TeamID | |||
| { | |||
| get => teamID; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| teamID = value; | |||
| @@ -346,7 +369,8 @@ namespace GameClass.GameObj | |||
| public long PlayerID | |||
| { | |||
| get => playerID; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| playerID = value; | |||
| @@ -360,16 +384,17 @@ namespace GameClass.GameObj | |||
| public string Message | |||
| { | |||
| get => message; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| message = value; | |||
| } | |||
| } | |||
| } | |||
| #endregion | |||
| #endregion | |||
| #region 角色拥有的buff相关属性、方法 | |||
| #region 角色拥有的buff相关属性、方法 | |||
| public void AddMoveSpeed(int buffTime, double add = 2.0) => buffManeger.AddMoveSpeed(add, buffTime, newVal => | |||
| { MoveSpeed = newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed; }, | |||
| OrgMoveSpeed); | |||
| @@ -387,7 +412,8 @@ namespace GameClass.GameObj | |||
| private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||
| public Dictionary<BuffType, bool> Buff | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| Dictionary<BuffType, bool> buff = new Dictionary<BuffType, bool>(); | |||
| foreach (BuffType type in buffTypeArray) | |||
| { | |||
| @@ -420,7 +446,7 @@ namespace GameClass.GameObj | |||
| hp = MaxHp; | |||
| } | |||
| } | |||
| #endregion | |||
| #endregion | |||
| public override void Reset() // 要加锁吗? | |||
| { | |||
| _ = AddDeathCount(); | |||
| @@ -29,8 +29,9 @@ namespace GameClass.GameObj | |||
| public XY Position | |||
| { | |||
| get => position; | |||
| protected | |||
| set { | |||
| protected | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| position = value; | |||
| @@ -43,7 +44,8 @@ namespace GameClass.GameObj | |||
| public XY FacingDirection | |||
| { | |||
| get => facingDirection; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| facingDirection = value; | |||
| } | |||
| @@ -54,7 +56,8 @@ namespace GameClass.GameObj | |||
| public bool CanMove | |||
| { | |||
| get => canMove; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| canMove = value; | |||
| @@ -66,7 +69,8 @@ namespace GameClass.GameObj | |||
| public bool IsMoving | |||
| { | |||
| get => isMoving; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isMoving = value; | |||
| @@ -78,7 +82,8 @@ namespace GameClass.GameObj | |||
| public bool IsResetting | |||
| { | |||
| get => isResetting; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isResetting = value; | |||
| @@ -92,7 +97,8 @@ namespace GameClass.GameObj | |||
| public PlaceType Place | |||
| { | |||
| get => place; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| place = value; | |||
| @@ -106,7 +112,8 @@ namespace GameClass.GameObj | |||
| public int MoveSpeed | |||
| { | |||
| get => moveSpeed; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| moveSpeed = value; | |||
| @@ -120,8 +127,9 @@ namespace GameClass.GameObj | |||
| public int OrgMoveSpeed | |||
| { | |||
| get => orgMoveSpeed; | |||
| protected | |||
| set { | |||
| protected | |||
| set | |||
| { | |||
| orgMoveSpeed = value; | |||
| } | |||
| } | |||
| @@ -0,0 +1,156 @@ | |||
| using System.Collections.Generic; | |||
| using System.Threading; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| using System; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public partial class Map : IMap | |||
| { | |||
| private readonly Dictionary<uint, BirthPoint> birthPointList; // 出生点列表 | |||
| public Dictionary<uint, BirthPoint> BirthPointList => birthPointList; | |||
| private Dictionary<GameObjIdx, IList<IGameObj>> gameObjDict; | |||
| public Dictionary<GameObjIdx, IList<IGameObj>> GameObjDict => gameObjDict; | |||
| private Dictionary<GameObjIdx, ReaderWriterLockSlim> gameObjLockDict; | |||
| public Dictionary<GameObjIdx, ReaderWriterLockSlim> GameObjLockDict => gameObjLockDict; | |||
| public readonly uint[,] ProtoGameMap; | |||
| public PlaceType GetPlaceType(GameObj obj) | |||
| { | |||
| try | |||
| { | |||
| uint type = ProtoGameMap[obj.Position.x / GameData.numOfPosGridPerCell, obj.Position.y / GameData.numOfPosGridPerCell]; | |||
| if (type == 2) | |||
| return PlaceType.Grass1; | |||
| else if (type == 3) | |||
| return PlaceType.Grass2; | |||
| else if (type == 4) | |||
| return PlaceType.Grass3; | |||
| else | |||
| return PlaceType.Land; // 其他情况均返回land | |||
| } | |||
| catch | |||
| { | |||
| return PlaceType.Land; | |||
| } | |||
| } | |||
| public PlaceType GetPlaceType(XY pos) | |||
| { | |||
| try | |||
| { | |||
| switch (ProtoGameMap[pos.x / GameData.numOfPosGridPerCell, pos.y / GameData.numOfPosGridPerCell]) | |||
| { | |||
| case 2: | |||
| return PlaceType.Grass1; | |||
| case 3: | |||
| return PlaceType.Grass2; | |||
| case 4: | |||
| return PlaceType.Grass3; | |||
| default: | |||
| return PlaceType.Land; | |||
| } | |||
| } | |||
| catch | |||
| { | |||
| return PlaceType.Land; | |||
| } | |||
| } | |||
| public bool IsOutOfBound(IGameObj obj) | |||
| { | |||
| return obj.Position.x >= GameData.lengthOfMap - obj.Radius || obj.Position.x <= obj.Radius || obj.Position.y >= GameData.lengthOfMap - obj.Radius || obj.Position.y <= obj.Radius; | |||
| } | |||
| public IOutOfBound GetOutOfBound(XY pos) | |||
| { | |||
| return new OutOfBoundBlock(pos); | |||
| } | |||
| public Character? FindPlayer(long playerID) | |||
| { | |||
| Character? player = null; | |||
| gameObjLockDict[GameObjIdx.Player].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character person in gameObjDict[GameObjIdx.Player]) | |||
| { | |||
| if (playerID == person.ID) | |||
| { | |||
| player = person; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameObjLockDict[GameObjIdx.Player].ExitReadLock(); | |||
| } | |||
| return player; | |||
| } | |||
| public Map(uint[,] mapResource) | |||
| { | |||
| gameObjDict = new Dictionary<GameObjIdx, IList<IGameObj>>(); | |||
| gameObjLockDict = new Dictionary<GameObjIdx, ReaderWriterLockSlim>(); | |||
| foreach (GameObjIdx idx in Enum.GetValues(typeof(GameObjIdx))) | |||
| { | |||
| if (idx != GameObjIdx.None) | |||
| { | |||
| gameObjDict.Add(idx, new List<IGameObj>()); | |||
| gameObjLockDict.Add(idx, new ReaderWriterLockSlim()); | |||
| } | |||
| } | |||
| ProtoGameMap = new uint[mapResource.GetLength(0), mapResource.GetLength(1)]; | |||
| Array.Copy(mapResource, ProtoGameMap, mapResource.Length); | |||
| birthPointList = new Dictionary<uint, BirthPoint>(GameData.numOfBirthPoint); | |||
| // 将出生点插入 | |||
| for (int i = 0; i < GameData.rows; ++i) | |||
| { | |||
| for (int j = 0; j < GameData.cols; ++j) | |||
| { | |||
| switch (mapResource[i, j]) | |||
| { | |||
| case (uint)MapInfoObjType.Wall: | |||
| { | |||
| GameObjLockDict[GameObjIdx.Map].EnterWriteLock(); | |||
| try | |||
| { | |||
| GameObjDict[GameObjIdx.Map].Add(new Wall(GameData.GetCellCenterPos(i, j))); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[GameObjIdx.Map].ExitWriteLock(); | |||
| } | |||
| break; | |||
| } | |||
| case (uint)MapInfoObjType.BirthPoint1: | |||
| case (uint)MapInfoObjType.BirthPoint2: | |||
| case (uint)MapInfoObjType.BirthPoint3: | |||
| case (uint)MapInfoObjType.BirthPoint4: | |||
| case (uint)MapInfoObjType.BirthPoint5: | |||
| { | |||
| BirthPoint newBirthPoint = new BirthPoint(GameData.GetCellCenterPos(i, j)); | |||
| birthPointList.Add(MapInfo.BirthPointEnumToIdx((MapInfoObjType)mapResource[i, j]), newBirthPoint); | |||
| GameObjLockDict[GameObjIdx.Map].EnterWriteLock(); | |||
| try | |||
| { | |||
| GameObjDict[GameObjIdx.Map].Add(newBirthPoint); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[GameObjIdx.Map].ExitWriteLock(); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| using System.Threading; | |||
| using Preparation.Interface; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public partial class Map | |||
| { | |||
| // xfgg说:爱因斯坦说,每个坐标系都有与之绑定的时钟,(x, y, z, ict) 构成四维时空坐标,在洛伦兹变换下满足矢量性(狗头) | |||
| private readonly GameTimer timer = new(); | |||
| public ITimer Timer => timer; | |||
| public class GameTimer : ITimer | |||
| { | |||
| private bool isGaming = false; | |||
| public bool IsGaming => isGaming; | |||
| readonly object isGamingLock = new(); | |||
| public bool StartGame(int timeInMilliseconds) | |||
| { | |||
| lock (isGamingLock) | |||
| { | |||
| if (isGaming) | |||
| return false; | |||
| isGaming = true; | |||
| } | |||
| Thread.Sleep(timeInMilliseconds); | |||
| isGaming = false; | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,77 @@ | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public static class MapInfo | |||
| { | |||
| /// <summary> | |||
| /// 检测物体在哪;不能返回invisible。 | |||
| /// </summary> | |||
| /// <param name="obj"></param> | |||
| /// <returns></returns> | |||
| public static uint BirthPointEnumToIdx(MapInfoObjType birthPointEnum) | |||
| { | |||
| uint tmp = (uint)birthPointEnum; | |||
| // if (tmp < 5 || tmp > 12) throw new Exception("The parameter of BirthPointEnumToIdx is not a valid birth point enumeration value!"); | |||
| return tmp - 5; | |||
| } | |||
| /// <summary> | |||
| /// 50*50 | |||
| /// 1:Wall; 2:Grass1; 3:Grass2 ; 4:Grass3 ; 5~12:BirthPoint ; 13:GemWell | |||
| /// </summary> | |||
| public static uint[,] defaultMap = new uint[,] { | |||
| { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 13, 13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 1, 1, 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 13, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 13, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 13, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, | |||
| { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } | |||
| }; | |||
| } | |||
| } | |||
| @@ -0,0 +1,19 @@ | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| namespace GameClass.GameObj | |||
| { | |||
| /// <summary> | |||
| /// 墙体 | |||
| /// </summary> | |||
| public class Wall : GameObj | |||
| { | |||
| public Wall(XY initPos) : | |||
| base(initPos, GameData.numOfPosGridPerCell / 2, PlaceType.Land, GameObjType.Wall) | |||
| { | |||
| this.CanMove = false; | |||
| } | |||
| public override bool IsRigid => true; | |||
| public override ShapeType Shape => ShapeType.Square; | |||
| } | |||
| } | |||
| @@ -12,7 +12,8 @@ namespace GameClass.GameObj | |||
| public ICharacter? Parent | |||
| { | |||
| get => parent; | |||
| set { | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| parent = value; | |||
| @@ -0,0 +1,20 @@ | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| namespace GameClass.GameObj | |||
| { | |||
| /// <summary> | |||
| /// 逻辑墙 | |||
| /// </summary> | |||
| public class OutOfBoundBlock : GameObj, IOutOfBound | |||
| { | |||
| public OutOfBoundBlock(XY initPos) : | |||
| base(initPos, int.MaxValue, PlaceType.Land, GameObjType.OutOfBoundBlock) | |||
| { | |||
| this.CanMove = false; | |||
| } | |||
| public override bool IsRigid => true; | |||
| public override ShapeType Shape => ShapeType.Square; | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| 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 override ShapeType Shape => ShapeType.Circle; | |||
| public override bool IsRigid => false; | |||
| public long MappingID { get; } | |||
| public Prop PropHasPicked; | |||
| public PickedProp(Prop prop) : | |||
| base(prop.Position, prop.Radius, prop.Place, GameObjType.PickedProp) | |||
| { | |||
| this.PropHasPicked = prop; | |||
| this.MappingID = prop.ID; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,125 @@ | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| namespace GameClass.GameObj | |||
| { | |||
| public abstract class Prop : ObjOfCharacter | |||
| { | |||
| protected bool laid = false; | |||
| public bool Laid => laid; // 道具是否放置在地图上 | |||
| public override bool IsRigid => true; | |||
| protected override bool IgnoreCollideExecutor(IGameObj targetObj) | |||
| { | |||
| if (targetObj.Type == GameObjType.BirthPoint || targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet || targetObj.Type == GameObjType.Character) | |||
| return true; | |||
| return false; | |||
| } | |||
| public override ShapeType Shape => ShapeType.Square; | |||
| public abstract PropType GetPropType(); | |||
| public Prop(XY initPos, int radius = GameData.PropRadius) : | |||
| base(initPos, radius, PlaceType.Land, GameObjType.Prop) | |||
| { | |||
| this.CanMove = false; | |||
| this.moveSpeed = GameData.PropMoveSpeed; | |||
| } | |||
| public void SetNewPos(XY pos) | |||
| { | |||
| this.Position = pos; | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// 增益道具 | |||
| /// </summary> | |||
| public abstract class BuffProp : Prop | |||
| { | |||
| public BuffProp(XY initPos) : | |||
| base(initPos) | |||
| { | |||
| } | |||
| } | |||
| ///// <summary> | |||
| ///// 坑人地雷 | |||
| ///// </summary> | |||
| // public abstract class DebuffMine : Prop | |||
| //{ | |||
| // public DebuffMine(XYPosition initPos) : base(initPos) { } | |||
| // } | |||
| #region 所有增益道具 | |||
| /// <summary> | |||
| /// 增加速度 | |||
| /// </summary> | |||
| public sealed class AddSpeed : BuffProp | |||
| { | |||
| public AddSpeed(XY initPos) : | |||
| base(initPos) | |||
| { | |||
| } | |||
| public override PropType GetPropType() => PropType.addSpeed; | |||
| } | |||
| /// <summary> | |||
| /// 复活甲 | |||
| /// </summary> | |||
| public sealed class AddLIFE : BuffProp | |||
| { | |||
| public AddLIFE(XY initPos) : | |||
| base(initPos) | |||
| { | |||
| } | |||
| public override PropType GetPropType() => PropType.addLIFE; | |||
| } | |||
| /// <summary> | |||
| /// 护盾 | |||
| /// </summary> | |||
| public sealed class Shield : BuffProp | |||
| { | |||
| public Shield(XY initPos) : | |||
| base(initPos) | |||
| { | |||
| } | |||
| public override PropType GetPropType() => PropType.Shield; | |||
| } | |||
| /// <summary> | |||
| /// 矛 | |||
| /// </summary> | |||
| public sealed class Spear : BuffProp | |||
| { | |||
| public Spear(XY initPos) : | |||
| base(initPos) | |||
| { | |||
| } | |||
| public override PropType GetPropType() => PropType.Spear; | |||
| } | |||
| #endregion | |||
| // #region 所有坑人地雷 | |||
| ///// <summary> | |||
| ///// 减速 | |||
| ///// </summary> | |||
| // public sealed class MinusSpeed : DebuffMine | |||
| //{ | |||
| // public MinusSpeed(XYPosition initPos) : base(initPos) { } | |||
| // public override PropType GetPropType() => PropType.minusSpeed; | |||
| // } | |||
| ///// <summary> | |||
| ///// 减少攻击力 | |||
| ///// </summary> | |||
| // public sealed class MinusAP : DebuffMine | |||
| //{ | |||
| // public MinusAP(XYPosition initPos) : base(initPos) { } | |||
| // public override PropType GetPropType() => PropType.minusAP; | |||
| // } | |||
| ///// <summary> | |||
| ///// 增加冷却 | |||
| ///// </summary> | |||
| // public sealed class AddCD : DebuffMine | |||
| //{ | |||
| // public AddCD(XYPosition initPos) : base(initPos) { } | |||
| // public override PropType GetPropType() => PropType.addCD; | |||
| // } | |||
| // #endregion | |||
| } | |||
| @@ -13,7 +13,8 @@ namespace GameClass.GameObj | |||
| private readonly List<Character> playerList; | |||
| public int Score | |||
| { | |||
| get { | |||
| get | |||
| { | |||
| int score = 0; | |||
| foreach (var player in playerList) | |||
| score += player.Score; | |||
| @@ -0,0 +1,219 @@ | |||
| using GameClass.GameObj; | |||
| using System.Threading; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using Preparation.GameData; | |||
| using System; | |||
| using Timothy.FrameRateTask; | |||
| namespace GameClass.Skill | |||
| { | |||
| public class BecomeVampire : ICommonSkill //化身吸血鬼 | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = (int)(GameData.basicHp / 6 * 9.5); | |||
| public int MaxHp => maxHp; | |||
| private const int cd = GameData.basicCD; | |||
| public int CD => cd; | |||
| private const int maxBulletNum = GameData.basicBulletNum * 2 / 3; | |||
| public int MaxBulletNum => maxBulletNum; | |||
| // 以上参数以后再改 | |||
| public int SkillCD => GameData.commonSkillCD / 3 * 4; | |||
| public int DurationTime => GameData.commonSkillTime; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object CommonSkillLock => commonSkillLock; | |||
| public bool SkillEffect(Character player) | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.Vampire += 0.5; | |||
| Debugger.Output(player, "becomes vampire!"); | |||
| }, | |||
| () => | |||
| { | |||
| double tempVam = player.Vampire - 0.5; | |||
| player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; | |||
| }); | |||
| } | |||
| } | |||
| public class BecomeAssassin : ICommonSkill //化身刺客,隐身 | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed / 3 * 5; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = (int)(GameData.basicHp / 6 * 7.5); | |||
| public int MaxHp => maxHp; | |||
| private const int cd = GameData.basicCD; | |||
| public int CD => cd; | |||
| private const int maxBulletNum = GameData.basicBulletNum; | |||
| public int MaxBulletNum => maxBulletNum; | |||
| // 以上参数以后再改 | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object CommonSkillLock => commonSkillLock; | |||
| public bool SkillEffect(Character player) | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.IsInvisible = true; | |||
| Debugger.Output(player, "uses atombomb!"); | |||
| }, | |||
| () => { player.IsInvisible = false; }); | |||
| } | |||
| } | |||
| public class NuclearWeapon : ICommonSkill //核武器 | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed / 3 * 4; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp; | |||
| public int MaxHp => maxHp; | |||
| private const int cd = GameData.basicCD; | |||
| public int CD => cd; | |||
| private const int maxBulletNum = GameData.basicBulletNum * 2 / 3; | |||
| public int MaxBulletNum => maxBulletNum; | |||
| // 以上参数以后再改 | |||
| public int SkillCD => GameData.commonSkillCD / 3 * 7; | |||
| public int DurationTime => GameData.commonSkillTime / 10; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object CommonSkillLock => commonSkillLock; | |||
| public bool SkillEffect(Character player) | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||
| Debugger.Output(player, "uses atombomb!"); | |||
| }, | |||
| () => { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||
| } | |||
| } | |||
| public class SuperFast : ICommonSkill //3倍速 | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 4 / 3; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp / 6 * 4; | |||
| public int MaxHp => maxHp; | |||
| private const int cd = GameData.basicCD; | |||
| public int CD => cd; | |||
| private const int maxBulletNum = GameData.basicBulletNum * 4 / 3; | |||
| public int MaxBulletNum => maxBulletNum; | |||
| // 以上参数以后再改 | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 4; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object CommonSkillLock => commonSkillLock; | |||
| public bool SkillEffect(Character player) | |||
| { | |||
| return CommonSkillFactory.SkillEffect(this, player, () => | |||
| { | |||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||
| Debugger.Output(player, "moves very fast!"); | |||
| }, | |||
| () => { }); | |||
| } | |||
| } | |||
| public class NoCommonSkill : ICommonSkill //这种情况不该发生,定义着以防意外 | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp; | |||
| public int MaxHp => maxHp; | |||
| private const int cd = GameData.basicCD; | |||
| public int CD => cd; | |||
| private const int maxBulletNum = GameData.basicBulletNum; | |||
| public int MaxBulletNum => maxBulletNum; | |||
| // 以上参数以后再改 | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object CommonSkillLock => commonSkillLock; | |||
| public bool SkillEffect(Character player) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| public static class CommonSkillFactory | |||
| { | |||
| public static bool SkillEffect(ICommonSkill commonSkill, Character player, Action startSkill, Action endSkill) | |||
| { | |||
| lock (commonSkill.CommonSkillLock) | |||
| { | |||
| if (player.TimeUntilCommonSkillAvailable == 0) | |||
| { | |||
| player.TimeUntilCommonSkillAvailable = commonSkill.SkillCD; | |||
| new Thread | |||
| (() => | |||
| { | |||
| startSkill(); | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| () => !player.IsResetting, | |||
| () => | |||
| { | |||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: (long)(commonSkill.DurationTime) | |||
| ) | |||
| { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| }.Start(); | |||
| endSkill(); | |||
| Debugger.Output(player, "return to normal."); | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| () => player.TimeUntilCommonSkillAvailable > 0 && !player.IsResetting, | |||
| () => | |||
| { | |||
| player.TimeUntilCommonSkillAvailable -= (int)GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: (long)(commonSkill.SkillCD - commonSkill.DurationTime) | |||
| ) | |||
| { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| }.Start(); | |||
| player.TimeUntilCommonSkillAvailable = 0; | |||
| Debugger.Output(player, "CommonSkill is ready."); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| Debugger.Output(player, "CommonSkill is cooling down!"); | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,23 @@ | |||
| using GameClass.GameObj; | |||
| using Preparation.Utility; | |||
| using System.Threading; | |||
| namespace GameClass.Skill | |||
| { | |||
| public interface IPassiveSkill | |||
| { | |||
| public BulletType InitBullet { get; } | |||
| public void SkillEffect(Character player); | |||
| } | |||
| public interface ICommonSkill | |||
| { | |||
| public int MoveSpeed { get; } | |||
| public int MaxHp { get; } | |||
| public int CD { get; } | |||
| public int MaxBulletNum { get; } | |||
| public bool SkillEffect(Character player); | |||
| public int DurationTime { get; } //技能持续时间 | |||
| public int SkillCD { get; } | |||
| public object CommonSkillLock { get; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,152 @@ | |||
| using System; | |||
| using System.Threading; | |||
| using GameClass.GameObj; | |||
| using Preparation.GameData; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using Timothy.FrameRateTask; | |||
| namespace GameClass.Skill //被动技能开局时就释放,持续到游戏结束 | |||
| { | |||
| public class RecoverAfterBattle : IPassiveSkill //脱战回血,普通子弹 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.OrdinaryBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| //以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| const int recoverDegree = 5; //每帧回复血量 | |||
| int nowHP = player.HP; | |||
| int lastHP = nowHP; | |||
| long waitTime = 0; | |||
| const long interval = 10000; //每隔interval时间不受伤害,角色即开始回血 | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| () => true, | |||
| () => | |||
| { | |||
| lastHP = nowHP; //lastHP等于上一帧的HP | |||
| nowHP = player.HP; //nowHP更新为这一帧的HP | |||
| if (lastHP > nowHP) //这一帧扣血了 | |||
| { | |||
| waitTime = 0; | |||
| } | |||
| else if (waitTime < interval) | |||
| { | |||
| waitTime += GameData.frameDuration; | |||
| } | |||
| if (waitTime >= interval) //回复时,每帧(50ms)回复5,即1s回复100。 | |||
| player.TryAddHp(recoverDegree); | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: GameData.gameDuration | |||
| ) | |||
| { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||
| #if DEBUG | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||
| } | |||
| #endif | |||
| } | |||
| }.Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.FastBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| //以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| PlaceType nowPlace = player.Place; | |||
| PlaceType lastPlace = nowPlace; | |||
| bool speedup = false; | |||
| const int SpeedUpTime = 2000; //加速时间:2s | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| () => true, | |||
| () => | |||
| { | |||
| lastPlace = nowPlace; | |||
| nowPlace = player.Place; | |||
| if ((lastPlace == PlaceType.Grass1 || lastPlace == PlaceType.Grass2 || lastPlace == PlaceType.Grass3) && nowPlace == PlaceType.Land) | |||
| { | |||
| if (!speedup) | |||
| { | |||
| new Thread(() => | |||
| { | |||
| speedup = true; | |||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||
| speedup = false; | |||
| }) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| () => 0, | |||
| maxTotalDuration: GameData.gameDuration | |||
| ) | |||
| { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||
| #if DEBUG | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||
| } | |||
| #endif | |||
| } | |||
| }.Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| } | |||
| public class Vampire : IPassiveSkill //被动就是吸血,普通子弹 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.LineBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| //以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| player.OriVampire = 0.5; | |||
| player.Vampire = player.OriVampire; | |||
| } | |||
| } | |||
| public class NoPassiveSkill : IPassiveSkill //没技能,这种情况不应该发生,先定义着以防意外 | |||
| { | |||
| private readonly BulletType initBullet = BulletType.OrdinaryBullet; | |||
| public BulletType InitBullet => initBullet; | |||
| //以上参数以后再改 | |||
| public void SkillEffect(Character player) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| @@ -7,7 +7,7 @@ | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="FrameRateTask" Version="1.1.2" /> | |||
| <PackageReference Include="FrameRateTask" Version="1.2.0" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| @@ -64,67 +64,30 @@ namespace GameEngine | |||
| ( | |||
| () => | |||
| { | |||
| if (!obj.IsAvailable&&gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况 | |||
| if (!obj.IsAvailable && gameTimer.IsGaming) //不能动就直接return,后面都是能动的情况 | |||
| return; | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = true; | |||
| double moveVecLength = 0.0; | |||
| double deltaLen = moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); // 转向,并用deltaLen存储行走的误差 | |||
| IGameObj? collisionObj = null; | |||
| bool isDestroyed = false; | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting, | |||
| () => | |||
| { | |||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||
| bool flag; // 循环标志 | |||
| do | |||
| { | |||
| flag = false; | |||
| collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength)); | |||
| if (collisionObj == null) | |||
| break; | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = true; | |||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||
| double moveVecLength = 0.0; | |||
| double deltaLen = moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); // 转向,并用deltaLen存储行走的误差 | |||
| IGameObj? collisionObj = null; | |||
| bool isDestroyed = false; | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting, | |||
| () => | |||
| { | |||
| case AfterCollision.ContinueCheck: | |||
| flag = true; | |||
| break; | |||
| case AfterCollision.Destroyed: | |||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | |||
| isDestroyed = true; | |||
| return false; | |||
| case AfterCollision.MoveMax: | |||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||
| moveVecLength = 0; | |||
| break; | |||
| } | |||
| } while (flag); | |||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||
| deltaLen += moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); | |||
| return true; | |||
| }, | |||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||
| () => | |||
| { | |||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||
| bool flag; | |||
| do | |||
| { | |||
| flag = false; | |||
| if (!isDestroyed) | |||
| { | |||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||
| if ((collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength))) == null) | |||
| { | |||
| obj.Move(new XY(direction, moveVecLength)); | |||
| } | |||
| else | |||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||
| bool flag; // 循环标志 | |||
| do | |||
| { | |||
| flag = false; | |||
| collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength)); | |||
| if (collisionObj == null) | |||
| break; | |||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||
| { | |||
| case AfterCollision.ContinueCheck: | |||
| @@ -133,43 +96,81 @@ namespace GameEngine | |||
| case AfterCollision.Destroyed: | |||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | |||
| isDestroyed = true; | |||
| break; | |||
| return false; | |||
| case AfterCollision.MoveMax: | |||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||
| moveVecLength = 0; | |||
| break; | |||
| } | |||
| } while (flag); | |||
| deltaLen += moveVecLength - Math.Sqrt(obj.Move(new XY(direction, moveVecLength))); | |||
| return true; | |||
| }, | |||
| GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond, | |||
| () => | |||
| { | |||
| int leftTime = moveTime % (GameData.numOfPosGridPerCell / GameData.numOfStepPerSecond); | |||
| bool flag; | |||
| do | |||
| { | |||
| flag = false; | |||
| if (!isDestroyed) | |||
| { | |||
| moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell; | |||
| if ((collisionObj = collisionChecker.CheckCollision(obj, new XY(direction, moveVecLength))) == null) | |||
| { | |||
| obj.Move(new XY(direction, moveVecLength)); | |||
| } | |||
| else | |||
| { | |||
| switch (OnCollision(obj, collisionObj, new XY(direction, moveVecLength))) | |||
| { | |||
| case AfterCollision.ContinueCheck: | |||
| flag = true; | |||
| break; | |||
| case AfterCollision.Destroyed: | |||
| Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); | |||
| isDestroyed = true; | |||
| break; | |||
| case AfterCollision.MoveMax: | |||
| MoveMax(obj, new XY(direction, moveVecLength)); | |||
| moveVecLength = 0; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } while (flag); | |||
| if (leftTime > 0) | |||
| { | |||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||
| } | |||
| } | |||
| } while (flag); | |||
| if (leftTime > 0) | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = false; // 结束移动 | |||
| EndMove(obj); | |||
| return 0; | |||
| }, | |||
| maxTotalDuration: moveTime | |||
| ) | |||
| { | |||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||
| } | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = false; // 结束移动 | |||
| EndMove(obj); | |||
| return 0; | |||
| }, | |||
| maxTotalDuration: moveTime | |||
| ) { | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) | |||
| Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); | |||
| AllowTimeExceed = true, | |||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||
| TimeExceedAction = b => | |||
| { | |||
| if (b) | |||
| Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); | |||
| #if DEBUG | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: Object moving time exceed for once."); | |||
| } | |||
| else | |||
| { | |||
| Console.WriteLine("Debug info: Object moving time exceed for once."); | |||
| } | |||
| #endif | |||
| } | |||
| }.Start(); | |||
| } | |||
| }.Start(); | |||
| } | |||
| ).Start(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <TargetFramework>net6.0</TargetFramework> | |||
| <Nullable>enable</Nullable> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <ProjectReference Include="..\GameClass\GameClass.csproj" /> | |||
| <ProjectReference Include="..\GameEngine\GameEngine.csproj" /> | |||
| <ProjectReference Include="..\Preparation\Preparation.csproj" /> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -54,7 +54,8 @@ namespace Gaming | |||
| // ActivateMine((Character)obj, (Mine)collisionObj); | |||
| // return MoveEngine.AfterCollision.ContinueCheck; | |||
| //} | |||
| return MoveEngine.AfterCollision.MoveMax; }, | |||
| return MoveEngine.AfterCollision.MoveMax; | |||
| }, | |||
| EndMove: obj => | |||
| { | |||
| // Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| @@ -4,7 +4,7 @@ namespace Preparation.GameData | |||
| { | |||
| public static class GameData | |||
| { | |||
| #region 基本常数与常方法 | |||
| #region 基本常数与常方法 | |||
| public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 | |||
| public const int numOfStepPerSecond = 20; // 每秒行走的步数 | |||
| public const int lengthOfMap = 50000; // 地图长度 | |||
| @@ -33,8 +33,10 @@ namespace Preparation.GameData | |||
| { | |||
| return PosGridToCellX(pos1) == PosGridToCellX(pos2) && PosGridToCellY(pos1) == PosGridToCellY(pos2); | |||
| } | |||
| #endregion | |||
| #region 角色相关 | |||
| public static int numOfBirthPoint = 5; | |||
| #endregion | |||
| #region 角色相关 | |||
| /// <summary> | |||
| /// 玩家相关 | |||
| /// </summary> | |||
| @@ -69,9 +71,9 @@ namespace Preparation.GameData | |||
| public const long GemProduceTime = 10000; | |||
| public const long PropProduceTime = 10000; | |||
| public const int PropDuration = 10000; | |||
| #endregion | |||
| #region 游戏帧相关 | |||
| #endregion | |||
| #region 游戏帧相关 | |||
| public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | |||
| #endregion | |||
| #endregion | |||
| } | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| | |||
| namespace Preparation.Interface | |||
| { | |||
| public interface IOutOfBound : IGameObj | |||
| { | |||
| // 接口不定义内容,为引擎使用 | |||
| } | |||
| } | |||
| @@ -0,0 +1,11 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
| <PropertyGroup> | |||
| <OutputType>Library</OutputType> | |||
| <TargetFramework>net6.0</TargetFramework> | |||
| <ApplicationIcon /> | |||
| <StartupObject /> | |||
| <Nullable>enable</Nullable> | |||
| </PropertyGroup> | |||
| </Project> | |||
| @@ -35,8 +35,6 @@ namespace Preparation.Utility | |||
| Grass1 = 3, | |||
| Grass2 = 4, | |||
| Grass3 = 5, | |||
| Grass4 = 6, | |||
| Grass5 = 7, | |||
| } | |||
| public enum BulletType // 子弹类型 | |||
| { | |||
| @@ -93,3 +91,16 @@ namespace Preparation.Utility | |||
| PickedProp = 5 | |||
| } | |||
| } | |||
| public enum MapInfoObjType | |||
| { | |||
| Null = 0, | |||
| Wall = 1, | |||
| Grass1 = 2, | |||
| Grass2 = 3, | |||
| Grass3 = 4, | |||
| BirthPoint1 = 5, | |||
| BirthPoint2 = 6, | |||
| BirthPoint3 = 7, | |||
| BirthPoint4 = 8, | |||
| BirthPoint5 = 9, | |||
| } | |||
| @@ -21,7 +21,7 @@ namespace Preparation.Utility | |||
| { | |||
| return "(" + x.ToString() + "," + y.ToString() + ")"; | |||
| } | |||
| public static int operator*(XY v1, XY v2) | |||
| public static int operator *(XY v1, XY v2) | |||
| { | |||
| return (v1.x * v2.x) + (v1.y * v2.y); | |||
| } | |||
| @@ -8,11 +8,11 @@ | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="FrameRateTask" Version="1.1.2" /> | |||
| <PackageReference Include="Google.Protobuf" Version="3.21.9" /> | |||
| <PackageReference Include="FrameRateTask" Version="1.2.0" /> | |||
| <PackageReference Include="Google.Protobuf" Version="3.21.11" /> | |||
| <PackageReference Include="Grpc" Version="2.46.5" /> | |||
| <PackageReference Include="Grpc.Core" Version="2.46.5" /> | |||
| <PackageReference Include="Grpc.Tools" Version="2.50.0"> | |||
| <PackageReference Include="Grpc.Tools" Version="2.51.0"> | |||
| <PrivateAssets>all</PrivateAssets> | |||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||
| </PackageReference> | |||
| @@ -5,11 +5,17 @@ VisualStudioVersion = 17.0.32014.148 | |||
| MinimumVisualStudioVersion = 10.0.40219.1 | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}" | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameClass", "GameClass\GameClass.csproj", "{39D838F6-2B84-49E1-9CAF-1DFF22960B5D}" | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gaming", "Gaming\Gaming.csproj", "{BE9E3584-93C0-4E0F-8DAC-967CF4792709}" | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Preparation", "Preparation\Preparation.csproj", "{E3DC4A37-8A83-40CC-AE47-68E70064C9DB}" | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientTest", "ClientTest\ClientTest.csproj", "{F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}" | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protos", "..\dependency\proto\Protos.csproj", "{9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}" | |||
| EndProject | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameEngine", "GameEngine\GameEngine.csproj", "{C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}" | |||
| Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameEngine", "GameEngine\GameEngine.csproj", "{1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}" | |||
| EndProject | |||
| Global | |||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
| @@ -21,6 +27,18 @@ Global | |||
| {D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {D033B809-2FB7-4340-B8B4-DDA30D6CA6FF}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {39D838F6-2B84-49E1-9CAF-1DFF22960B5D}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {BE9E3584-93C0-4E0F-8DAC-967CF4792709}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {E3DC4A37-8A83-40CC-AE47-68E70064C9DB}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {F3C98717-DD4F-45B8-B0F0-C217E7E2B5D4}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| @@ -29,10 +47,10 @@ Global | |||
| {9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {9ADA1EF8-DF2F-4C2E-9DE2-BC94DF89B44D}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {C7A82045-5EE5-46E8-AD0C-04103EFEAF7E}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
| {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
| {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
| {1D1D07F3-C332-4407-AC1B-EAD73F8BB3F3}.Release|Any CPU.Build.0 = Release|Any CPU | |||
| EndGlobalSection | |||
| GlobalSection(SolutionProperties) = preSolution | |||
| HideSolutionNode = FALSE | |||