From ad7c3e616fdc6f13812ec52675d226a19351494a Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Tue, 17 Dec 2024 15:40:19 -0500 Subject: Added getting player position from IPC --- src/ipc_state.cpp | 231 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 src/ipc_state.cpp (limited to 'src/ipc_state.cpp') diff --git a/src/ipc_state.cpp b/src/ipc_state.cpp new file mode 100644 index 0000000..18f318f --- /dev/null +++ b/src/ipc_state.cpp @@ -0,0 +1,231 @@ +#include "ipc_state.h" + +#define _WEBSOCKETPP_CPP11_STRICT_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logger.h" +#include "tracker_frame.h" + +namespace { + +constexpr const char* kIpcAddress = "ws://127.0.0.1:41253"; + +struct IPCState { + std::mutex state_mutex; + TrackerFrame* tracker_frame = nullptr; + + // Protected state + std::optional status_message; + + bool slot_matches = false; + std::string tracker_ap_server; + std::string tracker_ap_user; + std::string game_ap_server; + std::string game_ap_user; + + std::optional> player_position; + + int backoff_amount = 0; + + // Thread state + std::unique_ptr ws; + bool connected = false; + + void Start(TrackerFrame* frame) { + tracker_frame = frame; + + std::thread([this]() { Thread(); }).detach(); + } + + std::optional GetStatusMessage() { + std::lock_guard state_guard(state_mutex); + + return status_message; + } + + void SetTrackerSlot(std::string server, std::string user) { + std::lock_guard state_guard(state_mutex); + + tracker_ap_server = std::move(server); + tracker_ap_user = std::move(user); + + CheckIfSlotMatches(); + + backoff_amount = 0; + } + + bool IsConnected() { + std::lock_guard state_guard(state_mutex); + + return slot_matches; + } + + std::optional> GetPlayerPosition() { + std::lock_guard state_guard(state_mutex); + + return player_position; + } + + private: + void Thread() { + for (;;) { + player_position = std::nullopt; + + TrackerLog("Looking for game over IPC..."); + + { + std::lock_guard state_guard(state_mutex); + backoff_amount = 0; + } + + while (!TryConnect() || !connected) { + int backoff_limit; + { + std::lock_guard state_guard(state_mutex); + backoff_limit = (backoff_amount + 1) * 10; + } + + for (int i = 0; i < backoff_limit && !connected; i++) { + ws->poll(); + + // Back off + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + { + std::lock_guard state_guard(state_mutex); + backoff_amount = std::min(9, backoff_amount + 1); + + if (!connected) { + TrackerLog(fmt::format("Retrying IPC in {} second(s)...", + backoff_amount + 1)); + } + } + } + + while (connected) { + ws->poll(); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + SetStatusMessage("Disconnected from game."); + } + } + + bool TryConnect() { + try { + ws = std::make_unique( + kIpcAddress, [this]() { OnConnect(); }, [this]() { OnClose(); }, + [this](const std::string& s) { OnMessage(s); }, + [this](const std::string& s) { OnError(s); }); + return true; + } catch (const std::exception& ex) { + ws.reset(); + return false; + } + } + + void OnConnect() { connected = true; } + + void OnClose() { + connected = false; + + { + std::lock_guard state_guard(state_mutex); + + slot_matches = false; + } + } + + void OnMessage(const std::string& s) { + TrackerLog(s); + + auto msg = nlohmann::json::parse(s); + + if (msg["cmd"] == "Connect") { + std::lock_guard state_guard(state_mutex); + + game_ap_server = msg["slot"]["server"]; + game_ap_user = msg["slot"]["player"]; + + CheckIfSlotMatches(); + } else if (msg["cmd"] == "UpdatePosition") { + std::lock_guard state_guard(state_mutex); + + player_position = + std::make_tuple(msg["position"]["x"], msg["position"]["z"]); + + tracker_frame->RedrawPosition(); + } + } + + void OnError(const std::string& s) {} + + void CheckIfSlotMatches() { + slot_matches = (tracker_ap_server == game_ap_server && + tracker_ap_user == game_ap_user); + + if (slot_matches) { + status_message = "Connected to game."; + + Sync(); + } else if (tracker_ap_server.empty()) { + status_message = std::nullopt; + } else if (connected) { + status_message = "Local game doesn't match AP slot."; + } + + tracker_frame->UpdateStatusMessage(); + } + + void SetStatusMessage(std::optional msg) { + { + std::lock_guard state_guard(state_mutex); + status_message = msg; + } + + tracker_frame->UpdateStatusMessage(); + } + + void Sync() { + nlohmann::json msg; + msg["cmd"] = "Sync"; + + ws->send_text(msg.dump()); + } +}; + +IPCState& GetState() { + static IPCState* instance = new IPCState(); + return *instance; +} + +} // namespace + +void IPC_Start(TrackerFrame* tracker_frame) { GetState().Start(tracker_frame); } + +std::optional IPC_GetStatusMessage() { + return GetState().GetStatusMessage(); +} + +void IPC_SetTrackerSlot(std::string server, std::string user) { + GetState().SetTrackerSlot(server, user); +} + +bool IPC_IsConnected() { return GetState().IsConnected(); } + +std::optional> IPC_GetPlayerPosition() { + return GetState().GetPlayerPosition(); +} -- cgit 1.4.1