IPCPipe implemented for inter-process-communication.
This commit is contained in:
parent
75db36aba9
commit
fb8aa17ab1
@ -7,6 +7,7 @@ namespace Components
|
|||||||
void Loader::Initialize()
|
void Loader::Initialize()
|
||||||
{
|
{
|
||||||
Loader::Register(new Dedicated());
|
Loader::Register(new Dedicated());
|
||||||
|
Loader::Register(new Singleton());
|
||||||
|
|
||||||
Loader::Register(new Dvar());
|
Loader::Register(new Dvar());
|
||||||
Loader::Register(new Maps());
|
Loader::Register(new Maps());
|
||||||
@ -18,6 +19,7 @@ namespace Components
|
|||||||
Loader::Register(new Window());
|
Loader::Register(new Window());
|
||||||
Loader::Register(new Command());
|
Loader::Register(new Command());
|
||||||
Loader::Register(new Console());
|
Loader::Register(new Console());
|
||||||
|
Loader::Register(new IPCPipe());
|
||||||
Loader::Register(new Network());
|
Loader::Register(new Network());
|
||||||
Loader::Register(new RawFiles());
|
Loader::Register(new RawFiles());
|
||||||
Loader::Register(new Renderer());
|
Loader::Register(new Renderer());
|
||||||
@ -25,7 +27,6 @@ namespace Components
|
|||||||
Loader::Register(new UIScript());
|
Loader::Register(new UIScript());
|
||||||
Loader::Register(new FastFiles());
|
Loader::Register(new FastFiles());
|
||||||
Loader::Register(new Materials());
|
Loader::Register(new Materials());
|
||||||
Loader::Register(new Singleton());
|
|
||||||
Loader::Register(new FileSystem());
|
Loader::Register(new FileSystem());
|
||||||
Loader::Register(new QuickPatch());
|
Loader::Register(new QuickPatch());
|
||||||
Loader::Register(new ServerList());
|
Loader::Register(new ServerList());
|
||||||
|
@ -29,6 +29,7 @@ namespace Components
|
|||||||
#include "Modules\Window.hpp"
|
#include "Modules\Window.hpp"
|
||||||
#include "Modules\Command.hpp"
|
#include "Modules\Command.hpp"
|
||||||
#include "Modules\Console.hpp"
|
#include "Modules\Console.hpp"
|
||||||
|
#include "Modules\IPCPipe.hpp"
|
||||||
#include "Modules\Network.hpp"
|
#include "Modules\Network.hpp"
|
||||||
#include "Modules\Party.hpp" // Destroys the order, but requires network classes :D
|
#include "Modules\Party.hpp" // Destroys the order, but requires network classes :D
|
||||||
#include "Modules\RawFiles.hpp"
|
#include "Modules\RawFiles.hpp"
|
||||||
|
@ -4,6 +4,8 @@ namespace Components
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConnectProtocol();
|
ConnectProtocol();
|
||||||
|
const char* GetName() { return "ConnectProtocol"; };
|
||||||
|
|
||||||
void EvaluateProtocol();
|
void EvaluateProtocol();
|
||||||
static BOOL InvokeConnect();
|
static BOOL InvokeConnect();
|
||||||
|
|
||||||
|
251
src/Components/Modules/IPCPipe.cpp
Normal file
251
src/Components/Modules/IPCPipe.cpp
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
#include "..\..\STDInclude.hpp"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
Pipe* IPCPipe::ServerPipe = 0;
|
||||||
|
Pipe* IPCPipe::ClientPipe = 0;
|
||||||
|
|
||||||
|
#pragma region Pipe
|
||||||
|
|
||||||
|
Pipe::Pipe() : mType(IPCTYPE_NONE), ReconnectAttempt(0), hPipe(INVALID_HANDLE_VALUE), mThread(0), ConnectCallback(0), mThreadAttached(false)
|
||||||
|
{
|
||||||
|
this->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipe::~Pipe()
|
||||||
|
{
|
||||||
|
this->Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pipe::Connect(std::string name)
|
||||||
|
{
|
||||||
|
this->Destroy();
|
||||||
|
|
||||||
|
this->mType = IPCTYPE_CLIENT;
|
||||||
|
this->SetName(name);
|
||||||
|
|
||||||
|
this->hPipe = CreateFile(this->PipeFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
|
||||||
|
if (INVALID_HANDLE_VALUE == this->hPipe)
|
||||||
|
{
|
||||||
|
Logger::Print("Failed to connect to the pipe\n");
|
||||||
|
|
||||||
|
if (this->ReconnectAttempt < IPC_MAX_RECONNECTS)
|
||||||
|
{
|
||||||
|
Logger::Print("Attempting to reconnect to the pipe.\n");
|
||||||
|
this->ReconnectAttempt++;
|
||||||
|
Sleep(500);
|
||||||
|
|
||||||
|
return this->Connect(name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->Destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->ReconnectAttempt = 0;
|
||||||
|
Logger::Print("Successfully connected to the pipe\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pipe::Create(std::string name)
|
||||||
|
{
|
||||||
|
this->Destroy();
|
||||||
|
|
||||||
|
this->mType = IPCTYPE_SERVER;
|
||||||
|
this->SetName(name);
|
||||||
|
|
||||||
|
this->hPipe = CreateNamedPipe(this->PipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->mPacket), sizeof(this->mPacket), NMPWAIT_USE_DEFAULT_WAIT, NULL);
|
||||||
|
|
||||||
|
if (INVALID_HANDLE_VALUE != this->hPipe)
|
||||||
|
{
|
||||||
|
this->mThreadAttached = true;
|
||||||
|
this->mThread = new std::thread(this->ReceiveThread, this);
|
||||||
|
Logger::Print("Pipe successfully created\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Print("Failed to create the pipe\n");
|
||||||
|
this->Destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipe::OnConnect(Pipe::Callback callback)
|
||||||
|
{
|
||||||
|
this->ConnectCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipe::SetCallback(std::string command, Pipe::PacketCallback callback)
|
||||||
|
{
|
||||||
|
this->PacketCallbacks[command] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Pipe::Write(std::string command, std::string data)
|
||||||
|
{
|
||||||
|
if (this->mType != IPCTYPE_CLIENT || this->hPipe == INVALID_HANDLE_VALUE) return false;
|
||||||
|
|
||||||
|
Pipe::Packet packet;
|
||||||
|
strcpy_s(packet.Command, command.data());
|
||||||
|
strcpy_s(packet.Buffer, data.data());
|
||||||
|
|
||||||
|
DWORD cbBytes;
|
||||||
|
return (WriteFile(this->hPipe, &packet, sizeof(packet), &cbBytes, NULL) || GetLastError() == ERROR_IO_PENDING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipe::Destroy()
|
||||||
|
{
|
||||||
|
//this->Type = IPCTYPE_NONE;
|
||||||
|
|
||||||
|
//*this->PipeFile = 0;
|
||||||
|
//*this->PipeName = 0;
|
||||||
|
|
||||||
|
if (INVALID_HANDLE_VALUE != this->hPipe)
|
||||||
|
{
|
||||||
|
if (this->mType == IPCTYPE_SERVER) DisconnectNamedPipe(this->hPipe);
|
||||||
|
|
||||||
|
CloseHandle(this->hPipe);
|
||||||
|
Logger::Print("Disconnected from the pipe.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->mThreadAttached = false;
|
||||||
|
|
||||||
|
if (this->mThread)
|
||||||
|
{
|
||||||
|
Logger::Print("Terminating pipe thread...\n");
|
||||||
|
|
||||||
|
this->mThread->join();
|
||||||
|
|
||||||
|
Logger::Print("Pipe thread terminated.\n");
|
||||||
|
|
||||||
|
delete this->mThread;
|
||||||
|
|
||||||
|
this->mThread = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipe::SetName(std::string name)
|
||||||
|
{
|
||||||
|
memset(this->PipeName, 0, sizeof(this->PipeName));
|
||||||
|
memset(this->PipeFile, 0, sizeof(this->PipeFile));
|
||||||
|
|
||||||
|
strncpy_s(this->PipeName, name.c_str(), sizeof(this->PipeName));
|
||||||
|
sprintf_s(this->PipeFile, sizeof(this->PipeFile), "\\\\.\\Pipe\\%s", this->PipeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pipe::ReceiveThread(Pipe* pipe)
|
||||||
|
{
|
||||||
|
if (!pipe || pipe->mType != IPCTYPE_SERVER || pipe->hPipe == INVALID_HANDLE_VALUE) return;
|
||||||
|
|
||||||
|
if (ConnectNamedPipe(pipe->hPipe, NULL) == FALSE)
|
||||||
|
{
|
||||||
|
Logger::Print("Failed to initialize pipe reading.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Print("Client connected to the pipe\n");
|
||||||
|
if (pipe->ConnectCallback) pipe->ConnectCallback();
|
||||||
|
|
||||||
|
DWORD cbBytes;
|
||||||
|
|
||||||
|
while (pipe->mThreadAttached && pipe->hPipe != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
BOOL bResult = ReadFile(pipe->hPipe, &pipe->mPacket, sizeof(pipe->mPacket), &cbBytes, NULL);
|
||||||
|
|
||||||
|
if (bResult && cbBytes)
|
||||||
|
{
|
||||||
|
if (pipe->PacketCallbacks.find(pipe->mPacket.Command) != pipe->PacketCallbacks.end())
|
||||||
|
{
|
||||||
|
pipe->PacketCallbacks[pipe->mPacket.Command](pipe->mPacket.Buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pipe->mThreadAttached && pipe->hPipe != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
Logger::Print("Failed to read from client through pipe\n");
|
||||||
|
|
||||||
|
DisconnectNamedPipe(pipe->hPipe);
|
||||||
|
ConnectNamedPipe(pipe->hPipe, NULL);
|
||||||
|
if (pipe->ConnectCallback) pipe->ConnectCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory(&pipe->mPacket, sizeof(pipe->mPacket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
// Callback to connect first instance's client pipe to the second instance's server pipe
|
||||||
|
void IPCPipe::ConnectClient()
|
||||||
|
{
|
||||||
|
if (Singleton::IsFirstInstance() && IPCPipe::ClientPipe)
|
||||||
|
{
|
||||||
|
IPCPipe::ClientPipe->Connect(IPC_PIPE_NAME_CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes to the process on the other end of the pipe
|
||||||
|
bool IPCPipe::Write(std::string command, std::string data)
|
||||||
|
{
|
||||||
|
if (IPCPipe::ClientPipe)
|
||||||
|
{
|
||||||
|
return IPCPipe::ClientPipe->Write(command, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Installs a callback for receiving commands from the process on the other end of the pipe
|
||||||
|
void IPCPipe::On(std::string command, Pipe::PacketCallback callback)
|
||||||
|
{
|
||||||
|
if (IPCPipe::ServerPipe)
|
||||||
|
{
|
||||||
|
IPCPipe::ServerPipe->SetCallback(command, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCPipe::IPCPipe()
|
||||||
|
{
|
||||||
|
// Server pipe
|
||||||
|
IPCPipe::ServerPipe = new Pipe();
|
||||||
|
IPCPipe::ServerPipe->OnConnect(IPCPipe::ConnectClient);
|
||||||
|
IPCPipe::ServerPipe->Create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT));
|
||||||
|
|
||||||
|
// Client pipe
|
||||||
|
IPCPipe::ClientPipe = new Pipe();
|
||||||
|
|
||||||
|
// Connect second instance's client pipe to first instance's server pipe
|
||||||
|
if (!Singleton::IsFirstInstance())
|
||||||
|
{
|
||||||
|
IPCPipe::ClientPipe->Connect(IPC_PIPE_NAME_SERVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCPipe::On("ping", [] (std::string data)
|
||||||
|
{
|
||||||
|
Logger::Print("Received ping form pipe, sending pong!\n");
|
||||||
|
IPCPipe::Write("pong", data);
|
||||||
|
});
|
||||||
|
|
||||||
|
IPCPipe::On("pong", [] (std::string data)
|
||||||
|
{
|
||||||
|
Logger::Print("Received pong form pipe!\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test pipe functionality by sending pings
|
||||||
|
Command::Add("ipcping", [] (Command::Params params)
|
||||||
|
{
|
||||||
|
Logger::Print("Sending ping to pipe!\n");
|
||||||
|
IPCPipe::Write("ping", "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
IPCPipe::~IPCPipe()
|
||||||
|
{
|
||||||
|
if (IPCPipe::ServerPipe) delete IPCPipe::ServerPipe;
|
||||||
|
if (IPCPipe::ClientPipe) delete IPCPipe::ClientPipe;
|
||||||
|
|
||||||
|
IPCPipe::ServerPipe = 0;
|
||||||
|
IPCPipe::ClientPipe = 0;
|
||||||
|
}
|
||||||
|
}
|
76
src/Components/Modules/IPCPipe.hpp
Normal file
76
src/Components/Modules/IPCPipe.hpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#define IPC_MAX_RECONNECTS 3
|
||||||
|
#define IPC_COMMAND_SIZE 100
|
||||||
|
#define IPC_BUFFER_SIZE 0x2000
|
||||||
|
|
||||||
|
#define IPC_PIPE_NAME_SERVER "IW4x-Server"
|
||||||
|
#define IPC_PIPE_NAME_CLIENT "IW4x-Client"
|
||||||
|
|
||||||
|
namespace Components
|
||||||
|
{
|
||||||
|
class Pipe
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Packet
|
||||||
|
{
|
||||||
|
char Command[IPC_COMMAND_SIZE];
|
||||||
|
char Buffer[IPC_BUFFER_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
IPCTYPE_NONE,
|
||||||
|
IPCTYPE_SERVER,
|
||||||
|
IPCTYPE_CLIENT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void(__cdecl* PacketCallback)(std::string data);
|
||||||
|
typedef void(__cdecl* Callback)();
|
||||||
|
|
||||||
|
Pipe();
|
||||||
|
~Pipe();
|
||||||
|
|
||||||
|
bool Connect(std::string name);
|
||||||
|
bool Create(std::string name);
|
||||||
|
|
||||||
|
bool Write(std::string command, std::string data);
|
||||||
|
void SetCallback(std::string command, PacketCallback callback);
|
||||||
|
void OnConnect(Callback callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Callback ConnectCallback;
|
||||||
|
std::map<std::string, PacketCallback> PacketCallbacks;
|
||||||
|
|
||||||
|
HANDLE hPipe;
|
||||||
|
std::thread* mThread;
|
||||||
|
bool mThreadAttached;
|
||||||
|
|
||||||
|
Type mType;
|
||||||
|
Packet mPacket;
|
||||||
|
|
||||||
|
char PipeName[MAX_PATH];
|
||||||
|
char PipeFile[MAX_PATH];
|
||||||
|
unsigned int ReconnectAttempt;
|
||||||
|
|
||||||
|
void Destroy();
|
||||||
|
void SetName(std::string name);
|
||||||
|
|
||||||
|
static void ReceiveThread(Pipe* pipe);
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPCPipe : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IPCPipe();
|
||||||
|
~IPCPipe();
|
||||||
|
const char* GetName() { return "IPCPipe"; };
|
||||||
|
|
||||||
|
static bool Write(std::string command, std::string data);
|
||||||
|
static void On(std::string command, Pipe::PacketCallback callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Pipe* ServerPipe;
|
||||||
|
static Pipe* ClientPipe;
|
||||||
|
|
||||||
|
static void ConnectClient();
|
||||||
|
};
|
||||||
|
}
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
|
std::mutex Logger::MessageMutex;
|
||||||
|
std::vector<std::string> Logger::MessageQueue;
|
||||||
|
|
||||||
bool Logger::IsConsoleReady()
|
bool Logger::IsConsoleReady()
|
||||||
{
|
{
|
||||||
return (IsWindow(*(HWND*)0x64A3288) != FALSE);
|
return (IsWindow(*(HWND*)0x64A3288) != FALSE);
|
||||||
@ -18,7 +21,14 @@ namespace Components
|
|||||||
|
|
||||||
if (Logger::IsConsoleReady())
|
if (Logger::IsConsoleReady())
|
||||||
{
|
{
|
||||||
Game::Com_Printf(0, "%s", buffer);
|
if (!Game::Sys_IsMainThread())
|
||||||
|
{
|
||||||
|
Logger::EnqueueMessage(buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game::Com_PrintMessage(0, buffer, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -50,8 +60,43 @@ namespace Components
|
|||||||
Game::Com_Error(2, "%s", buffer);
|
Game::Com_Error(2, "%s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Logger::Frame()
|
||||||
|
{
|
||||||
|
Logger::MessageMutex.lock();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < Logger::MessageQueue.size(); i++)
|
||||||
|
{
|
||||||
|
if (Logger::IsConsoleReady())
|
||||||
|
{
|
||||||
|
Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutputDebugStringA(Logger::MessageQueue[i].data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::MessageQueue.clear();
|
||||||
|
Logger::MessageMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::EnqueueMessage(std::string message)
|
||||||
|
{
|
||||||
|
Logger::MessageMutex.lock();
|
||||||
|
Logger::MessageQueue.push_back(message);
|
||||||
|
Logger::MessageMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
Logger::Logger()
|
Logger::Logger()
|
||||||
{
|
{
|
||||||
|
Renderer::OnFrame(Logger::Frame); // Client
|
||||||
|
Dedicated::OnFrame(Logger::Frame); // Dedi
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::~Logger()
|
||||||
|
{
|
||||||
|
Logger::MessageMutex.lock();
|
||||||
|
Logger::MessageQueue.clear();
|
||||||
|
Logger::MessageMutex.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,19 @@ namespace Components
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Logger();
|
Logger();
|
||||||
|
~Logger();
|
||||||
const char* GetName() { return "Logger"; };
|
const char* GetName() { return "Logger"; };
|
||||||
|
|
||||||
static void Print(const char* message, ...);
|
static void Print(const char* message, ...);
|
||||||
static void Error(const char* message, ...);
|
static void Error(const char* message, ...);
|
||||||
static void SoftError(const char* message, ...);
|
static void SoftError(const char* message, ...);
|
||||||
static bool IsConsoleReady();
|
static bool IsConsoleReady();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::mutex MessageMutex;
|
||||||
|
static std::vector<std::string> MessageQueue;
|
||||||
|
|
||||||
|
static void Frame();
|
||||||
|
static void EnqueueMessage(std::string message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ namespace Game
|
|||||||
|
|
||||||
Com_Error_t Com_Error = (Com_Error_t)0x4B22D0;
|
Com_Error_t Com_Error = (Com_Error_t)0x4B22D0;
|
||||||
Com_Printf_t Com_Printf = (Com_Printf_t)0x402500;
|
Com_Printf_t Com_Printf = (Com_Printf_t)0x402500;
|
||||||
|
Com_PrintMessage_t Com_PrintMessage = (Com_PrintMessage_t)0x4AA830;
|
||||||
Com_Milliseconds_t Com_Milliseconds = (Com_Milliseconds_t)0x42A660;
|
Com_Milliseconds_t Com_Milliseconds = (Com_Milliseconds_t)0x42A660;
|
||||||
Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60;
|
Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60;
|
||||||
|
|
||||||
@ -86,6 +87,8 @@ namespace Game
|
|||||||
|
|
||||||
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
|
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
|
||||||
|
|
||||||
|
Sys_IsMainThread_t Sys_IsMainThread = (Sys_IsMainThread_t)0x4C37D0;
|
||||||
|
|
||||||
UI_AddMenuList_t UI_AddMenuList = (UI_AddMenuList_t)0x4533C0;
|
UI_AddMenuList_t UI_AddMenuList = (UI_AddMenuList_t)0x4533C0;
|
||||||
UI_DrawHandlePic_t UI_DrawHandlePic = (UI_DrawHandlePic_t)0x4D0EA0;
|
UI_DrawHandlePic_t UI_DrawHandlePic = (UI_DrawHandlePic_t)0x4D0EA0;
|
||||||
|
|
||||||
|
@ -21,6 +21,9 @@ namespace Game
|
|||||||
typedef void(__cdecl * Com_Printf_t)(int, const char*, ...);
|
typedef void(__cdecl * Com_Printf_t)(int, const char*, ...);
|
||||||
extern Com_Printf_t Com_Printf;
|
extern Com_Printf_t Com_Printf;
|
||||||
|
|
||||||
|
typedef void(__cdecl * Com_PrintMessage_t)(int, const char*, char);
|
||||||
|
extern Com_PrintMessage_t Com_PrintMessage;
|
||||||
|
|
||||||
typedef int(__cdecl * Com_Milliseconds_t)(void);
|
typedef int(__cdecl * Com_Milliseconds_t)(void);
|
||||||
extern Com_Milliseconds_t Com_Milliseconds;
|
extern Com_Milliseconds_t Com_Milliseconds;
|
||||||
|
|
||||||
@ -187,6 +190,9 @@ namespace Game
|
|||||||
typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char);
|
typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char);
|
||||||
extern Steam_JoinLobby_t Steam_JoinLobby;
|
extern Steam_JoinLobby_t Steam_JoinLobby;
|
||||||
|
|
||||||
|
typedef bool(__cdecl * Sys_IsMainThread_t)();
|
||||||
|
extern Sys_IsMainThread_t Sys_IsMainThread;
|
||||||
|
|
||||||
typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close);
|
typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close);
|
||||||
extern UI_AddMenuList_t UI_AddMenuList;
|
extern UI_AddMenuList_t UI_AddMenuList;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <version.hpp>
|
#include <version.hpp>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user