Merge branch 'boost' into 'develop'

Boost
This commit is contained in:
momo5502 2017-01-27 23:11:43 +01:00
commit b2a84b2caf
55 changed files with 827 additions and 463 deletions

92
.gitmodules vendored
View File

@ -35,3 +35,95 @@
path = deps/protobuf
url = https://github.com/google/protobuf.git
branch = 3.2.x
[submodule "deps/boost/interprocess"]
path = deps/boost/interprocess
url = https://github.com/boostorg/interprocess.git
branch = develop
[submodule "deps/boost/config"]
path = deps/boost/config
url = https://github.com/boostorg/config.git
branch = develop
[submodule "deps/boost/date_time"]
path = deps/boost/date_time
url = https://github.com/boostorg/date_time.git
branch = develop
[submodule "deps/boost/assert"]
path = deps/boost/assert
url = https://github.com/boostorg/assert.git
branch = develop
[submodule "deps/boost/utility"]
path = deps/boost/utility
url = https://github.com/boostorg/utility.git
branch = develop
[submodule "deps/boost/detail"]
path = deps/boost/detail
url = https://github.com/boostorg/detail.git
branch = develop
[submodule "deps/boost/winapi"]
path = deps/boost/winapi
url = https://github.com/boostorg/winapi.git
branch = develop
[submodule "deps/boost/integer"]
path = deps/boost/integer
url = https://github.com/boostorg/integer.git
branch = develop
[submodule "deps/boost/move"]
path = deps/boost/move
url = https://github.com/boostorg/move.git
branch = develop
[submodule "deps/boost/static_assert"]
path = deps/boost/static_assert
url = https://github.com/boostorg/static_assert.git
branch = develop
[submodule "deps/boost/container"]
path = deps/boost/container
url = https://github.com/boostorg/container.git
branch = develop
[submodule "deps/boost/intrusive"]
path = deps/boost/intrusive
url = https://github.com/boostorg/intrusive.git
branch = develop
[submodule "deps/boost/core"]
path = deps/boost/core
url = https://github.com/boostorg/core.git
branch = develop
[submodule "deps/boost/functional"]
path = deps/boost/functional
url = https://github.com/boostorg/functional.git
branch = develop
[submodule "deps/boost/type_traits"]
path = deps/boost/type_traits
url = https://github.com/boostorg/type_traits.git
branch = develop
[submodule "deps/boost/preprocessor"]
path = deps/boost/preprocessor
url = https://github.com/boostorg/preprocessor.git
branch = develop
[submodule "deps/boost/smart_ptr"]
path = deps/boost/smart_ptr
url = https://github.com/boostorg/smart_ptr.git
branch = develop
[submodule "deps/boost/throw_exception"]
path = deps/boost/throw_exception
url = https://github.com/boostorg/throw_exception.git
branch = develop
[submodule "deps/boost/predef"]
path = deps/boost/predef
url = https://github.com/boostorg/predef.git
branch = develop
[submodule "deps/boost/mpl"]
path = deps/boost/mpl
url = https://github.com/boostorg/mpl.git
branch = develop
[submodule "deps/boost/unordered"]
path = deps/boost/unordered
url = https://github.com/boostorg/unordered.git
branch = develop
[submodule "deps/boost/iterator"]
path = deps/boost/iterator
url = https://github.com/boostorg/iterator.git
branch = develop
[submodule "deps/boost/tuple"]
path = deps/boost/tuple
url = https://github.com/boostorg/tuple.git
branch = develop

View File

@ -33,6 +33,5 @@
| `--disable-bitmessage` | Disable use of BitMessage completely. |
| `--disable-node-log` | Disable debugging messages for Nodes in Debug builds. |
| `--disable-base128` | Disable base128 encoding for minidumps. |
| `--disable-steam-game` | Disable Steam's in-game setting. |
| `--no-new-structure` | Do not use new virtual path structure (separating headers and source files). |
| `--enable-dxsdk` | Enable DirectX SDK (required for GfxMap exporting). |

1
deps/boost/assert vendored Submodule

@ -0,0 +1 @@
Subproject commit 89e5b86c469c993ea4c53ebc7ed4a9b133f785a6

1
deps/boost/config vendored Submodule

@ -0,0 +1 @@
Subproject commit b4628d91eb8b2cbf96e3dadee3d6bff97b50ae46

1
deps/boost/container vendored Submodule

@ -0,0 +1 @@
Subproject commit 23e9e8b4946f8b026ced6b048d7a62b4ca81b722

1
deps/boost/core vendored Submodule

@ -0,0 +1 @@
Subproject commit 1abd68102d26d87109b5eda8d80f8bb0382ce4df

1
deps/boost/date_time vendored Submodule

@ -0,0 +1 @@
Subproject commit 47cf10d5fd7cee50d4e53a6132c69a7e1cbb2d0b

1
deps/boost/detail vendored Submodule

@ -0,0 +1 @@
Subproject commit 6c111975865d112c11101ef8221695cc4cd57562

1
deps/boost/functional vendored Submodule

@ -0,0 +1 @@
Subproject commit c592e854919730597b1793f85667e7d88f000d29

1
deps/boost/integer vendored Submodule

@ -0,0 +1 @@
Subproject commit 13b153c657697129cabe7ac8b3e62ef844a62945

1
deps/boost/interprocess vendored Submodule

@ -0,0 +1 @@
Subproject commit 0cd4548b45a9b9fdac2c58f2acb793095754f821

1
deps/boost/intrusive vendored Submodule

@ -0,0 +1 @@
Subproject commit 286f597606de0d139e256af8c2695d90535be905

1
deps/boost/iterator vendored Submodule

@ -0,0 +1 @@
Subproject commit 760da84f9cbbe87afb7ef845ef5fa6be158637b7

1
deps/boost/move vendored Submodule

@ -0,0 +1 @@
Subproject commit 135e598bc4ffc63001d84f93764fddee234f1da2

1
deps/boost/mpl vendored Submodule

@ -0,0 +1 @@
Subproject commit 3b126bdf8c7abbfef27101232a379c8e0c3db1ac

1
deps/boost/predef vendored Submodule

@ -0,0 +1 @@
Subproject commit 822d09f19bc2f4ea6f42da8e0be83d10ce912ce1

1
deps/boost/preprocessor vendored Submodule

@ -0,0 +1 @@
Subproject commit d8389ffda600ce73d62b077616987744f5f83453

1
deps/boost/smart_ptr vendored Submodule

@ -0,0 +1 @@
Subproject commit 19147212a9edd1facdc9a17cf586b79c92f4116a

1
deps/boost/static_assert vendored Submodule

@ -0,0 +1 @@
Subproject commit c2f58a187a67502a20aaa14c88625f12e400c5c1

1
deps/boost/throw_exception vendored Submodule

@ -0,0 +1 @@
Subproject commit f94638e5225afff877347576ff7b4170971e7a2a

1
deps/boost/tuple vendored Submodule

@ -0,0 +1 @@
Subproject commit 895af7c97a2f74980eb459badf67787c2a3ecadf

1
deps/boost/type_traits vendored Submodule

@ -0,0 +1 @@
Subproject commit 4fffc7637da8479e3f94674ef1dd0fc996a7d027

1
deps/boost/unordered vendored Submodule

@ -0,0 +1 @@
Subproject commit 57cc6d4bac1cc93fb8fb05696116b184f3d1fecc

1
deps/boost/utility vendored Submodule

@ -0,0 +1 @@
Subproject commit ccfd741c0a423e6c8dc4493e3a4e042b5a34a329

1
deps/boost/winapi vendored Submodule

@ -0,0 +1 @@
Subproject commit b017fd886612a9001dfdffeb1aa4663b6e2acda8

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit d1f0939a42ae8a6b6bca95a4b9048d7416e72865
Subproject commit 2c8346a259791ccb176da80e31e59f1df479bd6d

83
premake/boost.lua Normal file
View File

@ -0,0 +1,83 @@
boost = {
settings = nil,
}
function boost.setup(settings)
if not settings.source then error("Missing source.") end
boost.settings = settings
end
function boost.import()
if not boost.settings then error("Run boost.setup first") end
--links { "boost" }
boost.includes()
end
function boost.includes()
if not boost.settings then error("Run boost.setup first") end
submodules = {
"mpl",
"core",
"move",
"tuple",
"assert",
"predef",
"config",
"detail",
"winapi",
"integer",
"utility",
"iterator",
"container",
"unordered",
"date_time",
"smart_ptr",
"intrusive",
"functional",
"type_traits",
"interprocess",
"preprocessor",
"static_assert",
"throw_exception",
}
for i, submodule in ipairs(submodules) do
includedirs { path.join(boost.settings.source, string.format("%s/include", submodule)) }
end
includedirs { boost.settings.source }
end
function boost.project()
if not boost.settings then error("Run boost.setup first") end
--[[
project "boost"
language "C++"
includedirs
{
boost.settings.source,
}
files
{
path.join(boost.settings.source, "*.cpp"),
path.join(boost.settings.source, "*.hpp"),
}
removefiles
{
path.join(boost.settings.source, "test*"),
}
-- not our code, ignore POSIX usage warnings for now
warnings "Off"
defines { "_LIB" }
removedefines { "_USRDLL", "_DLL" }
kind "StaticLib"
]]
end

View File

@ -88,11 +88,6 @@ newoption {
description = "Disable base128 encoding for minidumps."
}
newoption {
trigger = "disable-steam-game",
description = "Disable Steam's in-game setting."
}
newoption {
trigger = "enable-dxsdk",
description = "Enable DirectX SDK (required for GfxMap exporting)."
@ -204,6 +199,7 @@ require "premake/pdcurses"
require "premake/protobuf"
require "premake/sqlite3"
require "premake/zlib"
require "premake/boost"
base128.setup
{
@ -260,6 +256,10 @@ zlib.setup
},
source = path.join(depsBasePath, "zlib"),
}
boost.setup
{
source = path.join(depsBasePath, "boost"),
}
workspace "iw4x"
location "./build"
@ -304,7 +304,7 @@ workspace "iw4x"
}
includedirs {
"%{prj.location}/src",
"./src"
"./src",
}
resincludedirs {
"$(ProjectDir)src" -- fix for VS IDE
@ -341,9 +341,6 @@ workspace "iw4x"
if _OPTIONS["disable-base128"] then
defines { "DISABLE_BASE128" }
end
if _OPTIONS["disable-steam-game"] then
defines { "DISABLE_STEAM_GAME" }
end
if _OPTIONS["enable-dxsdk"] then
defines { "ENABLE_DXSDK" }
includedirs { "%DXSDK_DIR%Include" }
@ -369,6 +366,7 @@ workspace "iw4x"
pdcurses.import()
protobuf.import()
zlib.import()
boost.import()
-- fix vpaths for protobuf sources
vpaths
@ -397,8 +395,9 @@ workspace "iw4x"
-- Pre-build
prebuildcommands
{
"cd %{_MAIN_SCRIPT_DIR}",
"pushd %{_MAIN_SCRIPT_DIR}",
"tools\\premake5 generate-buildinfo",
"popd",
}
-- Post-build
@ -486,6 +485,7 @@ workspace "iw4x"
pdcurses.project()
protobuf.project()
zlib.project()
boost.project()
rule "ProtobufCompiler"
display "Protobuf compiler"

View File

@ -43,7 +43,6 @@ namespace Components
Loader::Register(new Command());
Loader::Register(new Console());
Loader::Register(new Friends());
Loader::Register(new IPCPipe());
Loader::Register(new ModList());
Loader::Register(new Network());
Loader::Register(new Theatre());
@ -68,6 +67,7 @@ namespace Components
Loader::Register(new BitMessage());
#endif
Loader::Register(new FileSystem());
Loader::Register(new IPCHandler());
Loader::Register(new ModelSurfs());
Loader::Register(new PlayerName());
Loader::Register(new QuickPatch());

View File

@ -59,7 +59,6 @@ namespace Components
#include "Modules/Window.hpp"
#include "Modules/Command.hpp"
#include "Modules/Console.hpp"
#include "Modules/IPCPipe.hpp"
#include "Modules/UIScript.hpp"
#include "Modules/ModList.hpp"
#include "Modules/Network.hpp"
@ -86,6 +85,7 @@ namespace Components
#include "Modules/Threading.hpp"
#include "Modules/BitMessage.hpp"
#include "Modules/FileSystem.hpp"
#include "Modules/IPCHandler.hpp"
#include "Modules/ModelSurfs.hpp"
#include "Modules/PlayerName.hpp"
#include "Modules/QuickPatch.hpp"

View File

@ -6,7 +6,7 @@
#endif
// Uncomment to enable process protection (conflicts with steam!)
//#define PROCTECT_PROCESS
#define PROCTECT_PROCESS
namespace Components
{

View File

@ -212,7 +212,7 @@ namespace Components
ConnectProtocol::ConnectProtocol()
{
// IPC handler
IPCPipe::On("connect", [] (std::string data)
IPCHandler::OnClient("connect", [] (std::string data)
{
Command::Execute(Utils::String::VA("connect %s", data.data()), false);
});
@ -229,7 +229,7 @@ namespace Components
{
if (!Singleton::IsFirstInstance())
{
IPCPipe::Write("connect", ConnectProtocol::ConnectString);
IPCHandler::SendClient("connect", ConnectProtocol::ConnectString);
ExitProcess(0);
}
else

View File

@ -507,7 +507,7 @@ namespace Components
{ "con_outputWindowColor", { 0.25f, 0.25f, 0.25f, 0.85f } },
};
for (int i = 0; i < ARRAY_SIZE(patchedColors); ++i)
for (int i = 0; i < ARRAYSIZE(patchedColors); ++i)
{
if (std::string(name) == patchedColors[i].name)
{

View File

@ -0,0 +1,128 @@
#include "STDInclude.hpp"
namespace Components
{
std::unordered_map<std::string, IPCHandler::Callback> IPCHandler::WorkerCallbacks;
std::unordered_map<std::string, IPCHandler::Callback> IPCHandler::ClientCallbacks;
std::unique_ptr<Utils::IPC::BidirectionalChannel> IPCHandler::WorkerChannel;
std::unique_ptr<Utils::IPC::BidirectionalChannel> IPCHandler::ClientChannel;
void IPCHandler::SendWorker(std::string message, std::string data)
{
IPCHandler::InitChannels();
Proto::IPC::Command command;
command.set_command(message);
command.set_data(data);
IPCHandler::WorkerChannel->send(command.SerializeAsString());
}
void IPCHandler::SendClient(std::string message, std::string data)
{
IPCHandler::InitChannels();
Proto::IPC::Command command;
command.set_command(message);
command.set_data(data);
IPCHandler::ClientChannel->send(command.SerializeAsString());
}
void IPCHandler::OnWorker(std::string message, IPCHandler::Callback callback)
{
IPCHandler::WorkerCallbacks[message] = callback;
}
void IPCHandler::OnClient(std::string message, IPCHandler::Callback callback)
{
IPCHandler::ClientCallbacks[message] = callback;
}
void IPCHandler::InitChannels()
{
if (!IPCHandler::WorkerChannel)
{
IPCHandler::WorkerChannel.reset(new Utils::IPC::BidirectionalChannel("IW4x-Worker-Channel", !Worker::IsWorker()));
}
if (!IPCHandler::ClientChannel)
{
IPCHandler::ClientChannel.reset(new Utils::IPC::BidirectionalChannel("IW4x-Client-Channel", Singleton::IsFirstInstance()));
}
}
void IPCHandler::StartWorker()
{
STARTUPINFOA sInfo;
PROCESS_INFORMATION pInfo;
ZeroMemory(&sInfo, sizeof(sInfo));
ZeroMemory(&pInfo, sizeof(pInfo));
sInfo.cb = sizeof(sInfo);
CreateProcessA("iw4x.exe", const_cast<char*>(Utils::String::VA("-parent %d", GetCurrentProcessId())), nullptr, nullptr, false, NULL, nullptr, nullptr, &sInfo, &pInfo);
if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hThread);
if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hProcess);
}
void IPCHandler::HandleClient()
{
IPCHandler::InitChannels();
std::string packet;
if(IPCHandler::ClientChannel->receive(&packet))
{
Proto::IPC::Command command;
if(command.ParseFromString(packet))
{
auto callback = IPCHandler::ClientCallbacks.find(command.command());
if (callback != IPCHandler::ClientCallbacks.end())
{
callback->second(command.data());
}
}
}
}
void IPCHandler::HandleWorker()
{
IPCHandler::InitChannels();
std::string packet;
if (IPCHandler::WorkerChannel->receive(&packet))
{
Proto::IPC::Command command;
if (command.ParseFromString(packet))
{
auto callback = IPCHandler::WorkerCallbacks.find(command.command());
if (callback != IPCHandler::WorkerCallbacks.end())
{
callback->second(command.data());
}
}
}
}
IPCHandler::IPCHandler()
{
if (Dedicated::IsEnabled()) return;
IPCHandler::InitChannels();
IPCHandler::StartWorker();
QuickPatch::OnFrame([]()
{
IPCHandler::HandleWorker();
IPCHandler::HandleClient();
});
}
IPCHandler::~IPCHandler()
{
IPCHandler::WorkerCallbacks.clear();
IPCHandler::ClientCallbacks.clear();
}
}

View File

@ -0,0 +1,36 @@
#pragma once
namespace Components
{
class IPCHandler : public Component
{
public:
typedef Utils::Slot<void(std::string)> Callback;
IPCHandler();
~IPCHandler();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "IPCHandler"; };
#endif
static void SendWorker(std::string message, std::string data);
static void SendClient(std::string message, std::string data);
static void OnWorker(std::string message, Callback callback);
static void OnClient(std::string message, Callback callback);
private:
static std::unique_ptr<Utils::IPC::BidirectionalChannel> WorkerChannel;
static std::unique_ptr<Utils::IPC::BidirectionalChannel> ClientChannel;
static std::unordered_map<std::string, Callback> WorkerCallbacks;
static std::unordered_map<std::string, Callback> ClientCallbacks;
static void InitChannels();
static void StartWorker();
static void HandleClient();
static void HandleWorker();
};
}

View File

@ -1,245 +0,0 @@
#include "STDInclude.hpp"
namespace Components
{
Pipe IPCPipe::ServerPipe;
Pipe IPCPipe::ClientPipe;
#pragma region Pipe
Pipe::Pipe() : connectCallback(0), pipe(INVALID_HANDLE_VALUE), threadAttached(false), type(IPCTYPE_NONE), reconnectAttempt(0)
{
this->destroy();
}
Pipe::~Pipe()
{
this->destroy();
}
bool Pipe::connect(std::string name)
{
this->destroy();
this->type = IPCTYPE_CLIENT;
this->setName(name);
this->pipe = CreateFileA(this->pipeFile, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (INVALID_HANDLE_VALUE == this->pipe)
{
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;
std::this_thread::sleep_for(500ms);
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->type = IPCTYPE_SERVER;
this->setName(name);
this->pipe = CreateNamedPipeA(this->pipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->packet), sizeof(this->packet), NMPWAIT_USE_DEFAULT_WAIT, nullptr);
if (INVALID_HANDLE_VALUE != this->pipe && this->pipe)
{
// Only create the thread, when not performing unit tests!
if (!Loader::PerformingUnitTests())
{
this->threadAttached = true;
this->thread = std::thread(Pipe::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, Utils::Slot<Pipe::PacketCallback> callback)
{
this->packetCallbacks[command] = callback;
}
bool Pipe::write(std::string command, std::string data)
{
if (this->type != IPCTYPE_CLIENT || this->pipe == 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->pipe, &_packet, sizeof(_packet), &cbBytes, nullptr) || GetLastError() == ERROR_IO_PENDING);
}
void Pipe::destroy()
{
//this->Type = IPCTYPE_NONE;
//*this->PipeFile = 0;
//*this->PipeName = 0;
if (this->pipe && INVALID_HANDLE_VALUE != this->pipe)
{
CancelIoEx(this->pipe, nullptr);
//DeleteFileA(this->pipeFile);
if (this->type == IPCTYPE_SERVER) DisconnectNamedPipe(this->pipe);
CloseHandle(this->pipe);
Logger::Print("Disconnected from the pipe.\n");
}
this->pipe = nullptr;
this->threadAttached = false;
if (this->thread.joinable())
{
Logger::Print("Terminating pipe thread...\n");
this->thread.join();
Logger::Print("Pipe thread terminated.\n");
}
this->thread = std::thread();
}
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.data(), sizeof(this->pipeName));
sprintf_s(this->pipeFile, sizeof(this->pipeFile), "\\\\.\\Pipe\\%s", this->pipeName);
}
void Pipe::ReceiveThread(Pipe* pipe)
{
if (!pipe || pipe->type != IPCTYPE_SERVER || pipe->pipe == INVALID_HANDLE_VALUE || !pipe->pipe) return;
if (ConnectNamedPipe(pipe->pipe, nullptr) == FALSE)
{
Logger::Print("Failed to initialize pipe reading.\n");
return;
}
Logger::Print("Client connected to the pipe\n");
pipe->connectCallback();
DWORD cbBytes;
while (pipe->threadAttached && pipe->pipe && pipe->pipe != INVALID_HANDLE_VALUE)
{
BOOL bResult = ReadFile(pipe->pipe, &pipe->packet, sizeof(pipe->packet), &cbBytes, nullptr);
if (bResult && cbBytes)
{
if (pipe->packetCallbacks.find(pipe->packet.command) != pipe->packetCallbacks.end())
{
pipe->packetCallbacks[pipe->packet.command](pipe->packet.buffer);
}
}
else if (pipe->threadAttached && pipe->pipe != INVALID_HANDLE_VALUE)
{
Logger::Print("Failed to read from client through pipe\n");
DisconnectNamedPipe(pipe->pipe);
ConnectNamedPipe(pipe->pipe, nullptr);
pipe->connectCallback();
}
ZeroMemory(&pipe->packet, sizeof(pipe->packet));
}
}
#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.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)
{
return IPCPipe::ClientPipe.write(command, data);
}
// Installs a callback for receiving commands from the process on the other end of the pipe
void IPCPipe::On(std::string command, Utils::Slot<Pipe::PacketCallback> callback)
{
IPCPipe::ServerPipe.setCallback(command, callback);
}
IPCPipe::IPCPipe()
{
if (Dedicated::IsEnabled()) return;
// Server pipe
IPCPipe::ServerPipe.onConnect(IPCPipe::ConnectClient);
IPCPipe::ServerPipe.create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT));
// 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*)
{
Logger::Print("Sending ping to pipe!\n");
IPCPipe::Write("ping", "");
});
}
void IPCPipe::preDestroy()
{
IPCPipe::ServerPipe.destroy();
IPCPipe::ClientPipe.destroy();
}
}

View File

@ -1,83 +0,0 @@
#pragma once
#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, Utils::Slot<PacketCallback> callback);
void onConnect(Callback callback);
void destroy();
private:
Utils::Slot<void()> connectCallback;
std::map<std::string, Utils::Slot<PacketCallback>> packetCallbacks;
HANDLE pipe;
std::thread thread;
bool threadAttached;
Type type;
Packet packet;
char pipeName[MAX_PATH];
char pipeFile[MAX_PATH];
unsigned int reconnectAttempt;
void setName(std::string name);
static void ReceiveThread(Pipe* pipe);
};
class IPCPipe : public Component
{
public:
IPCPipe();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "IPCPipe"; };
#endif
void preDestroy() override;
static bool Write(std::string command, std::string data);
static void On(std::string command, Utils::Slot<Pipe::PacketCallback> callback);
private:
static Pipe ServerPipe;
static Pipe ClientPipe;
static void ConnectClient();
};
}

View File

@ -244,7 +244,7 @@ namespace Components
Game::newMapArena_t* arena = &ArenaLength::NewArenas[i];
if (arena->mapName == map)
{
for (int j = 0; j < ARRAY_SIZE(arena->keys); ++j)
for (int j = 0; j < ARRAYSIZE(arena->keys); ++j)
{
if (arena->keys[j] == "dependency"s)
{
@ -267,7 +267,7 @@ namespace Components
Game::newMapArena_t* arena = &ArenaLength::NewArenas[i];
if (arena->mapName == map)
{
for (int j = 0; j < ARRAY_SIZE(arena->keys); ++j)
for (int j = 0; j < ARRAYSIZE(arena->keys); ++j)
{
if (arena->keys[j] == "allieschar"s)
{

View File

@ -77,7 +77,7 @@ namespace Components
header.sectionHeader[Game::SECTION_FIXUP].buffer = allocator.allocateArray<char>(header.sectionHeader[Game::SECTION_FIXUP].size);
// Load section data
for (int i = 0; i < ARRAY_SIZE(header.sectionHeader); ++i)
for (int i = 0; i < ARRAYSIZE(header.sectionHeader); ++i)
{
model.seek(header.sectionHeader[i].offset, FS_SEEK_SET);
if (!model.read(header.sectionHeader[i].buffer, header.sectionHeader[i].size))

View File

@ -53,15 +53,8 @@ namespace Components
CreateProcessA("updater.exe", nullptr, nullptr, nullptr, false, NULL, nullptr, nullptr, &sInfo, &pInfo);
if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE)
{
CloseHandle(pInfo.hThread);
}
if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE)
{
CloseHandle(pInfo.hProcess);
}
if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hThread);
if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hProcess);
TerminateProcess(GetCurrentProcess(), exitCode);
}

View File

@ -14,7 +14,7 @@ namespace Components
{
#if(0) // Disabled for now
{
for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i)
for (int i = 0; i < ARRAYSIZE(PlayerName::PlayerNames); ++i)
{
PlayerName::PlayerNames[i] = "mumu";
}
@ -26,7 +26,7 @@ namespace Components
PlayerName::~PlayerName()
{
for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i)
for (int i = 0; i < ARRAYSIZE(PlayerName::PlayerNames); ++i)
{
PlayerName::PlayerNames[i].clear();
}

View File

@ -20,8 +20,14 @@ namespace Main
Main::EntryPointHook.uninstall();
Main::SetEnvironment();
Utils::Cryptography::Initialize();
if(Worker::IsWorker())
{
Worker::Initialize();
}
else
{
Components::Loader::Initialize();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
@ -38,10 +44,19 @@ namespace Main
}
#endif
}
}
void Uninitialize()
{
if(Worker::IsWorker())
{
Worker::Uninitialize();
}
else
{
Components::Loader::Uninitialize();
}
Utils::Cache::Uninitialize();
google::protobuf::ShutdownProtobufLibrary();
}
@ -51,8 +66,6 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
Steam::Proxy::RunMod();
// Ensure we're working with our desired binary
if (Utils::Hook::Get<DWORD>(0x4C0FFF) != 0x6824748B)
{

9
src/Proto/ipc.proto Normal file
View File

@ -0,0 +1,9 @@
syntax = "proto3";
package Proto.IPC;
message Command
{
bytes command = 1;
bytes data = 2;
}

View File

@ -18,6 +18,11 @@
#include <d3d9.h>
#include <Aclapi.h>
#pragma warning(push)
#pragma warning(disable: 4996)
#include <xutility>
#pragma warning(pop)
#include <sstream>
#include <fstream>
#include <cctype>
@ -80,10 +85,17 @@ template <size_t S> class Sizer { };
#include "proto/auth.pb.h"
#include "proto/node.pb.h"
#include "proto/rcon.pb.h"
#include "proto/ipc.pb.h"
#pragma warning(pop)
#define ENABLE_BASE64
#ifndef DISABLE_BASE128
#define ENABLE_BASE128
#endif
#include "Utils/IO.hpp"
#include "Utils/IPC.hpp"
#include "Utils/CSV.hpp"
#include "Utils/Time.hpp"
#include "Utils/Cache.hpp"
@ -106,6 +118,7 @@ template <size_t S> class Sizer { };
#include "Utils/Stream.hpp"
#include "Components/Loader.hpp"
#include "Worker/Worker.hpp"
// Libraries
#pragma comment(lib, "Winmm.lib")

View File

@ -5,17 +5,17 @@ namespace Steam
::Utils::Library Proxy::Client;
::Utils::Library Proxy::Overlay;
ISteamClient008* Proxy::SteamClient;
IClientEngine* Proxy::ClientEngine;
IClientUser* Proxy::ClientUser;
ISteamClient008* Proxy::SteamClient = nullptr;
IClientEngine* Proxy::ClientEngine = nullptr;
IClientUser* Proxy::ClientUser = nullptr;
void* Proxy::SteamPipe;
void* Proxy::SteamUser;
void* Proxy::SteamPipe = nullptr;
void* Proxy::SteamUser = nullptr;
Friends15* Proxy::SteamFriends;
Utils* Proxy::SteamUtils;
Friends15* Proxy::SteamFriends = nullptr;
Utils* Proxy::SteamUtils = nullptr;
uint32_t Proxy::AppId;
uint32_t Proxy::AppId = 0;
std::recursive_mutex Proxy::CallMutex;
std::vector<Proxy::CallContainer> Proxy::Calls;
@ -29,54 +29,15 @@ namespace Steam
{
Proxy::AppId = appId;
SetEnvironmentVariableA("SteamAppId", ::Utils::String::VA("%lu", appId));
SetEnvironmentVariableA("SteamGameId", ::Utils::String::VA("%llu", appId & 0xFFFFFF));
// if (!Components::Flags::HasFlag("nosteam"))
// {
// SetEnvironmentVariableA("SteamAppId", ::Utils::String::VA("%lu", appId));
// SetEnvironmentVariableA("SteamGameId", ::Utils::String::VA("%llu", appId & 0xFFFFFF));
//
// ::Utils::IO::WriteFile("steam_appid.txt", ::Utils::String::VA("%lu", appId), false);
// }
::Utils::IO::WriteFile("steam_appid.txt", ::Utils::String::VA("%lu", appId), false);
}
void Proxy::SetMod(std::string mod)
{
#if 0
if (!Proxy::ClientUser) return;
GameID_t gameID;
gameID.m_nType = 1; // k_EGameIDTypeGameMod
gameID.m_nAppID = Proxy::AppId & 0xFFFFFF;
gameID.m_nModID = 0x01010101;
char ourPath[MAX_PATH] = { 0 };
GetModuleFileNameA(GetModuleHandle(nullptr), ourPath, sizeof(ourPath));
char ourDirectory[MAX_PATH] = { 0 };
GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory);
char blob[1] = { 0 };
std::string cmdline = ::Utils::String::VA("\"%s\" -parentProc %d", ourPath, GetCurrentProcessId());
Proxy::ClientUser->SpawnProcess(blob, 0, ourPath, cmdline.data(), 0, ourDirectory, gameID, Proxy::AppId, mod.data(), 0);
#endif
}
void Proxy::RunMod()
{
char* command = "-parentProc ";
char* parentProc = strstr(GetCommandLineA(), command);
if (parentProc)
{
parentProc += strlen(command);
int pid = atoi(parentProc);
HANDLE processHandle = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (processHandle && processHandle != INVALID_HANDLE_VALUE)
{
WaitForSingleObject(processHandle, INFINITE);
CloseHandle(processHandle);
}
TerminateProcess(GetCurrentProcess(), 0);
}
remove("steam_appid.txt");
}
void Proxy::RegisterCall(int32_t callId, uint32_t size, uint64_t call)
@ -142,13 +103,13 @@ namespace Steam
}
Proxy::CallbackMsg message;
while (Proxy::SteamBGetCallback(Proxy::SteamPipe, &message))
while (Proxy::SteamBGetCallback && Proxy::SteamFreeLastCallback && Proxy::SteamBGetCallback(Proxy::SteamPipe, &message))
{
#ifdef DEBUG
Components::Logger::Print("Steam::Proxy: Callback dispatched: %d\n", message.m_iCallback);
printf("Callback dispatched: %d\n", message.m_iCallback);
#endif
Steam::Callbacks::RunCallback(message.m_iCallback, message.m_pubParam);
//Steam::Callbacks::RunCallback(message.m_iCallback, message.m_pubParam);
Proxy::RunCallback(message.m_iCallback, message.m_pubParam);
Proxy::SteamFreeLastCallback(Proxy::SteamPipe);
}
@ -163,7 +124,7 @@ namespace Steam
::Utils::Memory::Allocator allocator;
#ifdef DEBUG
Components::Logger::Print("Steam::Proxy: Handling call: %d\n", call.callId);
printf("Handling call: %d\n", call.callId);
#endif
call.handled = true;
@ -172,7 +133,7 @@ namespace Steam
{
#ifdef DEBUG
auto error = Proxy::SteamUtils->GetAPICallFailureReason(call.call);
Components::Logger::Print("Steam::Proxy: API call failed: %X Handle: %llX\n", error, call.call);
printf("API call failed: %X Handle: %llX\n", error, call.call);
#endif
continue;
}
@ -185,7 +146,7 @@ namespace Steam
{
#ifdef DEBUG
auto error = Proxy::SteamUtils->GetAPICallFailureReason(call.call);
Components::Logger::Print("Steam::Proxy: GetAPICallResult failed: %X Handle: %llX\n", error, call.call);
printf("GetAPICallResult failed: %X Handle: %llX\n", error, call.call);
#endif
continue;
}
@ -198,16 +159,19 @@ namespace Steam
Proxy::UnregisterCalls();
}
bool Proxy::Inititalize()
bool Proxy::Inititalize(bool overlayOnly)
{
std::string directoy = Proxy::GetSteamDirectory();
if (directoy.empty()) return false;
SetDllDirectoryA(Proxy::GetSteamDirectory().data());
Proxy::Client = ::Utils::Library(STEAMCLIENT_LIB, false);
Proxy::Overlay = ::Utils::Library(GAMEOVERLAY_LIB, false);
if (!Proxy::Client.valid() || !Proxy::Overlay.valid()) return false;
if (!Proxy::Overlay.valid()) return false;
if (overlayOnly) return true;
Proxy::Client = ::Utils::Library(STEAMCLIENT_LIB, false);
if (!Proxy::Client.valid()) return false;
Proxy::SteamClient = Proxy::Client.get<ISteamClient008*(const char*, int*)>("CreateInterface")("SteamClient008", nullptr);
if(!Proxy::SteamClient) return false;

View File

@ -334,12 +334,10 @@ namespace Steam
class Proxy
{
public:
static bool Inititalize();
static bool Inititalize(bool overlayOnly = false);
static void Uninititalize();
static void SetGame(uint32_t appId);
static void SetMod(std::string mod);
static void RunMod();
//Overlay related proxies
static void SetOverlayNotificationPosition(uint32_t eNotificationPosition);

View File

@ -106,26 +106,12 @@ namespace Steam
{
bool SteamAPI_Init()
{
#ifndef DISABLE_STEAM_GAME
if (!Components::Flags::HasFlag("nosteam"))
{
//Proxy::SetGame(10190);
}
#endif
Proxy::SetGame(10190);
if (!Proxy::Inititalize())
if (!Proxy::Inititalize(true))
{
OutputDebugStringA("Steamproxy not initialized properly");
}
else
{
#ifndef DISABLE_STEAM_GAME
if (!Components::Flags::HasFlag("nosteam"))
{
//Proxy::SetMod("IW4x - Modern Warfare 2");
}
#endif
}
return true;
}
@ -143,7 +129,7 @@ namespace Steam
void SteamAPI_RunCallbacks()
{
Callbacks::RunCallbacks();
Proxy::RunFrame();
//Proxy::RunFrame();
}
void SteamAPI_Shutdown()

View File

@ -29,7 +29,7 @@ namespace Utils
if (Cache::ValidUrl.empty())
{
for (int i = 0; i < ARRAY_SIZE(Cache::Urls); i++)
for (int i = 0; i < ARRAYSIZE(Cache::Urls); i++)
{
std::string result = Utils::WebIO(useragent, Cache::GetUrl(Cache::Urls[i], path)).setTimeout(timeout)->get();

104
src/Utils/IPC.cpp Normal file
View File

@ -0,0 +1,104 @@
#include "STDInclude.hpp"
namespace Utils
{
namespace IPC
{
Channel::Channel(std::string _name, int _queueSize, int _bufferSize, bool _remove) : name(_name), remove(_remove)
{
if(this->remove) boost::interprocess::message_queue::remove(this->name.data());
queue.reset(new boost::interprocess::message_queue(boost::interprocess::open_or_create, this->name.data(), _queueSize, _bufferSize + sizeof(Channel::Header)));
}
Channel::~Channel()
{
if (this->remove) boost::interprocess::message_queue::remove(this->name.data());
}
bool Channel::receive(std::string* data)
{
if (!data) return false;
data->clear();
if(this->packet.size() < this->queue->get_max_msg_size())
{
packet.resize(this->queue->get_max_msg_size());
}
const Channel::Header* header = reinterpret_cast<const Channel::Header*>(packet.data());
const char* buffer = reinterpret_cast<const char*>(header + 1);
unsigned int priority;
boost::interprocess::message_queue::size_type recvd_size;
if (this->queue->try_receive(const_cast<char*>(packet.data()), packet.size(), recvd_size, priority))
{
if ((recvd_size - sizeof(Channel::Header)) != header->fragmentSize || header->fragmentPart) return false;
data->append(buffer, header->fragmentSize);
if(header->fragmented)
{
Channel::Header mainHeader = *header;
unsigned int part = mainHeader.fragmentPart;
while (true)
{
if (!this->queue->try_receive(const_cast<char*>(packet.data()), packet.size(), recvd_size, priority)) return false;
if (header->packetId != mainHeader.packetId || header->totalSize != mainHeader.totalSize || header->fragmentPart != (++part))
{
data->clear();
return false;
}
data->append(buffer, header->fragmentSize);
if(header->totalSize <= data->size())
{
break;
}
}
}
return true;
}
return false;
}
void Channel::send(std::string data)
{
const size_t fragmentSize = (this->queue->get_max_msg_size() - sizeof(Channel::Header)) - 1;
Channel::Header header;
header.fragmented = (data.size() + sizeof(Channel::Header)) > this->queue->get_max_msg_size();
header.packetId = static_cast<short>(timeGetTime() + rand());;
header.totalSize = data.size();
size_t sentSize = 0;
for (unsigned short i = 0; sentSize < data.size(); ++i)
{
header.fragmentPart = i;
header.fragmentSize = std::min(fragmentSize, data.size() - (fragmentSize * i));
std::string buffer;
buffer.append(reinterpret_cast<char*>(&header), sizeof(Channel::Header));
buffer.append(data.data() + sentSize, header.fragmentSize);
Channel::sendMessage(buffer);
sentSize += header.fragmentSize;
}
}
void Channel::sendMessage(std::string data)
{
if (data.size() <= this->queue->get_max_msg_size())
{
while (!this->queue->try_send(data.data(), data.size(), 0))
{
std::this_thread::sleep_for(100us);
}
}
}
}
}

94
src/Utils/IPC.hpp Normal file
View File

@ -0,0 +1,94 @@
#pragma once
namespace boost
{
typedef unsigned long long ulong_long_type;
}
#pragma warning(push)
#pragma warning(disable: 4091)
#pragma warning(disable: 4996)
#define _SCL_SECURE_NO_WARNINGS
#ifdef sleep
#undef sleep
#endif
//#define BOOST_DISABLE_WIN32
#define BOOST_USE_WINDOWS_H
#define BOOST_DATE_TIME_NO_LIB
#include <boost/interprocess/ipc/message_queue.hpp>
#undef _SCL_SECURE_NO_WARNINGS
#pragma warning(pop)
namespace Utils
{
namespace IPC
{
class Channel
{
public:
Channel(std::string _name, int _queueSize = 100, int _bufferSize = 1024, bool _remove = false);
~Channel();
bool receive(std::string* data);
void send(std::string data);
private:
struct Header
{
bool fragmented;
unsigned short packetId;
size_t fragmentSize;
size_t totalSize;
unsigned int fragmentPart;
};
void sendMessage(std::string data);
bool remove;
std::unique_ptr<boost::interprocess::message_queue> queue;
std::string packet;
std::string name;
};
class BidirectionalChannel
{
public:
BidirectionalChannel(std::string name, bool server, int queueSize = 100, int bufferSize = 1024) : isServer(server),
channel1(name, queueSize, bufferSize, server),
channel2(name + "2", queueSize, bufferSize, server)
{}
bool receive(std::string* data)
{
if(this->isServer)
{
return channel1.receive(data);
}
else
{
return channel2.receive(data);
}
}
void send(std::string data)
{
if (this->isServer)
{
return channel2.send(data);
}
else
{
return channel1.send(data);
}
}
private:
const bool isServer;
Channel channel1;
Channel channel2;
};
}
}

View File

@ -1,5 +1,5 @@
#include "STDInclude.hpp"
#ifndef DISABLE_BASE128
#ifdef ENABLE_BASE128
#include "base128.h"
#endif
@ -158,7 +158,7 @@ namespace Utils
double bytesPerSecond = (1000.0 / milliseconds) * bytes;
int i;
for (i = 0; bytesPerSecond > 1000 && i < ARRAY_SIZE(sizes); ++i) // 1024 or 1000?
for (i = 0; bytesPerSecond > 1000 && i < ARRAYSIZE(sizes); ++i) // 1024 or 1000?
{
bytesPerSecond /= 1000;
}
@ -166,6 +166,7 @@ namespace Utils
return Utils::String::VA("%.2f %s/s", static_cast<float>(bytesPerSecond), sizes[i]);
}
#ifdef ENABLE_BASE64
// Encodes a given string in Base64
std::string EncodeBase64(const char* input, const unsigned long inputSize)
{
@ -182,8 +183,9 @@ namespace Utils
{
return EncodeBase64(input.data(), input.size());
}
#endif
#ifndef DISABLE_BASE128
#ifdef ENABLE_BASE128
// Encodes a given string in Base128
std::string EncodeBase128(const std::string& input)
{

60
src/Worker/Runner.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "STDInclude.hpp"
namespace Worker
{
Runner::Runner(int pid) : processId(pid), terminate(false)
{
}
Runner::~Runner()
{
}
void Runner::run()
{
HANDLE processHandle = OpenProcess(SYNCHRONIZE, FALSE, this->processId);
if (!processHandle || processHandle == INVALID_HANDLE_VALUE)
{
printf("Unable to attach to parent process\n");
}
else
{
printf("Successfully attached to parent process\n");
printf("Starting worker...\n");
std::thread workerThread(&Runner::worker, this);
WaitForSingleObject(processHandle, INFINITE);
CloseHandle(processHandle);
printf("Awaiting worker termination...\n");
this->terminate = true;
if (workerThread.joinable()) workerThread.join();
printf("Worker terminated\n");
}
}
void Runner::worker()
{
printf("Worker started\n");
Utils::IPC::BidirectionalChannel channel("IW4x-Worker-Channel", !Worker::IsWorker());
while (!this->terminate)
{
Steam::Proxy::RunFrame();
std::string buffer;
if (channel.receive(&buffer))
{
printf("Data received: %s\n", buffer.data());
channel.send("OK " + buffer);
}
std::this_thread::sleep_for(1ms);
}
printf("Terminating worker\n");
}
}

19
src/Worker/Runner.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
namespace Worker
{
class Runner
{
public:
Runner(int pid);
~Runner();
void run();
private:
void worker();
int processId;
bool terminate;
};
}

65
src/Worker/Worker.cpp Normal file
View File

@ -0,0 +1,65 @@
#include "STDInclude.hpp"
namespace Worker
{
int ProcessId;
int __stdcall EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, char* /*lpCmdLine*/, int /*nCmdShow*/)
{
Runner runner(Worker::ProcessId);
runner.run();
return 0;
}
void Initialize()
{
if(!Steam::Proxy::Inititalize())
{
printf("Failed to initialize worker!\n");
ExitProcess(1);
}
else
{
#ifdef DEBUG
SetConsoleTitleA("IW4x Worker");
#else
FreeConsole();
#endif
Utils::Hook(0x6BABA1, Worker::EntryPoint, HOOK_CALL).install()->quick();
}
}
void Uninitialize()
{
Steam::Proxy::Uninititalize();
}
bool ParseWorkerFlag()
{
char* command = "-parent ";
char* parentProc = strstr(GetCommandLineA(), command);
if (parentProc)
{
parentProc += strlen(command);
Worker::ProcessId = atoi(parentProc);
return true;
}
return false;
}
bool IsWorker()
{
static Utils::Value<bool> flag;
if (!flag.isValid())
{
flag.set(Worker::ParseWorkerFlag());
}
return flag.get();
}
}

11
src/Worker/Worker.hpp Normal file
View File

@ -0,0 +1,11 @@
#pragma once
namespace Worker
{
void Initialize();
void Uninitialize();
bool IsWorker();
}
#include "Runner.hpp"