diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e413c59
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.vs
+_Build
+*.vcxproj.user
\ No newline at end of file
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
new file mode 100644
index 0000000..2d51f18
--- /dev/null
+++ b/Common/Common.vcxproj
@@ -0,0 +1,211 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+ 16.0
+ Win32Proj
+ {f364b2ab-f34a-4bcf-9362-22720020ddbf}
+ Common
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v142
+ Unicode
+
+
+ StaticLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v142
+ Unicode
+
+
+ StaticLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+
+
+ false
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+
+
+ true
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+
+
+ false
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+ $(ProjectDir)_Build\$(Configuration)\$(Platform)\
+
+
+ $(PlatformTarget)-windows-static
+ true
+
+
+ $(PlatformTarget)-windows-static
+ true
+
+
+ $(PlatformTarget)-windows-static
+ true
+
+
+ $(PlatformTarget)-windows-static
+ true
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ %(AdditionalIncludeDirectories)
+ MultiThreadedDebug
+ stdcpp17
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ %(AdditionalIncludeDirectories)
+ MultiThreaded
+ stdcpp17
+
+
+
+
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ %(AdditionalIncludeDirectories)
+ MultiThreadedDebug
+ stdcpp17
+
+
+
+
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ %(AdditionalIncludeDirectories)
+ MultiThreaded
+ stdcpp17
+
+
+
+
+ true
+ true
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
new file mode 100644
index 0000000..cd51572
--- /dev/null
+++ b/Common/Common.vcxproj.filters
@@ -0,0 +1,47 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/Common/src/Config.cpp b/Common/src/Config.cpp
new file mode 100644
index 0000000..3cef775
--- /dev/null
+++ b/Common/src/Config.cpp
@@ -0,0 +1,55 @@
+#include "pch.h"
+#include "Config.h"
+#include "util.h"
+
+using nlohmann::json;
+
+// Source: https://stackoverflow.com/a/54394658/3805929
+#define GET(j, key) this->key = j[#key].get()
+
+void from_json(const json& j, Platform& p)
+{
+ j["enabled"].get_to(p.enabled);
+ j["process"].get_to(p.process);
+ j["replicate"].get_to(p.replicate);
+ j["ignore"].get_to(p.ignore);
+ j["blacklist"].get_to(p.blacklist);
+}
+
+Config::Config()
+{
+ auto fullPath = getWorkingDirPath() / L"Config.jsonc";
+
+ std::ifstream ifs(fullPath, std::ios::in);
+
+ if(!ifs.good())
+ {
+ MessageBox(NULL, fullPath.c_str(), L"Config not found at: ", MB_ICONERROR | MB_ICONERROR);
+ exit(1);
+ }
+
+ try
+ {
+ auto j = json::parse(ifs, nullptr, true, true);
+
+ GET(j, log_level);
+ GET(j, platforms);
+ GET(j, ignore);
+ GET(j, terminate);
+ } catch(json::exception e)
+ {
+ MessageBoxA(NULL, e.what(), "Error parsing config file", MB_ICONERROR | MB_ICONERROR);
+ exit(1);
+ }
+}
+
+void Config::init()
+{
+ if(config != nullptr)
+ return;
+
+ config = new Config();
+}
+
+// Every app must call the config constructor first.
+Config* config = nullptr;
diff --git a/Common/src/Config.h b/Common/src/Config.h
new file mode 100644
index 0000000..5d474e5
--- /dev/null
+++ b/Common/src/Config.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "framework.h"
+#include "util.h"
+
+struct Platform
+{
+ bool enabled = true;
+ string process;
+ bool replicate = false;
+ vector ignore;
+ vector blacklist;
+};
+
+class Config
+{
+protected:
+ Config();
+public:
+ string log_level;
+ map platforms;
+ vector ignore;
+ vector terminate;
+
+ static void init();
+};
+
+extern Config* config;
diff --git a/Common/src/Logger.cpp b/Common/src/Logger.cpp
new file mode 100644
index 0000000..717c586
--- /dev/null
+++ b/Common/src/Logger.cpp
@@ -0,0 +1,35 @@
+#include "pch.h"
+#include "Logger.h"
+#include "Config.h"
+
+namespace Logger
+{
+
+void init(string loggerName, bool truncate)
+{
+ Config::init();
+ if(config->log_level == "off")
+ return;
+
+ try
+ {
+ auto processPath = getProcessPath();
+ auto fileName = fmt::format("{}.{}.log", loggerName, processPath.stem().string());
+ auto path = getWorkingDirPath() / "logs" / fileName;
+ logger = spdlog::basic_logger_mt(loggerName, path.u8string(), truncate);
+ logger->set_pattern("[%H:%M:%S.%e] [%l]\t%v");
+ logger->set_level(spdlog::level::from_str(config->log_level));
+ logger->flush_on(spdlog::level::debug);
+ } catch(const spdlog::spdlog_ex& ex)
+ {
+ // Now if we can't open log file, something must be really wrong, hence we exit.
+ auto message = stow(string(ex.what()));
+ MessageBox(NULL, message.c_str(), L"Failed to initialize the log file", MB_ICONERROR | MB_OK);
+ exit(1);
+ }
+
+}
+
+}
+
+shared_ptr logger = spdlog::null_logger_mt("null");
diff --git a/Common/src/Logger.h b/Common/src/Logger.h
new file mode 100644
index 0000000..c30afe1
--- /dev/null
+++ b/Common/src/Logger.h
@@ -0,0 +1,11 @@
+#pragma once
+#include "util.h"
+
+extern shared_ptr logger;
+
+namespace Logger
+{
+
+void init(string loggerName, bool truncate);
+
+}
diff --git a/Common/src/constants.h b/Common/src/constants.h
new file mode 100644
index 0000000..21a2e84
--- /dev/null
+++ b/Common/src/constants.h
@@ -0,0 +1,23 @@
+#pragma once
+
+constexpr auto VERSION = "1.0.0";
+constexpr auto WORKING_DIR = L"WORKING_DIR";
+
+constexpr auto INTEGRATION_64 = L"Integration64.dll";
+constexpr auto INTEGRATION_32 = L"Integration32.dll";
+
+#ifdef _WIN64
+
+constexpr auto EOSSDK = L"EOSSDK-Win64-Shipping.dll";
+constexpr auto STEAMAPI = L"steam_api64.dll";
+constexpr auto UPLAY_R2 = L"uplay_r2_loader64.dll";
+
+#else
+
+constexpr auto EOSSDK = L"EOSSDK-Win32-Shipping.dll";
+constexpr auto STEAMAPI = L"steam_api.dll";
+constexpr auto UPLAY_R2 = L"uplay_r2_loader.dll";
+
+#endif
+
+constexpr auto ORIGINCLIENT = L"OriginClient.dll";
diff --git a/Common/src/framework.h b/Common/src/framework.h
new file mode 100644
index 0000000..c8926e6
--- /dev/null
+++ b/Common/src/framework.h
@@ -0,0 +1,35 @@
+#pragma once
+#include
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include