Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic Interprocess logic. #7

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading