diff --git a/BunnymodXT/Linux/interprocess.cpp b/BunnymodXT/Linux/interprocess.cpp index c210b803..e07bbe9b 100644 --- a/BunnymodXT/Linux/interprocess.cpp +++ b/BunnymodXT/Linux/interprocess.cpp @@ -8,6 +8,7 @@ namespace Interprocess { mqd_t mq = static_cast(-1); + mqd_t mq_bunnysplit = static_cast(-1); void Initialize() { @@ -62,13 +63,25 @@ namespace Interprocess void WriteTime(const Time& time) { - if (!CVars::bxt_interprocess_enable.GetBool()) - return; - std::vector buf(10); buf[0] = static_cast(buf.size()); buf[1] = static_cast(MessageType::TIME); AddTimeToBuffer(buf.data() + 2, time); + + if (CVars::_bxt_bunnysplit_time_update_frequency.GetFloat() > 0.0f) { + auto ms = static_cast(1000 / CVars::_bxt_bunnysplit_time_update_frequency.GetFloat()); + static auto last_time = std::chrono::steady_clock::now() - std::chrono::milliseconds(ms + 1); + auto now = std::chrono::steady_clock::now(); + if (now >= last_time + std::chrono::milliseconds(ms)) { + WriteBunnySplit(buf); + last_time = now; + } + } else { + WriteBunnySplit(buf); + } + + if (!CVars::bxt_interprocess_enable.GetBool()) + return; Write(buf); } @@ -110,21 +123,103 @@ namespace Interprocess void WriteGameEnd(const Time& time) { + std::vector buf(11); + buf[0] = static_cast(buf.size()); + buf[1] = static_cast(MessageType::EVENT); + buf[2] = static_cast(EventType::GAMEEND); + AddTimeToBuffer(buf.data() + 3, time); + + WriteBunnySplit(buf); } void WriteMapChange(const Time& time, const std::string& map) { + int32_t size = static_cast(map.size()); + + std::vector buf(15 + size); + buf[0] = static_cast(buf.size()); + buf[1] = static_cast(MessageType::EVENT); + buf[2] = static_cast(EventType::MAPCHANGE); + auto time_size = AddTimeToBuffer(buf.data() + 3, time); + + std::memcpy(buf.data() + 3 + time_size, &size, sizeof(size)); + std::memcpy(buf.data() + 3 + time_size + 4, map.data(), size); + + WriteBunnySplit(buf); } void WriteTimerReset(const Time& time) { + std::vector buf(11); + buf[0] = static_cast(buf.size()); + buf[1] = static_cast(MessageType::EVENT); + buf[2] = static_cast(EventType::TIMER_RESET); + AddTimeToBuffer(buf.data() + 3, time); + + WriteBunnySplit(buf); } void WriteTimerStart(const Time& time) { + std::vector buf(11); + buf[0] = static_cast(buf.size()); + buf[1] = static_cast(MessageType::EVENT); + buf[2] = static_cast(EventType::TIMER_START); + AddTimeToBuffer(buf.data() + 3, time); + + WriteBunnySplit(buf); } void WriteBSALeapOfFaith(const Time& time) { + std::vector buf(11); + buf[0] = static_cast(buf.size()); + buf[1] = static_cast(MessageType::EVENT); + buf[2] = static_cast(EventType::BS_ALEAPOFFAITH); + AddTimeToBuffer(buf.data() + 3, time); + + WriteBunnySplit(buf); + } + + void InitBunnySplitPipe() + { + mq_bunnysplit = mq_open( + "/" BUNNYSPLIT_MQ_NAME, + O_WRONLY | O_CREAT | O_NONBLOCK, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, + nullptr); + + if (mq_bunnysplit == static_cast(-1)) { + EngineDevWarning("Error opening the BunnySplit message queue: %s\n", strerror(errno)); + EngineWarning("BunnySplit integration is not available.\n"); + return; + } + + EngineDevMsg("Opened the BunnySplit message queue.\n"); + } + + void ShutdownBunnySplitPipe() + { + if (mq_bunnysplit != static_cast(-1)) { + mq_close(mq_bunnysplit); + mq_unlink("/" BUNNYSPLIT_MQ_NAME); + EngineDevMsg("Closed the BunnySplit message queue.\n"); + } + + mq_bunnysplit = static_cast(-1); + } + + void WriteBunnySplit(const std::vector& data) + { + if (mq_bunnysplit == static_cast(-1)) + return; + + if (mq_send(mq_bunnysplit, data.data(), data.size(), 0) == -1) { + // This shouldn't really happen. + // Perhaps the message queue was force-deleted or something. + EngineDevWarning("[mq_bunnysplit] mq_send failed with %d (%s).\n", errno, strerror(errno)); + ShutdownBunnySplitPipe(); + InitBunnySplitPipe(); + } } } diff --git a/BunnymodXT/Linux/main_linux.cpp b/BunnymodXT/Linux/main_linux.cpp index d865b341..f4826ba3 100644 --- a/BunnymodXT/Linux/main_linux.cpp +++ b/BunnymodXT/Linux/main_linux.cpp @@ -94,6 +94,7 @@ static __attribute__((constructor(1337))) void Construct() _EngineDevWarning = PrintDevWarning; Interprocess::Initialize(); + Interprocess::InitBunnySplitPipe(); Hooks::AddToHookedModules(&HwDLL::GetInstance()); Hooks::AddToHookedModules(&ClientDLL::GetInstance()); @@ -111,4 +112,5 @@ static __attribute__((destructor(1337))) void Destruct() fclose(logfile); Interprocess::Shutdown(); + Interprocess::ShutdownBunnySplitPipe(); } diff --git a/BunnymodXT/Windows/interprocess.cpp b/BunnymodXT/Windows/interprocess.cpp index 0c17e94f..d9c17472 100644 --- a/BunnymodXT/Windows/interprocess.cpp +++ b/BunnymodXT/Windows/interprocess.cpp @@ -188,9 +188,10 @@ namespace Interprocess AddTimeToBuffer(buf.data() + 2, time); if (CVars::_bxt_bunnysplit_time_update_frequency.GetFloat() > 0.0f) { - static auto last_time = std::chrono::steady_clock::now() - std::chrono::milliseconds(static_cast(1000 / CVars::_bxt_bunnysplit_time_update_frequency.GetFloat()) + 1); + auto ms = static_cast(1000 / CVars::_bxt_bunnysplit_time_update_frequency.GetFloat()); + static auto last_time = std::chrono::steady_clock::now() - std::chrono::milliseconds(ms + 1); auto now = std::chrono::steady_clock::now(); - if (now >= last_time + std::chrono::milliseconds(static_cast(1000 / CVars::_bxt_bunnysplit_time_update_frequency.GetFloat()))) { + if (now >= last_time + std::chrono::milliseconds(ms)) { WriteBunnySplit(buf); last_time = now; } diff --git a/BunnymodXT/interprocess.hpp b/BunnymodXT/interprocess.hpp index 52219da5..7fcbbd03 100644 --- a/BunnymodXT/interprocess.hpp +++ b/BunnymodXT/interprocess.hpp @@ -24,4 +24,10 @@ namespace Interprocess void WriteTimerReset(const Time& time); void WriteTimerStart(const Time& time); void WriteBSALeapOfFaith(const Time& time); + +#ifndef _WIN32 + void InitBunnySplitPipe(); + void ShutdownBunnySplitPipe(); + void WriteBunnySplit(const std::vector& data); +#endif } diff --git a/BunnymodXT/shared.hpp b/BunnymodXT/shared.hpp index 6da72682..d7b04d10 100644 --- a/BunnymodXT/shared.hpp +++ b/BunnymodXT/shared.hpp @@ -18,3 +18,4 @@ enum class EventType : unsigned char { #define MQ_NAME "BunnymodXT-TASView" #define BUNNYSPLIT_PIPE_NAME "BunnymodXT-BunnySplit" +#define BUNNYSPLIT_MQ_NAME "BunnymodXT-BunnySplit"