diff --git a/LICENSE b/LICENSE
index aae4ee8..d05522f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2021 HardCoded
+Copyright (c) 2021 HardCoded and TechnologicNick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/PluginDevFolder/SMLuaHook/SMLuaHook.vcxproj b/PluginDevFolder/SMLuaHook/SMLuaHook.vcxproj
new file mode 100644
index 0000000..08df75f
--- /dev/null
+++ b/PluginDevFolder/SMLuaHook/SMLuaHook.vcxproj
@@ -0,0 +1,124 @@
+
+
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 16.0
+ Win32Proj
+ {93661f1d-21dc-4b5b-88ec-6bea337df56b}
+ SMLuaHook
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v142
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)..\SMLibrary\include;$(IncludePath)
+ $(OutDir);$(LibraryPath)
+
+
+ false
+ $(SolutionDir)..\SMLibrary\include;$(IncludePath)
+ $(OutDir);$(LibraryPath)
+
+
+
+ Level3
+ true
+ _DEBUG;SMLUAHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+ stdcpp17
+
+
+ Windows
+ true
+ false
+ smlibrary.lib
+
+
+ if not exist "$(OutputPath)plugins\" mkdir "$(OutputPath)plugins\"
+copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;SMLUAHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ NotUsing
+ pch.h
+ stdcpp17
+
+
+ Windows
+ true
+ true
+ true
+ false
+ smlibrary.lib
+
+
+ if not exist "$(OutputPath)plugins\" mkdir "$(OutputPath)plugins\"
+copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaHook/SMLuaHook.vcxproj.filters b/PluginDevFolder/SMLuaHook/SMLuaHook.vcxproj.filters
new file mode 100644
index 0000000..127eef9
--- /dev/null
+++ b/PluginDevFolder/SMLuaHook/SMLuaHook.vcxproj.filters
@@ -0,0 +1,33 @@
+
+
+
+
+ {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
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaHook/hooks.h b/PluginDevFolder/SMLuaHook/hooks.h
new file mode 100644
index 0000000..c01b763
--- /dev/null
+++ b/PluginDevFolder/SMLuaHook/hooks.h
@@ -0,0 +1,86 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+#include
+using Console::Color;
+
+#include "lua_hook_config.h"
+
+
+// LUAL_REGISTER
+typedef void (*pluaL_register)(lua_State*, const char*, const luaL_Reg*);
+GameHook* hck_luaL_register;
+
+// LUAL_LOADSTRING
+typedef int (*pluaL_loadstring)(lua_State*, const char*);
+GameHook* hck_luaL_loadstring;
+
+// LUA_NEWSTATE
+typedef lua_State* (*plua_newstate)(lua_Alloc, void*);
+GameHook* hck_lua_newstate;
+
+// LUAL_LOADBUFFER
+typedef int (*pluaL_loadbuffer)(lua_State*, const char*, size_t, const char*);
+GameHook* hck_luaL_loadbuffer;
+
+// =============
+
+namespace LuaHook::Hooks {
+ void hook_luaL_register(lua_State* L, const char* libname, const luaL_Reg* l) {
+ Console::log(Color::Aqua, "hook_luaL_register: libname=[%s]", libname);
+
+ const luaL_Reg* ptr = l;
+
+ int i = 0;
+ while (ptr->name != NULL) {
+ Console::log(Color::Aqua, "hook_luaL_register: luaL_Reg[%d] name=[%s] func=[%p]", i++, ptr->name, (void*)ptr->func);
+
+ ptr++;
+ }
+
+ return ((pluaL_register)*hck_luaL_register)(L, libname, l);
+ }
+
+ int hook_luaL_loadstring(lua_State* L, const char* s) {
+ Console::log(Color::Aqua, "hook_luaL_loadstring: s=[ ... ]");
+
+ std::map fields = {
+ {"s", &s}
+ };
+
+ std::string input(s);
+
+ if (LuaHook::runLuaHook("luaL_loadstring", &input, fields)) {
+ Console::log(Color::Green, "Set contents to:\n%s", input.c_str());
+ return ((pluaL_loadstring)*hck_luaL_loadstring)(L, input.c_str());
+ }
+
+ return ((pluaL_loadstring)*hck_luaL_loadstring)(L, s);
+ }
+
+ lua_State* hook_lua_newstate(lua_Alloc f, void* ud) {
+ Console::log(Color::Aqua, "hck_lua_newstate: ud=[%p]", ud);
+ return ((plua_newstate)*hck_lua_newstate)(f, ud);
+ }
+
+ int hook_luaL_loadbuffer(lua_State* L, const char* buff, size_t sz, const char* name) {
+ Console::log(Color::Aqua, "hck_luaL_loadbuffer: buff=[ ... ], sz=[%zu], name=[%s]", sz, name);
+
+ std::map fields = {
+ {"buff", &buff},
+ {"name", &name}
+ };
+
+ std::string input(buff, sz);
+
+ if (size_t executeCount = LuaHook::runLuaHook("luaL_loadbuffer", &input, fields)) {
+ Console::log(Color::Green, "Set contents to:\n%s", input.c_str());
+ return ((pluaL_loadbuffer)*hck_luaL_loadbuffer)(L, input.c_str(), input.size(), name);
+ }
+
+ return ((pluaL_loadbuffer)*hck_luaL_loadbuffer)(L, buff, sz, name);
+ }
+}
diff --git a/PluginDevFolder/SMLuaHook/lua_hook_config.h b/PluginDevFolder/SMLuaHook/lua_hook_config.h
new file mode 100644
index 0000000..0b78206
--- /dev/null
+++ b/PluginDevFolder/SMLuaHook/lua_hook_config.h
@@ -0,0 +1,330 @@
+#pragma once
+#pragma warning(push)
+#pragma warning(disable : 26819 28020)
+#define JSON_DIAGNOSTICS 1
+#include
+#pragma warning(pop)
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace fs = std::filesystem;
+
+using json = nlohmann::json;
+
+namespace LuaHook {
+
+ struct selector;
+ struct executor;
+ struct hookItem;
+
+ typedef std::function& fields, hookItem& hookItem, selector& selector)> selectorFunction;
+ typedef std::function& fields, hookItem& hookItem, executor& executor)> executorFunction;
+
+ struct selector {
+ selectorFunction* func;
+
+ json j_selector;
+ };
+
+ struct executor {
+ executorFunction* func;
+
+ json j_executor;
+ };
+
+ struct hookItem {
+ float priority = 1;
+ std::vector selector;
+ std::vector execute;
+
+ json j_hook;
+
+ bool operator<(const hookItem& other) const {
+ return this->priority < other.priority;
+ }
+ };
+
+ namespace SelectorHelper {
+
+ std::any getInput(std::map& fields, hookItem& hookItem, selector& selector) {
+ if (selector.j_selector.contains("field")) {
+ std::string fieldName = selector.j_selector.at("field");
+
+ if (fields.find(fieldName) == fields.end()) {
+ throw new std::invalid_argument("Field not found");
+ }
+
+ return fields[fieldName];
+ }
+ else {
+ if (fields.size() == 1) {
+ return fields.begin()->second;
+ }
+ else {
+ // Throw an exception
+ selector.j_selector.at("field");
+ return NULL;
+ }
+ }
+ }
+
+ std::string getInputConstCharPtr(std::map& fields, hookItem& hookItem, selector& selector) {
+ std::any input = SelectorHelper::getInput(fields, hookItem, selector);
+
+ if (const char*** str = std::any_cast(&input)) {
+ return std::string(**str);
+ }
+ else {
+ throw new std::invalid_argument(std::string("Field type not castable to const char**: ") + input.type().name());
+ }
+ }
+
+ }
+
+ std::map selectorFunctions = {
+ {
+ "CONTAINS", [](std::map& fields, hookItem& hookItem, selector& selector) {
+ std::string input = SelectorHelper::getInputConstCharPtr(fields, hookItem, selector);
+
+ std::string value = selector.j_selector.at("value");
+
+ return input.find(value) != std::string::npos;
+ }
+ },
+ {
+ "EQUALS", [](std::map& fields, hookItem& hookItem, selector& selector) {
+ std::string input = SelectorHelper::getInputConstCharPtr(fields, hookItem, selector);
+
+ std::string value = selector.j_selector.at("value");
+
+ return input.compare(value) == 0;
+ }
+ }
+ };
+
+
+
+ namespace ExecutorHelper {
+
+ std::string readFile(fs::path path) {
+ std::ifstream in(path);
+
+ if (in.fail()) {
+#pragma warning(suppress : 4996)
+ throw std::exception((std::string() + "Failed to open file \"" + path.string() + "\": " + strerror(errno)).c_str());
+ }
+
+ std::ostringstream sstr;
+ sstr << in.rdbuf();
+ return sstr.str();
+ }
+
+ }
+
+ std::map executorFunctions = {
+ {
+ "REPLACE_CONTENT_WITH_FILE", [](std::string* input, std::map& fields, hookItem& hookItem, executor& executor) {
+ return input->assign(LuaHook::ExecutorHelper::readFile(PathHelper::resolvePath(executor.j_executor.at("file"))));
+ }
+ },
+ {
+ "PREPEND_FILE", [](std::string* input, std::map& fields, hookItem& hookItem, executor& executor) {
+ return input->insert(0, LuaHook::ExecutorHelper::readFile(PathHelper::resolvePath(executor.j_executor.at("file"))).append("\n"));
+ }
+ },
+ {
+ "APPEND_FILE", [](std::string* input, std::map& fields, hookItem& hookItem, executor& executor) {
+ return input->append("\n").append(LuaHook::ExecutorHelper::readFile(PathHelper::resolvePath(executor.j_executor.at("file"))));
+ }
+ },
+ {
+ "PREPEND_STRING", [](std::string* input, std::map& fields, hookItem& hookItem, executor& executor) {
+ return input->insert(0, executor.j_executor.at("string").get().append("\n"));
+ }
+ },
+ {
+ "APPEND_STRING", [](std::string* input, std::map& fields, hookItem& hookItem, executor& executor) {
+ return input->append("\n").append(executor.j_executor.at("string"));
+ }
+ }
+ };
+
+
+
+ void from_json(const json& j, selector& s) {
+ std::string op = j.at("operator").get();
+
+ if (selectorFunctions.find(op) == selectorFunctions.end()) {
+ std::vector opList;
+ for (auto const& opFunc : selectorFunctions) {
+ opList.push_back(opFunc.first);
+ }
+
+ throw std::exception((std::string() + "Unknown operator \"" + op + "\". Possible operators: " + json(opList).dump()).c_str());
+ }
+
+ s.func = &selectorFunctions.at(op);
+
+ j.get_to(s.j_selector);
+ }
+
+ void from_json(const json& j, executor& e) {
+ std::string command = j.at("command").get();
+
+ if (executorFunctions.find(command) == executorFunctions.end()) {
+ std::vector commandList;
+ for (auto const& cmdFunc : executorFunctions) {
+ commandList.push_back(cmdFunc.first);
+ }
+
+ throw std::exception((std::string() + "Unknown command \"" + command + "\". Possible commands: " + json(commandList).dump()).c_str());
+ }
+
+ e.func = &executorFunctions.at(command);
+
+ j.get_to(e.j_executor);
+ }
+
+ void from_json(const json& j, hookItem& hi) {
+ j.at("priority").get_to(hi.priority);
+ j.at("selector").get_to(hi.selector);
+ j.at("execute").get_to(hi.execute);
+
+ j.get_to(hi.j_hook);
+ }
+
+
+
+ class HookConfig {
+ public:
+ inline static std::vector enabledConfigs;
+
+ private:
+ json root;
+ std::map> hooks;
+ bool enabled = false;
+
+ public:
+ HookConfig(json root) {
+ this->root = root;
+
+ for (auto& [key, value] : this->root.at("hooks").items()) {
+ try {
+ this->hooks[key] = value.get>();
+ }
+ catch (json::exception e) {
+ Console::log(Color::LightRed, "Failed parsing %s hooks: %s", key.c_str(), e.what());
+ }
+ catch (std::exception e) {
+ Console::log(Color::LightRed, "Failed processing %s hooks: %s", key.c_str(), e.what());
+ }
+ }
+ }
+
+ ~HookConfig() {
+ if (this->enabled) {
+ Console::log(Color::LightYellow, "Warning: Deconstructing HookConfig while enabled!");
+ }
+ }
+
+ void setEnabled(bool enabled) {
+ if (enabled == this->enabled) {
+ return;
+ }
+
+ if (enabled) {
+ // Add this
+ HookConfig::enabledConfigs.push_back(this);
+ }
+ else {
+ // Remove this
+ HookConfig::enabledConfigs.erase(std::remove(HookConfig::enabledConfigs.begin(), HookConfig::enabledConfigs.end(), this), HookConfig::enabledConfigs.end());
+ }
+ }
+
+ static std::vector getHookItems(std::string name) {
+ size_t totalSize = 0;
+
+ // Calculate the total size
+ for (auto& hookConfig : HookConfig::enabledConfigs) {
+ if (hookConfig->hooks.find(name) == hookConfig->hooks.end())
+ continue;
+
+ totalSize += hookConfig->hooks[name].size();
+ }
+
+ std::vector items;
+ items.reserve(totalSize);
+
+ // Insert all hookItems into items
+ for (auto& hookConfig : HookConfig::enabledConfigs) {
+ if (hookConfig->hooks.find(name) == hookConfig->hooks.end())
+ continue;
+
+ items.insert(items.end(), hookConfig->hooks[name].begin(), hookConfig->hooks[name].end());
+ }
+
+ std::sort(items.begin(), items.end());
+
+ return items;
+ }
+
+ static std::set getHookNames() {
+ std::set names;
+
+ // Insert all hookItems into items
+ for (auto& hookConfig : HookConfig::enabledConfigs) {
+ for (auto& [hookName, hookItems] : hookConfig->hooks) {
+ names.insert(hookName);
+ }
+ }
+
+ return names;
+ }
+
+ };
+
+
+
+ size_t runLuaHook(std::string name, std::string* input, std::map& fields) {
+ size_t executeCount = 0;
+
+ for (hookItem& hookItem : HookConfig::getHookItems(name)) {
+ bool selected = true;
+
+ for (selector& selector : hookItem.selector) {
+ selected &= (*selector.func)(fields, hookItem, selector);
+
+ Console::log(selected ? Color::LightPurple : Color::Purple, selected ? "selected" : "not selected");
+
+ if (!selected) {
+ break;
+ }
+ }
+
+ if (selected) {
+
+ for (executor& executor : hookItem.execute) {
+ try {
+ (*executor.func)(input, fields, hookItem, executor);
+
+ executeCount++;
+ }
+ catch (std::exception& e) {
+ Console::log(Color::LightRed, "Failed executing executor %s: %s", executor.j_executor.dump(4).c_str(), e.what());
+ }
+ }
+
+ }
+ }
+
+ return executeCount;
+ }
+
+}
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaHook/main.cpp b/PluginDevFolder/SMLuaHook/main.cpp
new file mode 100644
index 0000000..d855217
--- /dev/null
+++ b/PluginDevFolder/SMLuaHook/main.cpp
@@ -0,0 +1,145 @@
+#define _SM_LIBRARY_BUILD_PLUGIN
+#define _SM_PLUGIN_NAME SMLuaHook
+
+#include
+#include
+#include
+#include
+
+using Console::Color;
+
+#include "hooks.h"
+#include "lua_hook_config.h"
+bool InjectLua();
+
+LIB_RESULT PluginLoad() {
+ Console::log(Color::Aqua, "Starting plugin ...");
+
+ if (!InjectLua()) {
+ Console::log(Color::Red, "Failed to inject lua functions");
+ return PLUGIN_ERROR;
+ }
+
+ return PLUGIN_SUCCESSFULL;
+}
+
+const char* defaultConfig = R"(// Configuration file for hooking the Lua C API
+{
+ "hooks": {
+
+ // This function is used for setting up the Lua environment
+ "luaL_loadstring": [
+ /*
+ {
+ // Replace the environment table (the functions accessible inside
+ // the lua sandbox) with an environment table loaded from a file
+
+ // Hooks are ran from high to low priority
+ "priority": 1,
+
+ // All selectors must result in true for commands to be ran
+ "selector": [
+ {
+ // The "name" field can be omitted if the hooked function has
+ // at most one string field (check the (Lua/Luajit) source code)
+
+ // "name": "s",
+ "operator": "CONTAINS",
+ "value": "unsafe_env"
+ }
+ ],
+
+ "execute": [
+ {
+ "command": "REPLACE_CONTENT_WITH_FILE",
+ "file": "$PLUGIN_CONFIG/override/unsafe_env.lua"
+ }
+ ]
+ }
+ */
+ ],
+
+ // All files the game tries to load pass through here
+ "luaL_loadbuffer": [
+ /*
+ {
+ // Enable survival dev mode
+
+ "priority": 1,
+ "selector": [
+ {
+ "field": "name",
+ "operator": "EQUALS",
+ "value": "Survival/Scripts/game/SurvivalGame.lua"
+ }
+ ],
+ "execute": [
+ {
+ "command": "PREPEND_STRING",
+ "string": "g_survivalDev = true"
+ }
+ ]
+ }
+ */
+ ]
+
+ }
+}
+)";
+
+bool InjectLua() {
+ Console::log(Color::Aqua, "Installing lua hooks");
+
+ hck_luaL_register = GameHooks::InjectFromName("lua51.dll", "luaL_register", &LuaHook::Hooks::hook_luaL_register, 15);
+ hck_luaL_loadstring = GameHooks::InjectFromName("lua51.dll", "luaL_loadstring", &LuaHook::Hooks::hook_luaL_loadstring, 16);
+ hck_lua_newstate = GameHooks::InjectFromName("lua51.dll", "lua_newstate", &LuaHook::Hooks::hook_lua_newstate, 6);
+ hck_luaL_loadbuffer = GameHooks::InjectFromName("lua51.dll", "luaL_loadbuffer", &LuaHook::Hooks::hook_luaL_loadbuffer, 13);
+
+ if (!hck_luaL_register) {
+ Console::log(Color::Red, "Failed to inject 'luaL_register'");
+ return false;
+ }
+
+ if (!hck_luaL_loadstring) {
+ Console::log(Color::Red, "Failed to inject 'luaL_loadstring'");
+ return false;
+ }
+
+ if (!hck_lua_newstate) {
+ Console::log(Color::Red, "Failed to inject 'lua_newstate'");
+ return false;
+ }
+
+ if (!hck_luaL_loadbuffer) {
+ Console::log(Color::Red, "Failed to inject 'luaL_loadbuffer'");
+ return false;
+ }
+
+ PluginConfig config(_LIB_PLUGIN_NAME_STR, "lua_hooks.json");
+ config.setDefaultContent(defaultConfig);
+ config.createIfNotExists();
+ config.load();
+
+ try {
+ Console::log(Color::Aqua, "Loading Lua C API hook config files...");
+ LuaHook::HookConfig *hookConfig = new LuaHook::HookConfig(config.root);
+ hookConfig->setEnabled(true);
+ }
+ catch (const json::exception& e) {
+ Console::log(Color::LightRed, "Failed initialising HookConfig: %s", e.what());
+ }
+
+ Console::log(Color::Aqua, "Loaded %llu Lua C API hook config files", LuaHook::HookConfig::enabledConfigs.size());
+ for (auto& hookName : LuaHook::HookConfig::getHookNames()) {
+ Console::log(Color::Aqua, " %s (%llu)", hookName.c_str(), LuaHook::HookConfig::getHookItems(hookName).size());
+ }
+
+
+ return true;
+}
+
+LIB_RESULT PluginUnload() {
+ Console::log(Color::Aqua, "Unloading this plugin!");
+ //util->Unload();
+ return PLUGIN_SUCCESSFULL;
+}
diff --git a/PluginDevFolder/SMLuaHook/packages.config b/PluginDevFolder/SMLuaHook/packages.config
new file mode 100644
index 0000000..a51867b
--- /dev/null
+++ b/PluginDevFolder/SMLuaHook/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj b/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj
index c86cf1c..ef294b4 100644
--- a/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj
+++ b/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj
@@ -15,7 +15,9 @@
-
+
+
+
16.0
@@ -69,6 +71,7 @@
NotUsing
+ stdcpp17
Windows
@@ -96,6 +99,7 @@ copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"NotUsing
+ stdcpp17
Windows
@@ -116,5 +120,12 @@ copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj.filters b/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj.filters
index abc8bae..f362751 100644
--- a/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj.filters
+++ b/PluginDevFolder/SMLuaReaderPlugin/SMLuaReaderPlugin.vcxproj.filters
@@ -17,8 +17,8 @@
Header Files
-
- Header Files
-
+
+
+
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaReaderPlugin/packages.config b/PluginDevFolder/SMLuaReaderPlugin/packages.config
new file mode 100644
index 0000000..8226e66
--- /dev/null
+++ b/PluginDevFolder/SMLuaReaderPlugin/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h b/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h
index 6681f9e..916561b 100644
--- a/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h
+++ b/PluginDevFolder/SMLuaReaderPlugin/src/hooks.h
@@ -1,6 +1,7 @@
+#pragma once
#include
#include
-#include "lua.h"
+#include
#include
using Console::Color;
@@ -12,35 +13,42 @@ GameHook* hck_luaL_register;
// LUAL_LOADSTRING
typedef int (*pluaL_loadstring)(lua_State*, const char*);
-GameHook *hck_luaL_loadstring;
+GameHook* hck_luaL_loadstring;
// LUA_NEWSTATE
-typedef lua_State *(*plua_newstate)(lua_Alloc, void*);
-GameHook *hck_lua_newstate;
+typedef lua_State* (*plua_newstate)(lua_Alloc, void*);
+GameHook* hck_lua_newstate;
// LUAL_LOADBUFFER
typedef int (*pluaL_loadbuffer)(lua_State*, const char*, size_t, const char*);
-GameHook *hck_luaL_loadbuffer;
+GameHook* hck_luaL_loadbuffer;
// =============
namespace Hooks {
- void hook_luaL_register(lua_State *L, const char *libname, const luaL_Reg *l) {
+ void hook_luaL_register(lua_State* L, const char* libname, const luaL_Reg* l) {
Console::log(Color::Aqua, "hook_luaL_register: libname=[%s]", libname);
+
+ const luaL_Reg* ptr = l;
+
+ for (int i = 0; ptr->name != NULL; i++, ptr++) {
+ Console::log(Color::Aqua, "hook_luaL_register: luaL_Reg[%d] name=[%s] func=[%p]", i, ptr->name, (void*)ptr->func);
+ }
+
return ((pluaL_register)*hck_luaL_register)(L, libname, l);
}
- int hook_luaL_loadstring(lua_State *L, const char *s) {
+ int hook_luaL_loadstring(lua_State* L, const char* s) {
Console::log(Color::Aqua, "hook_luaL_loadstring: s=[ ... ]");
return ((pluaL_loadstring)*hck_luaL_loadstring)(L, s);
}
- lua_State *hook_lua_newstate(lua_Alloc f, void* ud) {
+ lua_State* hook_lua_newstate(lua_Alloc f, void* ud) {
Console::log(Color::Aqua, "hck_lua_newstate: ud=[%p]", ud);
return ((plua_newstate)*hck_lua_newstate)(f, ud);
}
- int hook_luaL_loadbuffer(lua_State *L, const char *buff, size_t sz, const char *name) {
+ int hook_luaL_loadbuffer(lua_State* L, const char* buff, size_t sz, const char* name) {
Console::log(Color::Aqua, "hck_luaL_loadbuffer: buff=[ ... ], sz=[%zu], name=[%s]", sz, name);
return ((pluaL_loadbuffer)*hck_luaL_loadbuffer)(L, buff, sz, name);
}
diff --git a/PluginDevFolder/SMLuaReaderPlugin/src/lua.h b/PluginDevFolder/SMLuaReaderPlugin/src/lua.h
deleted file mode 100644
index f0113d9..0000000
--- a/PluginDevFolder/SMLuaReaderPlugin/src/lua.h
+++ /dev/null
@@ -1,7 +0,0 @@
-typedef void *(*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
-typedef struct lua_State lua_State;
-typedef int (*lua_CFunction) (lua_State *L);
-typedef struct luaL_Reg {
- const char *name;
- lua_CFunction func;
-} luaL_Reg;
diff --git a/PluginDevFolder/SMPluginTemplate/SMPluginTemplate.vcxproj b/PluginDevFolder/SMPluginTemplate/SMPluginTemplate.vcxproj
index 0003fc3..0fb0b04 100644
--- a/PluginDevFolder/SMPluginTemplate/SMPluginTemplate.vcxproj
+++ b/PluginDevFolder/SMPluginTemplate/SMPluginTemplate.vcxproj
@@ -1,14 +1,6 @@
-
- Debug
- Win32
-
-
- Release
- Win32
-
Debug
x64
@@ -29,19 +21,6 @@
10.0
-
- DynamicLibrary
- true
- v142
- Unicode
-
-
- DynamicLibrary
- false
- v142
- true
- Unicode
-
DynamicLibrary
true
@@ -60,12 +39,6 @@
-
-
-
-
-
-
@@ -73,16 +46,6 @@
-
- true
- $(SolutionDir)..\SMLibrary\include;$(IncludePath)
- $(OutDir);$(LibraryPath)
-
-
- false
- $(SolutionDir)..\SMLibrary\include;$(IncludePath)
- $(OutDir);$(LibraryPath)
-
true
$(SolutionDir)..\SMLibrary\include;$(IncludePath)
@@ -93,60 +56,6 @@
$(SolutionDir)..\SMLibrary\include;$(IncludePath)
$(OutDir);$(LibraryPath)
-
-
- Level3
- true
- WIN32;_DEBUG;SMPLUGINTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- NotUsing
-
-
-
-
- Windows
- true
- false
- smlibrary.lib;%(AdditionalDependencies)
-
-
- if not exist "$(OutputPath)plugins\" mkdir "$(OutputPath)plugins\"
-copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
-
-
-
-
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;SMPLUGINTEMPLATE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- NotUsing
-
-
-
-
- Windows
- true
- true
- true
- false
- smlibrary.lib;%(AdditionalDependencies)
-
-
- if not exist "$(OutputPath)plugins\" mkdir "$(OutputPath)plugins\"
-copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
-
-
-
-
-
-
Level3
@@ -156,6 +65,7 @@ copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"NotUsing
+ stdcpp17
Windows
@@ -183,6 +93,7 @@ copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"NotUsing
+ stdcpp17
Windows
diff --git a/PluginDevFolder/TileEditorUnlockPlugin/TileEditorUnlockPlugin.vcxproj b/PluginDevFolder/TileEditorUnlockPlugin/TileEditorUnlockPlugin.vcxproj
index 0973a43..74b2dd6 100644
--- a/PluginDevFolder/TileEditorUnlockPlugin/TileEditorUnlockPlugin.vcxproj
+++ b/PluginDevFolder/TileEditorUnlockPlugin/TileEditorUnlockPlugin.vcxproj
@@ -1,14 +1,6 @@
-
- Debug
- Win32
-
-
- Release
- Win32
-
Debug
x64
@@ -29,19 +21,6 @@
10.0
-
- DynamicLibrary
- true
- v142
- Unicode
-
-
- DynamicLibrary
- false
- v142
- true
- Unicode
-
DynamicLibrary
true
@@ -60,12 +39,6 @@
-
-
-
-
-
-
@@ -73,16 +46,6 @@
-
- true
- $(SolutionDir)..\SMLibrary\include;$(IncludePath)
- $(OutDir);$(LibraryPath)
-
-
- false
- $(SolutionDir)..\SMLibrary\include;$(IncludePath)
- $(OutDir);$(LibraryPath)
-
true
$(SolutionDir)..\SMLibrary\include;$(IncludePath)
@@ -93,52 +56,6 @@
$(SolutionDir)..\SMLibrary\include;$(IncludePath)
$(OutDir);$(LibraryPath)
-
-
- Level3
- true
- WIN32;_DEBUG;TILEEDITORUNLOCKPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- NotUsing
-
-
-
-
- Windows
- true
- false
- smlibrary.lib;%(AdditionalDependencies)
-
-
- if not exist "$(OutputPath)plugins\" mkdir "$(OutputPath)plugins\"
-copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;TILEEDITORUNLOCKPLUGIN_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
- true
- NotUsing
-
-
-
-
- Windows
- true
- true
- true
- false
- smlibrary.lib;%(AdditionalDependencies)
-
-
- if not exist "$(OutputPath)plugins\" mkdir "$(OutputPath)plugins\"
-copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"
-
-
Level3
@@ -148,6 +65,7 @@ copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"NotUsing
+ stdcpp17
Windows
@@ -171,6 +89,7 @@ copy /B "$(LocalDebuggerCommand)" "$(OutputPath)plugins\$(TargetFileName)"NotUsing
+ stdcpp17
Windows
diff --git a/SMInjector/SMInjector.sln b/SMInjector/SMInjector.sln
index a160e7b..6b362ff 100644
--- a/SMInjector/SMInjector.sln
+++ b/SMInjector/SMInjector.sln
@@ -24,58 +24,33 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMLuaReaderPlugin", "..\Plu
{81368E09-9FA2-4F28-9915-22FE758BFD48} = {81368E09-9FA2-4F28-9915-22FE758BFD48}
EndProjectSection
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PlaygroundPlugin", "..\PluginDevFolder\PlaygroundPlugin\PlaygroundPlugin.vcxproj", "{53AE29AD-5DEB-4557-A65E-6E68D2E5336A}"
- ProjectSection(ProjectDependencies) = postProject
- {81368E09-9FA2-4F28-9915-22FE758BFD48} = {81368E09-9FA2-4F28-9915-22FE758BFD48}
- EndProjectSection
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SMLuaHook", "..\PluginDevFolder\SMLuaHook\SMLuaHook.vcxproj", "{93661F1D-21DC-4B5B-88EC-6BEA337DF56B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
Release|x64 = Release|x64
- Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E94AFAD6-2262-40E4-81D3-CD0130B98C0B}.Debug|x64.ActiveCfg = Debug|x64
- {E94AFAD6-2262-40E4-81D3-CD0130B98C0B}.Debug|x86.ActiveCfg = Debug|x64
{E94AFAD6-2262-40E4-81D3-CD0130B98C0B}.Release|x64.ActiveCfg = Release|x64
{E94AFAD6-2262-40E4-81D3-CD0130B98C0B}.Release|x64.Build.0 = Release|x64
- {E94AFAD6-2262-40E4-81D3-CD0130B98C0B}.Release|x86.ActiveCfg = Release|x64
{81368E09-9FA2-4F28-9915-22FE758BFD48}.Debug|x64.ActiveCfg = Debug|x64
- {81368E09-9FA2-4F28-9915-22FE758BFD48}.Debug|x86.ActiveCfg = Debug|Win32
- {81368E09-9FA2-4F28-9915-22FE758BFD48}.Debug|x86.Build.0 = Debug|Win32
{81368E09-9FA2-4F28-9915-22FE758BFD48}.Release|x64.ActiveCfg = Release|x64
{81368E09-9FA2-4F28-9915-22FE758BFD48}.Release|x64.Build.0 = Release|x64
- {81368E09-9FA2-4F28-9915-22FE758BFD48}.Release|x86.ActiveCfg = Release|Win32
- {81368E09-9FA2-4F28-9915-22FE758BFD48}.Release|x86.Build.0 = Release|Win32
{F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Debug|x64.ActiveCfg = Debug|x64
- {F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Debug|x86.ActiveCfg = Debug|Win32
- {F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Debug|x86.Build.0 = Debug|Win32
{F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Release|x64.ActiveCfg = Release|x64
{F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Release|x64.Build.0 = Release|x64
- {F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Release|x86.ActiveCfg = Release|Win32
- {F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA}.Release|x86.Build.0 = Release|Win32
{16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Debug|x64.ActiveCfg = Debug|x64
- {16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Debug|x86.ActiveCfg = Debug|Win32
- {16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Debug|x86.Build.0 = Debug|Win32
{16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Release|x64.ActiveCfg = Release|x64
{16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Release|x64.Build.0 = Release|x64
- {16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Release|x86.ActiveCfg = Release|Win32
- {16BDCA26-D20C-4AC4-8DB3-9C108719B752}.Release|x86.Build.0 = Release|Win32
{13E88C11-DEB6-47D5-9382-4E5D484A58C2}.Debug|x64.ActiveCfg = Debug|x64
- {13E88C11-DEB6-47D5-9382-4E5D484A58C2}.Debug|x86.ActiveCfg = Debug|x64
{13E88C11-DEB6-47D5-9382-4E5D484A58C2}.Release|x64.ActiveCfg = Release|x64
{13E88C11-DEB6-47D5-9382-4E5D484A58C2}.Release|x64.Build.0 = Release|x64
- {13E88C11-DEB6-47D5-9382-4E5D484A58C2}.Release|x86.ActiveCfg = Release|x64
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Debug|x64.ActiveCfg = Debug|x64
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Debug|x64.Build.0 = Debug|x64
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Debug|x86.ActiveCfg = Debug|Win32
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Debug|x86.Build.0 = Debug|Win32
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Release|x64.ActiveCfg = Release|x64
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Release|x64.Build.0 = Release|x64
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Release|x86.ActiveCfg = Release|Win32
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A}.Release|x86.Build.0 = Release|Win32
+ {93661F1D-21DC-4B5B-88EC-6BEA337DF56B}.Debug|x64.ActiveCfg = Debug|x64
+ {93661F1D-21DC-4B5B-88EC-6BEA337DF56B}.Debug|x64.Build.0 = Debug|x64
+ {93661F1D-21DC-4B5B-88EC-6BEA337DF56B}.Release|x64.ActiveCfg = Release|x64
+ {93661F1D-21DC-4B5B-88EC-6BEA337DF56B}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -84,7 +59,7 @@ Global
{F09BBCFB-A1E3-43E0-8406-FBC8B72A09CA} = {4EC6A5BC-FCE4-4FFE-AC55-7D83B6B7C8D7}
{16BDCA26-D20C-4AC4-8DB3-9C108719B752} = {4EC6A5BC-FCE4-4FFE-AC55-7D83B6B7C8D7}
{13E88C11-DEB6-47D5-9382-4E5D484A58C2} = {4EC6A5BC-FCE4-4FFE-AC55-7D83B6B7C8D7}
- {53AE29AD-5DEB-4557-A65E-6E68D2E5336A} = {4EC6A5BC-FCE4-4FFE-AC55-7D83B6B7C8D7}
+ {93661F1D-21DC-4B5B-88EC-6BEA337DF56B} = {4EC6A5BC-FCE4-4FFE-AC55-7D83B6B7C8D7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D7E2F6B1-96AC-4FB5-B8AA-FDB43C7F169E}
diff --git a/SMInjector/src/main.cpp b/SMInjector/src/main.cpp
index fa7393c..dae7a96 100644
--- a/SMInjector/src/main.cpp
+++ b/SMInjector/src/main.cpp
@@ -9,28 +9,23 @@
#include "find_steam.h"
+namespace fs = std::filesystem;
+
bool Inject(HANDLE, const wchar_t*);
+bool InjectSetDllDirectory(HANDLE, const wchar_t*);
inline bool does_file_exist(const wchar_t* name) {
struct _stat buffer;
return (_wstat(name, &buffer) == 0);
}
-std::wstring get_dir_path() {
- wchar_t buffer[MAX_PATH] = { 0 };
- GetModuleFileNameW(NULL, buffer, MAX_PATH);
- std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/");
- return std::wstring(buffer).substr(0, pos);
-}
-
-std::wstring get_dll_path(const wchar_t* dll_name) {
- wchar_t buffer[MAX_PATH] = { 0 };
- GetModuleFileNameW(NULL, buffer, MAX_PATH);
- std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/");
- return std::wstring(buffer).substr(0, pos).append(L"\\").append(dll_name);
+fs::path get_dir_path() {
+ TCHAR dir[MAX_PATH] = { 0 };
+ DWORD length = GetModuleFileName(NULL, dir, _countof(dir));
+ return fs::path(dir).parent_path();
}
-BOOL startup(std::wstring in_exe, std::wstring in_dir, std::wstring in_cmd, HANDLE &hProcess, HANDLE &hThread) {
+BOOL startup(fs::path in_exe, fs::path in_dir, std::wstring in_cmd, HANDLE &hProcess, HANDLE &hThread) {
STARTUPINFO si;
PROCESS_INFORMATION pi;
@@ -39,8 +34,8 @@ BOOL startup(std::wstring in_exe, std::wstring in_dir, std::wstring in_cmd, HAND
wchar_t cmd[4097] = { 0 };
ZeroMemory(cmd, 4097);
- memcpy(exe, in_exe.c_str(), min(in_exe.size() * 2, MAX_PATH + 1));
- memcpy(dir, in_dir.c_str(), min(in_dir.size() * 2, MAX_PATH + 1));
+ memcpy(exe, in_exe.c_str(), min(in_exe.string().size() * 2, MAX_PATH + 1));
+ memcpy(dir, in_dir.c_str(), min(in_dir.string().size() * 2, MAX_PATH + 1));
swprintf_s(cmd, 4097, L"\"%s\" %s", exe, in_cmd.c_str());
//wprintf(L"EXE: [%s]\n", exe);
@@ -78,9 +73,10 @@ BOOL startup(std::wstring in_exe, std::wstring in_dir, std::wstring in_cmd, HAND
int main(int argc, char** argv) {
printf("SMInjector: startup\n");
- std::wstring game_path = SteamFinder::FindGame(L"Scrap Mechanic");
- std::wstring dll_path = get_dll_path(L"SMLibrary.dll");
-
+ fs::path game_path = SteamFinder::FindGame(L"Scrap Mechanic");
+ fs::path dir_path = get_dir_path();
+ fs::path dll_path = dir_path / "SMLibrary.dll";
+
wprintf(L"GAME: [%s]\n", game_path.c_str());
wprintf(L"DLL : [%s]\n", dll_path.c_str());
@@ -91,18 +87,38 @@ int main(int argc, char** argv) {
HANDLE hProcess;
HANDLE hThread;
- std::wstring exe_exe = std::wstring(game_path).append(L"\\Release\\ScrapMechanic.exe");
- std::wstring exe_dir = std::wstring(game_path).append(L"\\Release");
+ fs::path exe_dir = game_path / "Release";
+ fs::path exe_exe = game_path / "Release" / "ScrapMechanic.exe";
if(startup(exe_exe, exe_dir, L"-dev", hProcess, hThread)) {
- if(!Inject(hProcess, dll_path.c_str())) {
- printf("SMInjector: failed to inject dll file\n");
+
+ // Set the dll directory so SMLibrary.dll can load all it's dependencies
+ if (!InjectSetDllDirectory(hProcess, dir_path.c_str())) {
+ printf("SMInjector: Failed to inject dll directory\n");
+ TerminateProcess(hProcess, 0);
+ CloseHandle(hProcess);
+ return 0;
+ }
+
+ // Inject SMLibrary.dll
+ if (!Inject(hProcess, dll_path.c_str())) {
+ printf("SMInjector: Failed to inject SMLibrary.dll\n");
TerminateProcess(hProcess, 0);
CloseHandle(hProcess);
return 0;
}
- printf("\nSMInjector: Adding plugins.\n");
- for(const auto& file : std::filesystem::directory_iterator(get_dir_path().append(L"\\plugins"))) {
+ // Create plugin dependencies directory
+ if (!fs::exists(dir_path / "plugins" / "dependencies")) {
+ fs::create_directories(dir_path / "plugins" / "dependencies");
+ }
+
+ // Inject plugins
+ printf("\nSMInjector: Adding plugins...\n");
+ for(const auto& file : fs::directory_iterator(get_dir_path() / "plugins")) {
+ if (file.path().extension() != ".dll") {
+ continue;
+ }
+
if(!Inject(hProcess, file.path().c_str())) {
wprintf(L" Failed to inject '%s'\n", file.path().filename().c_str());
return 0;
@@ -147,3 +163,34 @@ bool Inject(HANDLE hProc, const wchar_t* path) {
CloseHandle(threadID);
return true;
}
+
+bool InjectSetDllDirectory(HANDLE hProc, const wchar_t* path) {
+ if (!does_file_exist(path)) {
+ return false;
+ }
+
+ const size_t path_length = wcslen(path) * 2;
+
+ LPVOID lpvoid = VirtualAllocEx(hProc, NULL, path_length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (!lpvoid) {
+ return false;
+ }
+
+ WriteProcessMemory(hProc, lpvoid, path, path_length, NULL);
+ HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
+ if (!kernel32) {
+ return false;
+ }
+
+ LPVOID SetDllDirectoryAddr = (LPVOID)GetProcAddress(kernel32, "SetDllDirectoryW");
+
+ HANDLE threadID = CreateRemoteThread(hProc, NULL, NULL, (LPTHREAD_START_ROUTINE)SetDllDirectoryAddr, lpvoid, NULL, NULL);
+ if (!threadID) {
+ return false;
+ }
+
+ WaitForSingleObject(threadID, INFINITE);
+ VirtualFreeEx(hProc, lpvoid, 0, MEM_RELEASE);
+ CloseHandle(threadID);
+ return true;
+}
diff --git a/SMLibrary/SMLibrary.vcxproj b/SMLibrary/SMLibrary.vcxproj
index 41c4fb6..5503edf 100644
--- a/SMLibrary/SMLibrary.vcxproj
+++ b/SMLibrary/SMLibrary.vcxproj
@@ -1,14 +1,6 @@
-
- Debug
- Win32
-
-
- Release
- Win32
-
Debug
x64
@@ -27,19 +19,6 @@
SMLibrary
-
- DynamicLibrary
- true
- v142
- Unicode
-
-
- DynamicLibrary
- false
- v142
- true
- Unicode
-
DynamicLibrary
true
@@ -58,12 +37,6 @@
-
-
-
-
-
-
@@ -71,14 +44,6 @@
-
- true
- $(SourcePath)
-
-
- false
- $(SourcePath)
-
true
$(SourcePath)
@@ -87,35 +52,6 @@
false
$(SourcePath)
-
-
- Level3
- true
- WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- true
- MaxSpeed
-
-
- Console
- true
-
-
-
-
- Level3
- true
- true
- true
- WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
- true
-
-
- Console
- true
- true
- true
-
-
Level3
@@ -123,6 +59,8 @@
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
MaxSpeed
+ Default
+ stdcpp17
Console
@@ -137,6 +75,7 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
+ stdcpp17
Console
@@ -153,11 +92,24 @@
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
\ No newline at end of file
diff --git a/SMLibrary/SMLibrary.vcxproj.filters b/SMLibrary/SMLibrary.vcxproj.filters
index 3c136c5..556726b 100644
--- a/SMLibrary/SMLibrary.vcxproj.filters
+++ b/SMLibrary/SMLibrary.vcxproj.filters
@@ -41,5 +41,17 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
\ No newline at end of file
diff --git a/SMLibrary/include/console.h b/SMLibrary/include/console.h
index 1c59933..a62fa9d 100644
--- a/SMLibrary/include/console.h
+++ b/SMLibrary/include/console.h
@@ -37,8 +37,8 @@ namespace Console {
};
#ifdef _SM_LIBRARY_BUILD_PLUGIN
- _LIB_IMPORT
- void vlogf(Color color, const char *plugin_name, const char *format, va_list args);
+ _LIB_IMPORT void vlogf(Color color, const char* plugin_name, const char* format, va_list args);
+ _LIB_IMPORT void wvlogf(Color color, const char* plugin_name, const wchar_t* format, va_list args);
#else
FILE* console_handle = NULL;
HANDLE hConsole;
@@ -59,8 +59,7 @@ namespace Console {
#endif
}
- _LIB_EXPORT
- void vlogf(Color color, const char *plugin_name, const char *format, va_list args) {
+ _LIB_EXPORT void vlogf(Color color, const char *plugin_name, const char *format, va_list args) {
if(!console_handle) return;
if(!hConsole) hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -70,12 +69,29 @@ namespace Console {
vprintf(format, args);
printf("\n");
}
+
+ _LIB_EXPORT void wvlogf(Color color, const char* plugin_name, const wchar_t* format, va_list args) {
+ if (!console_handle) return;
+
+ if (!hConsole) hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (hConsole) SetConsoleTextAttribute(hConsole, (WORD)color);
+
+ printf("[%s]: ", plugin_name);
+ vwprintf(format, args);
+ printf("\n");
+ }
#endif
void log(Color color, const char *format, ...) {
va_list args;
va_start(args, format);
vlogf(color, _LIB_PLUGIN_NAME_STR, format, args);
}
+
+ void wlog(Color color, const wchar_t* format, ...) {
+ va_list args;
+ va_start(args, format);
+ wvlogf(color, _LIB_PLUGIN_NAME_STR, format, args);
+ }
}
#endif
diff --git a/SMLibrary/include/path_helper.h b/SMLibrary/include/path_helper.h
new file mode 100644
index 0000000..7a21e49
--- /dev/null
+++ b/SMLibrary/include/path_helper.h
@@ -0,0 +1,42 @@
+#pragma once
+#include
+#include
+
+#include "plugin_config.h"
+
+namespace fs = std::filesystem;
+
+namespace PathHelper {
+
+ fs::path getInstallationPath() {
+ TCHAR dir[MAX_PATH] = { 0 };
+ DWORD length = GetModuleFileName(NULL, dir, _countof(dir));
+ return fs::path(dir).parent_path();
+ }
+
+ fs::path resolvePath(std::string path) {
+
+#ifdef _LIB_PLUGIN_NAME_STR
+ if (path.rfind("$PLUGIN_CONFIG", 0) == 0) {
+ return PluginConfig::getConfigDirectory() / fs::path(_LIB_PLUGIN_NAME_STR) / path.substr(path.find_first_of("/") + 1);
+ }
+#endif
+
+ if (path.rfind("$GAME_DATA", 0) == 0) {
+ return PathHelper::getInstallationPath() / fs::path("Data") / path.substr(path.find_first_of("/") + 1);
+ }
+
+ if (path.rfind("$SURVIVAL_DATA", 0) == 0) {
+ return PathHelper::getInstallationPath() / fs::path("Survival") / path.substr(path.find_first_of("/") + 1);
+ }
+
+ if (path.rfind("$CHALLENGE_DATA", 0) == 0) {
+ return PathHelper::getInstallationPath() / fs::path("ChallengeData") / path.substr(path.find_first_of("/") + 1);
+ }
+
+ // TODO: Call the funtion in the game to do this
+
+ return path;
+ }
+
+}
diff --git a/SMLibrary/include/plugin_config.h b/SMLibrary/include/plugin_config.h
new file mode 100644
index 0000000..7c25e03
--- /dev/null
+++ b/SMLibrary/include/plugin_config.h
@@ -0,0 +1,114 @@
+#pragma once
+#include "stdafx.h"
+#include
+#include
+#include
+#pragma warning(push)
+#pragma warning(disable : 26819 28020)
+#define JSON_DIAGNOSTICS 1
+#include
+#pragma warning(pop)
+#include "console.h"
+
+namespace fs = std::filesystem;
+using json = nlohmann::json;
+
+class PluginConfig {
+private:
+ inline static fs::path configDirectory;
+
+ const char* pluginName = NULL;
+ fs::path path;
+ fs::path fullPath;
+
+ const char* defaultContent = "// Empty config file\n{}\n";
+
+public:
+ json root;
+
+ _LIB_FUNCTION static bool setConfigDirectory(const fs::path& configDirectory) {
+ PluginConfig::configDirectory = fs::absolute(configDirectory);
+
+ if (!fs::is_directory(configDirectory) || !fs::exists(configDirectory)) {
+ if (!fs::create_directories(configDirectory)) {
+ Console::wlog(Console::Color::LightRed, L"Failed creating main config directory \"%s\"", PluginConfig::configDirectory.c_str());
+ return false;
+ }
+ }
+
+ Console::wlog(Console::Color::Aqua, L"Set main config directory to \"%s\"", PluginConfig::configDirectory.c_str());
+
+ return true;
+ }
+
+ _LIB_FUNCTION static fs::path getConfigDirectory() {
+ return PluginConfig::configDirectory;
+ }
+
+ PluginConfig(const char *pluginName, const fs::path& path) {
+ this->pluginName = pluginName;
+ this->path = path;
+
+ this->fullPath = PluginConfig::getConfigDirectory() / fs::path(pluginName) / this->path;
+ }
+
+#ifdef _LIB_PLUGIN_NAME_STR
+ PluginConfig(const fs::path& path) : PluginConfig(_LIB_PLUGIN_NAME_STR, path) {}
+#endif
+
+ void setDefaultContent(const char* defaultContent) {
+ this->defaultContent = defaultContent;
+ }
+
+ bool createIfNotExists() {
+ if (fs::exists(this->fullPath)) {
+ return false;
+ }
+
+ Console::wlog(Console::Color::LightYellow, L"Warning: Unable to find config file \"%s\", creating with default content...", this->fullPath.c_str());
+
+ if (!fs::exists(this->fullPath.parent_path())) {
+ fs::create_directories(this->fullPath.parent_path());
+ }
+
+ std::ofstream ofs(this->fullPath);
+
+ if (!ofs.is_open()) {
+#pragma warning(suppress : 4996)
+ Console::wlog(Console::Color::LightRed, L"Failed creating config file \"%s\": %s", this->fullPath.c_str(), _wcserror(errno));
+ return false;
+ }
+
+ ofs << this->defaultContent;
+ ofs.close();
+
+ return true;
+ }
+
+ bool load() {
+ std::ifstream ifs(this->fullPath);
+
+ if (!ifs.is_open()) {
+#pragma warning(suppress : 4996)
+ Console::wlog(Console::Color::LightRed, L"Failed reading config file \"%s\": %s", this->fullPath.c_str(), _wcserror(errno));
+ return false;
+ }
+
+ Console::wlog(Console::Color::Gray, L"Loaded config file \"%s\"", this->fullPath.c_str());
+
+
+ try {
+ this->root = json::parse(ifs, nullptr, true, true);
+ std::cout << this->root.dump(4) << '\n';
+
+ } catch (json::exception& e) {
+ Console::wlog(Console::Color::LightRed, L"Failed parsing config file \"%s\":", this->fullPath.c_str());
+ Console::log(Console::Color::LightRed, " %s", e.what());
+ }
+
+ ifs.close();
+
+ return true;
+ }
+
+};
\ No newline at end of file
diff --git a/SMLibrary/include/sigscan.h b/SMLibrary/include/sigscan.h
new file mode 100644
index 0000000..b22810a
--- /dev/null
+++ b/SMLibrary/include/sigscan.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "console.h"
+
+#define ERROR_GETMODULE(reason, ...) Console::log(Color::LightRed, "[SignatureScanner] Failed getting handle of module %s. Reason: " reason, moduleName, __VA_ARGS__)
+
+using Console::Color;
+
+class SignatureScanner {
+private:
+ LPCWSTR moduleName;
+ DWORD64 moduleBase;
+ DWORD moduleSize;
+
+ MODULEINFO GetModuleInfo(LPCWSTR moduleName) {
+ MODULEINFO moduleInfo = { 0 };
+ HMODULE hModule = GetModuleHandle(moduleName);
+ if (hModule == NULL)
+ return moduleInfo;
+
+ GetModuleInformation(GetCurrentProcess(), hModule, &moduleInfo, sizeof(MODULEINFO));
+
+ return moduleInfo;
+ }
+
+public:
+ SignatureScanner(LPCWSTR moduleName) {
+ this->moduleName = moduleName;
+
+ MODULEINFO moduleInfo = GetModuleInfo(moduleName);
+
+ if (moduleInfo.SizeOfImage == 0) {
+ Console::log(Color::LightRed, "[SignatureScanner] Failed getting info of module %s", moduleName);
+ return;
+ }
+
+ this->moduleBase = (DWORD64) moduleInfo.lpBaseOfDll;
+ this->moduleSize = moduleInfo.SizeOfImage;
+
+ Console::wlog(Color::Aqua, L"[SignatureScanner] Found module %s with base=[0x%llX] size=[%ul]", moduleName, this->moduleBase, this->moduleSize);
+ }
+
+};
+
+#undef ERROR_GETMODULE
diff --git a/SMLibrary/packages.config b/SMLibrary/packages.config
new file mode 100644
index 0000000..db3400a
--- /dev/null
+++ b/SMLibrary/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/SMLibrary/src/sm_lib.cpp b/SMLibrary/src/sm_lib.cpp
index 3a833c5..df36141 100644
--- a/SMLibrary/src/sm_lib.cpp
+++ b/SMLibrary/src/sm_lib.cpp
@@ -2,11 +2,16 @@
#include
#include
#include
+#include
+#include
+
+namespace fs = std::filesystem;
#define _SM_PLUGIN_NAME SMLibrary
#define _SM_OUTPUT_LOGS
#include "../include/sm_lib.h"
+#include "../include/plugin_config.h"
#include "../include/console.h"
using Console::Color;
@@ -32,7 +37,15 @@ BOOL PostConsoleInjections();
#include "hooks.h"
-BOOL Startup(HMODULE hModule) {
+fs::path smlibrarydllPath;
+
+fs::path GetDllPath(HMODULE hModule) {
+ TCHAR dllPath[MAX_PATH] = { 0 };
+ DWORD length = GetModuleFileName(hModule, dllPath, _countof(dllPath));
+ return fs::path(dllPath);
+}
+
+BOOL Startup() {
HMODULE sm_handle = GetModuleHandleA("ScrapMechanic.exe");
if(!sm_handle) return false;
@@ -43,6 +56,9 @@ BOOL Startup(HMODULE hModule) {
BOOL PostConsoleInjections() {
Console::log_open();
+
+ PluginConfig::setConfigDirectory(smlibrarydllPath.parent_path() / "config");
+
Console::log(Color::Aqua, "Installing the library functions");
const size_t plugins_size = plugins.size();
@@ -60,11 +76,45 @@ BOOL PostConsoleInjections() {
return true;
}
+void SetupDllDirectories() {
+ fs::path baseDir = smlibrarydllPath.parent_path();
+
+ fs::path directories[] = {
+ baseDir,
+ baseDir / "plugins",
+ baseDir / "plugins" / "dependencies"
+ };
+
+ for (const fs::path& dir : directories) {
+ if (!AddDllDirectory(dir.c_str())) {
+ std::string body;
+ body += "Failed adding dll directory \"";
+ body += dir.string();
+ body += "\"\nSome plugins might not load\n\nReason:\n";
+ body += std::system_category().message(GetLastError());
+
+ MessageBoxA(0, body.c_str(), "AddDllDirectory failed", MB_ICONERROR);
+ }
+ }
+
+ if (!SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)) {
+ std::string body;
+ body += "Some plugins might not load\n\nReason:\n";
+ body += std::system_category().message(GetLastError());
+
+ MessageBoxA(0, body.c_str(), "SetDefaultDllDirectories failed", MB_ICONERROR);
+ }
+}
+
BOOL WINAPI DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) {
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
- Startup(hModule);
MessageBox(0, L"From DLL\n", L"Process Attach", MB_ICONINFORMATION);
+
+ smlibrarydllPath = GetDllPath(hModule);
+
+ SetupDllDirectories();
+ Startup();
break;
case DLL_PROCESS_DETACH: