Skip to content

Commit

Permalink
Implement basic Interprocess logic.
Browse files Browse the repository at this point in the history
  • Loading branch information
keyboardcrash32 committed Aug 4, 2024
1 parent 6e658af commit edaaf5f
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/SvenBXT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ void SvenBXT_Shutdown()

SvenBXT_UnhookEngine();
SvenBXT_UnhookClient();

Interprocess::Shutdown();

g_bHasLoaded = false;
}
Expand Down
20 changes: 20 additions & 0 deletions src/SvenBXT.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@
#define SVENBXT_VERSION __DATE__ // maybe something else? :thinking:
#define SVENBXT_GITHUB_URL "https://github.com/ScriptedSnark/SvenBXT"

// INTERPROCESS & SVENSPLIT
#define SVENSPLIT_PIPE_NAME "SvenBXT-SvenSplit"

enum class MessageType : unsigned char
{
TIME = 0x00,
EVENT = 0x01
};

enum class EventType : unsigned char
{
GAMEEND = 0x00,
MAPCHANGE = 0x01,
TIMER_RESET = 0x02,
TIMER_START = 0x03,
SS_ALEAPOFFAITH = 0x04
};

#include "interprocess.h"

// WINDOWS
#ifdef PLATFORM_WINDOWS
#include <windows.h>
Expand Down
3 changes: 3 additions & 0 deletions src/cl_dll/cdll_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ void CL_Initialize()
CreateHook(Client, V_CalcRefdef);
CreateHook(Client, HUD_VidInit);
CreateHook(Client, HUD_Redraw);

TRACE("Initializing interprocesses...\n");
Interprocess::Initialize();

TRACE("Initializing HUD...\n");
gBXTHud.Init();
Expand Down
12 changes: 11 additions & 1 deletion src/cl_dll/hud_timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ int __MsgFunc_BXTTimer(const char* pszName, int iSize, void* pbuf)
bool stop = READ_BYTE();

g_RTATimer.SyncTimer(time, stop);
Interprocess::WriteTime(Interprocess::GetTime());

return 0;
}
Expand All @@ -65,6 +66,9 @@ int CHudTimer::Init()
hud_timer_anchor = CVAR_CREATE("sbxt_hud_timer_anchor", "0.0 0.5", 0);
hud_timer_offset = CVAR_CREATE("sbxt_hud_timer_offset", "", 0);

svensplit_time_update_frequency = CVAR_CREATE("_sbxt_svensplit_time_update_frequency", "41", 0);
interprocess_enable = CVAR_CREATE("sbxt_interprocess_enable", "0", 0);

HOOK_COMMAND("sbxt_timer_start", TimerStart);
HOOK_COMMAND("sbxt_timer_stop", TimerStop);
HOOK_COMMAND("sbxt_timer_reset", TimerReset);
Expand All @@ -81,6 +85,8 @@ int CHudTimer::VidInit()

int CHudTimer::Draw(float time)
{
Interprocess::WriteTime(Interprocess::GetTime());

if (!hud_timer->value)
return 0;

Expand All @@ -91,7 +97,7 @@ int CHudTimer::Draw(float time)
int minutes = g_RTATimer.GetMinutes();
int seconds = g_RTATimer.GetSeconds();
int milliseconds = g_RTATimer.GetMilliseconds();

if (hud_timer->value == 1)
{
char rta_timer[64];
Expand Down Expand Up @@ -135,6 +141,8 @@ void CHudTimer::TimerStart()
g_RTATimer.StartTimer();
//g_IGTTimer.StartTimer();

Interprocess::WriteTimerStart(Interprocess::GetTime());

if (UTIL_IsHost())
{
SV_SyncTimer();
Expand All @@ -157,6 +165,8 @@ void CHudTimer::TimerReset()
g_RTATimer.ResetTimer();
//g_IGTTimer.ResetTimer();

Interprocess::WriteTimerReset(Interprocess::GetTime());

if (UTIL_IsHost())
{
SV_SyncTimer();
Expand Down
3 changes: 3 additions & 0 deletions src/cl_dll/hud_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class CHudTimer: public CBXTHudBase
bool ShouldSync() { return (hud_timer_serversync->value && !UTIL_IsHost()); }
bool IsInILMode() { return hud_timer_il_mode->value; };

cvar_t* svensplit_time_update_frequency;
cvar_t* interprocess_enable;

private:
cvar_t* hud_timer_serversync;
cvar_t* hud_timer_il_mode;
Expand Down
2 changes: 2 additions & 0 deletions src/dlls/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ void FASTCALL HOOKED_CNihilanth_DyingThink(void* thisptr)
{
g_lpHUDTimer->TimerStop();

Interprocess::WriteGameEnd(Interprocess::GetTime());

ORIG_CNihilanth_DyingThink(thisptr);
}

Expand Down
235 changes: 235 additions & 0 deletions src/interprocess.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#include "interprocess.h"
#include <windows.h>
#include "Utils.h"
#include "SvenBXT.h"
#include "cl_dll/hud_timer.h"

namespace Interprocess
{
static HANDLE pipe_SvenSplit = INVALID_HANDLE_VALUE;
static OVERLAPPED overlapped;
static bool writing_to_pipe;

static void InitSvenSplitPipe()
{
pipe_SvenSplit = CreateNamedPipe(
"\\\\.\\pipe\\" SVENSPLIT_PIPE_NAME,
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_REJECT_REMOTE_CLIENTS,
1,
256 * 1000,
0,
0,
NULL);
if (pipe_SvenSplit == INVALID_HANDLE_VALUE)
{
Sys_Printf("Error opening the SvenSplit pipe: %d\n", GetLastError());
Sys_Printf("SvenSplit integration is not available.\n");
return;
}
Sys_Printf("Opened the SvenSplit pipe.\n");

std::memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (overlapped.hEvent == NULL)
{
Sys_Printf("Error creating an event for overlapped: %d. Closing the SvenSplit pipe.\n", GetLastError());
Sys_Printf("SvenSplit integration is not available.\n");
CloseHandle(pipe_SvenSplit);
pipe_SvenSplit = INVALID_HANDLE_VALUE;
}
}

void Initialize()
{
InitSvenSplitPipe();
}

static void ShutdownSvenSplitPipe()
{
if (pipe_SvenSplit != INVALID_HANDLE_VALUE)
{
CloseHandle(pipe_SvenSplit);
Sys_Printf("Closed the SvenSplit pipe.\n");
}
pipe_SvenSplit = INVALID_HANDLE_VALUE;

CloseHandle(overlapped.hEvent);
std::memset(&overlapped, 0, sizeof(overlapped));
}

void Shutdown()
{
ShutdownSvenSplitPipe();
}

static void WriteSvenSplit(const std::vector<char>& data)
{
if (pipe_SvenSplit == INVALID_HANDLE_VALUE)
return;

if (writing_to_pipe)
{
if (WaitForSingleObject(overlapped.hEvent, INFINITE) != WAIT_OBJECT_0)
{
// Some weird error?
Sys_Printf("WaitForSingleObject failed with %d.\n", GetLastError());
DisconnectNamedPipe(pipe_SvenSplit);
return WriteSvenSplit(data);
}
writing_to_pipe = false;
}

if (!ConnectNamedPipe(pipe_SvenSplit, &overlapped))
{
auto err = GetLastError();
if (err == ERROR_NO_DATA)
{
// Client has disconnected.
DisconnectNamedPipe(pipe_SvenSplit);
return WriteSvenSplit(data);
}
else if (err == ERROR_IO_PENDING)
{
// Waiting for someone to connect.
return;
}
else if (err != ERROR_PIPE_CONNECTED)
{
// Some weird error with pipe?
// Try remaking it.
Sys_Printf("ConnectNamedPipe failed with %d.\n", err);
ShutdownSvenSplitPipe();
InitSvenSplitPipe();
return WriteSvenSplit(data);
}
}

if (!WriteFile(pipe_SvenSplit, data.data(), data.size(), NULL, &overlapped))
{
auto err = GetLastError();
if (err == ERROR_IO_PENDING)
{
// Started writing.
writing_to_pipe = true;
return;
}
else
{
Sys_Printf("WriteFile failed with %d.\n", err);
DisconnectNamedPipe(pipe_SvenSplit);
return;
}
}
}

static size_t AddTimeToBuffer(char* buf, const Time& time)
{
std::memcpy(buf, &time.hours, sizeof(time.hours));
std::memcpy(buf + sizeof(time.hours), &time.minutes, sizeof(time.minutes));
std::memcpy(buf + sizeof(time.hours) + sizeof(time.minutes), &time.seconds, sizeof(time.seconds));
std::memcpy(buf + sizeof(time.hours) + sizeof(time.minutes) + sizeof(time.seconds), &time.milliseconds, sizeof(time.milliseconds));
return sizeof(time.hours) + sizeof(time.minutes) + sizeof(time.seconds) + sizeof(time.milliseconds);
}

void WriteTime(const Time& time)
{
if (!g_lpHUDTimer->interprocess_enable->value)
return;

std::vector<char> buf(10);
buf[0] = static_cast<char>(buf.size());
buf[1] = static_cast<char>(MessageType::TIME);
AddTimeToBuffer(buf.data() + 2, time);

if (g_lpHUDTimer->svensplit_time_update_frequency->value > 0.0f)
{
static auto last_time = std::chrono::steady_clock::now() - std::chrono::milliseconds(static_cast<long long>(1000 / g_lpHUDTimer->svensplit_time_update_frequency->value) + 1);
auto now = std::chrono::steady_clock::now();
if (now >= last_time + std::chrono::milliseconds(static_cast<long long>(1000 / g_lpHUDTimer->svensplit_time_update_frequency->value)))
{
WriteSvenSplit(buf);
last_time = now;
}
}
else
{
WriteSvenSplit(buf);
}
}

void WriteGameEnd(const Time& time)
{
std::vector<char> buf(11);
buf[0] = static_cast<char>(buf.size());
buf[1] = static_cast<char>(MessageType::EVENT);
buf[2] = static_cast<char>(EventType::GAMEEND);
AddTimeToBuffer(buf.data() + 3, time);

WriteSvenSplit(buf);
}

void WriteMapChange(const Time& time, const std::string& map)
{
int32_t size = static_cast<int32_t>(map.size());

std::vector<char> buf(15 + size);
buf[0] = static_cast<char>(buf.size());
buf[1] = static_cast<char>(MessageType::EVENT);
buf[2] = static_cast<char>(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);

WriteSvenSplit(buf);
}

void WriteTimerReset(const Time& time)
{
std::vector<char> buf(11);
buf[0] = static_cast<char>(buf.size());
buf[1] = static_cast<char>(MessageType::EVENT);
buf[2] = static_cast<char>(EventType::TIMER_RESET);
AddTimeToBuffer(buf.data() + 3, time);

WriteSvenSplit(buf);
}

void WriteTimerStart(const Time& time)
{
std::vector<char> buf(11);
buf[0] = static_cast<char>(buf.size());
buf[1] = static_cast<char>(MessageType::EVENT);
buf[2] = static_cast<char>(EventType::TIMER_START);
AddTimeToBuffer(buf.data() + 3, time);

WriteSvenSplit(buf);
}

void WriteSSALeapOfFaith(const Time& time)
{
std::vector<char> buf(11);
buf[0] = static_cast<char>(buf.size());
buf[1] = static_cast<char>(MessageType::EVENT);
buf[2] = static_cast<char>(EventType::SS_ALEAPOFFAITH);
AddTimeToBuffer(buf.data() + 3, time);

WriteSvenSplit(buf);
}

Interprocess::Time GetTime()
{
int hours = g_RTATimer.GetHours();
int minutes = g_RTATimer.GetMinutes();
int seconds = g_RTATimer.GetSeconds();
int milliseconds = g_RTATimer.GetMilliseconds();

return Interprocess::Time{
static_cast<uint32_t>(hours),
static_cast<uint8_t>(minutes),
static_cast<uint8_t>(seconds),
static_cast<uint16_t>(milliseconds)
};
}
}
30 changes: 30 additions & 0 deletions src/interprocess.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef INTERPROCESS_H_INCLUDED
#define INTERPROCESS_H_INCLUDED

#include <vector>
#include <string>

namespace Interprocess
{
struct Time
{
uint32_t hours;
uint8_t minutes;
uint8_t seconds;
uint16_t milliseconds;
};

void Initialize();
void Shutdown();

void WriteTime(const Time& time);

void WriteGameEnd(const Time& time);
void WriteMapChange(const Time& time, const std::string& map);
void WriteTimerReset(const Time& time);
void WriteTimerStart(const Time& time);
void WriteSSALeapOfFaith(const Time& time);
Time GetTime();
}

#endif // INTERPROCESS_H_INCLUDED

0 comments on commit edaaf5f

Please sign in to comment.