| @@ -0,0 +1,522 @@ | |||
| #include "BL3Lua.h" | |||
| #include "LuaUtility.h" | |||
| #include "include/patternscan.hpp" | |||
| int lua_exception_handler(lua_State* L, sol::optional<const std::exception&> maybe_exception, sol::string_view description) { | |||
| // L is the lua state, which you can wrap in a state_view if necessary | |||
| // maybe_exception will contain exception, if it exists | |||
| // description will either be the what() of the exception or a description saying that we hit the general-case catch(...) | |||
| std::cout << "An exception occurred in a function, here's what it says "; | |||
| if (maybe_exception) { | |||
| std::cout << "(straight from the exception): "; | |||
| const std::exception& ex = *maybe_exception; | |||
| std::cout << ex.what() << std::endl; | |||
| } | |||
| else { | |||
| std::cout << "(from the description parameter): "; | |||
| std::cout.write(description.data(), static_cast<std::streamsize>(description.size())); | |||
| std::cout << std::endl; | |||
| } | |||
| // you must push 1 element onto the stack to be | |||
| // transported through as the error object in Lua | |||
| // note that Lua -- and 99.5% of all Lua users and libraries -- expects a string | |||
| // so we push a single string (in our case, the description of the error) | |||
| return sol::stack::push(L, description); | |||
| } | |||
| inline void my_panic(sol::optional<std::string> maybe_msg) { | |||
| std::cerr << "Lua is in a panic state and will now abort() the application" << std::endl; | |||
| if (maybe_msg) { | |||
| const std::string& msg = maybe_msg.value(); | |||
| std::cerr << "\terror message: " << msg << std::endl; | |||
| } | |||
| // When this function exits, Lua will exhibit default behavior and abort() | |||
| } | |||
| BL3Lua::BL3Lua() | |||
| { | |||
| InitializeCriticalSection(&luaCritSec); | |||
| /*InitializeCriticalSection(&procEventCritSec); | |||
| InitializeCriticalSection(&consoleCommandCritSec);*/ | |||
| lua = new sol::state(); | |||
| lua->open_libraries(); | |||
| lua->set_exception_handler(lua_exception_handler); | |||
| lua->set_panic(sol::c_call<decltype(&my_panic), &my_panic>); | |||
| registerBase(); | |||
| while (SDK::GEngine == nullptr) | |||
| { | |||
| auto engineAddress = PatternScan::FindSignature(NULL, "48 8b 4c 24 50 48 89 05 ?? ?? ?? ?? 48 85 c9 74 05 e8"); | |||
| if (engineAddress != NULL) | |||
| { | |||
| auto tmp = (engineAddress + 5); | |||
| auto tmp2 = tmp + 3; | |||
| SDK::GEngine = reinterpret_cast<SDK::UEngine**>((tmp + 7 + *(int*)(tmp2))); | |||
| } | |||
| } | |||
| consoleEnvironment = sol::environment(*lua, sol::create, lua->globals()); | |||
| } | |||
| BL3Lua::~BL3Lua() | |||
| { | |||
| lua_close(lua->lua_state()); | |||
| DeleteCriticalSection(&luaCritSec); | |||
| } | |||
| bool BL3Lua::ExecuteScriptFile(const char* filePath, bool printInGame) | |||
| { | |||
| bool result = false; | |||
| EnterCriticalSection(&luaCritSec); | |||
| int indexToDelete = -1; | |||
| for (int i = 0; i < loadedComponents.size(); i++) { | |||
| if (!strcmp(loadedComponents[i]->m_FileName.c_str(), filePath)) { | |||
| indexToDelete = i; | |||
| break; | |||
| } | |||
| } | |||
| // TODO: Properly delete references during iteration | |||
| // Implement iterator instead of loop | |||
| if (indexToDelete != -1) { | |||
| // Remove registered Hotkeys from this env | |||
| auto hkIT = registeredHotkeys.begin(); | |||
| while (hkIT != registeredHotkeys.end()) { | |||
| /*for (auto& r : hkIT) {*/ | |||
| sol::reference eRef = std::get<0>(*hkIT); | |||
| sol::environment env = sol::get_environment(eRef); | |||
| if (env == loadedComponents[indexToDelete]->m_Env) { | |||
| eRef.abandon(); | |||
| hkIT = registeredHotkeys.erase(hkIT); | |||
| //registeredHotkeys.erase(std::remove(registeredHotkeys.begin(), registeredHotkeys.end(), r), registeredHotkeys.end()); | |||
| } | |||
| if(hkIT != registeredHotkeys.end()) | |||
| ++hkIT; | |||
| } | |||
| auto procEventIT = procEventHooks.begin(); | |||
| // Remove procEventHooks from this env | |||
| //for (auto& r : procEventHooks) { | |||
| while(procEventIT != procEventHooks.end()){ | |||
| bool didErase = false; | |||
| for (auto& p : procEventIT->second) { | |||
| sol::reference eRef = std::get<0>(p); | |||
| sol::environment env = sol::get_environment(eRef); | |||
| if (env == loadedComponents[indexToDelete]->m_Env) { | |||
| eRef.abandon(); | |||
| //r.second.erase(std::remove(r.second.begin(), r.second.end(), p), r.second.end()); | |||
| didErase = true; | |||
| } | |||
| } | |||
| if (didErase) { | |||
| procEventIT = procEventHooks.erase(procEventIT); | |||
| if (procEventIT != procEventHooks.end()) | |||
| ++procEventIT; | |||
| } | |||
| } | |||
| // Remove consoleCommands from this env | |||
| auto ccIT = consoleCommands.begin(); | |||
| //for (auto& r : consoleCommands) { | |||
| while(ccIT != consoleCommands.end()){ | |||
| sol::reference eRef = std::get<0>(ccIT->second); | |||
| sol::environment env = sol::get_environment(eRef); | |||
| if (env == loadedComponents[indexToDelete]->m_Env) { | |||
| eRef.abandon(); | |||
| ccIT = consoleCommands.erase(ccIT); | |||
| //consoleCommands.erase(r.first); | |||
| } | |||
| if (ccIT != consoleCommands.end()) | |||
| ++ccIT; | |||
| } | |||
| delete loadedComponents[indexToDelete]; | |||
| loadedComponents.erase(loadedComponents.begin() + indexToDelete); | |||
| } | |||
| lua->collect_garbage(); | |||
| LuaComponent* nComp = new LuaComponent(filePath, lua); | |||
| nComp->Init(); | |||
| loadedComponents.push_back(nComp); | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| return nComp->m_Env != sol::lua_nil; | |||
| } | |||
| bool BL3Lua::ExecuteScriptString(const char* scriptCode, bool printInGame) | |||
| { | |||
| bool result = false; | |||
| EnterCriticalSection(&luaCritSec); | |||
| try { | |||
| auto func_result = lua->safe_script(scriptCode, consoleEnvironment); | |||
| if (!func_result.valid()) { | |||
| sol::error err = func_result; | |||
| std::cout << "[LUA] failed with error: " << err.what() << std::endl; | |||
| if (printInGame) { | |||
| sol::protected_function printFunc = (*(lua))["PrintGameConsole"]; | |||
| if (printFunc.valid()) { | |||
| std::string errorMessage = std::string("[LUA] failed with error: ").append(err.what()); | |||
| printFunc(errorMessage); | |||
| } | |||
| } | |||
| } | |||
| else { | |||
| result = true; | |||
| } | |||
| } | |||
| catch (...) { | |||
| } | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| return result; | |||
| } | |||
| void BL3Lua::RunCallbacks(const char* callbackName, sol::object data) | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| try{ | |||
| sol::protected_function runCallbackFunc = (*lua)["RunCallbacks"]; | |||
| if (runCallbackFunc.valid()){ | |||
| sol::protected_function_result result = runCallbackFunc(callbackName, data); | |||
| if (!result.valid()) { | |||
| sol::error err = result; | |||
| std::cout << "Error during callbacks: " << err.what() << std::endl; | |||
| } | |||
| } | |||
| } | |||
| catch(...){} | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::TDump(sol::object tableToDump) | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| try { | |||
| sol::protected_function tdumpFunc = (*lua)["internalTDump"]; | |||
| if (tdumpFunc.valid()) { | |||
| sol::protected_function_result result = tdumpFunc(tableToDump); | |||
| if (!result.valid()) { | |||
| sol::error err = result; | |||
| std::cout << "Error during tdump: " << err.what() << std::endl; | |||
| } | |||
| } | |||
| } | |||
| catch (...) {} | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::ClearCallbacks() | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| while (callbacks && !callbacks.empty()) { | |||
| callbacks.clear(); | |||
| } | |||
| callbacks = lua->create_named_table("Callbacks"); | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::ValidateHotkeys() | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| std::vector<int> toDelete; | |||
| std::vector<std::tuple<sol::reference, lua_State*, std::string, std::string, std::string>> tmp; | |||
| bool needsFixup = false; | |||
| for (int i = 0; i < registeredHotkeys.size(); ++i) { | |||
| if (!std::get<0>(registeredHotkeys[i]).valid()) | |||
| { | |||
| needsFixup = true; | |||
| } | |||
| else { | |||
| tmp.push_back(registeredHotkeys[i]); | |||
| } | |||
| } | |||
| if (needsFixup) { | |||
| registeredHotkeys = tmp; | |||
| } | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| // Registering works | |||
| uint32_t BL3Lua::RegisterHotkey(sol::this_state s, sol::this_environment e, sol::variadic_args va) { | |||
| bool anyError = false; | |||
| ValidateHotkeys(); | |||
| EnterCriticalSection(&luaCritSec); | |||
| std::vector<std::string> hotkeys; | |||
| sol::function func; | |||
| for (auto v : va) { | |||
| if (v.is<std::string_view>()) { | |||
| std::string hk = v.as<std::string>(); | |||
| if (!LuaUtility::ContainsKey(hk)) | |||
| { | |||
| anyError = true; | |||
| sol::protected_function printFunc = (*(lua))["PrintGameConsole"]; | |||
| if (printFunc.valid()) { | |||
| char buffer[1024]; | |||
| sprintf_s(buffer, sizeof(buffer), "\"%s\" is not a valid keybind!", hk.c_str()); | |||
| std::string errorMessage = std::string(buffer); | |||
| printFunc(errorMessage); | |||
| } | |||
| } | |||
| else { | |||
| hotkeys.push_back(hk); | |||
| } | |||
| } | |||
| else if (v.is<sol::function>()) { | |||
| func = v.as<sol::function>(); | |||
| } | |||
| } | |||
| //std::vector<std::string> hotkeys = hotkeyTable.as<std::vector<std::string>>(); | |||
| if (hotkeys.size() >= 1 && hotkeys.size() <= 3 && func.valid()) { | |||
| for (auto& hk : hotkeys) { | |||
| if (!LuaUtility::ContainsKey(hk)) | |||
| { | |||
| anyError = true; | |||
| sol::protected_function printFunc = (*(lua))["PrintGameConsole"]; | |||
| if (printFunc.valid()) { | |||
| char buffer[1024]; | |||
| sprintf_s(buffer, sizeof(buffer), "\"%s\" is not a valid keybind!", hk.c_str()); | |||
| std::string errorMessage = std::string(buffer); | |||
| printFunc(errorMessage); | |||
| } | |||
| } | |||
| } | |||
| if (anyError) { | |||
| LeaveCriticalSection(&luaCritSec); | |||
| return 0; | |||
| } | |||
| int index = -1; | |||
| for (int i = 0; i < registeredHotkeys.size(); ++i) { | |||
| sol::function testFunc = std::get<0>(registeredHotkeys[i]); | |||
| if (std::get<0>(registeredHotkeys[i]) == func) { | |||
| index = i; | |||
| break; | |||
| } | |||
| } | |||
| switch (hotkeys.size()) | |||
| { | |||
| case 1: | |||
| if (index != -1) { | |||
| registeredHotkeys[index] = std::make_tuple(func, s.L, hotkeys.at(0), "", ""); | |||
| } | |||
| else { | |||
| registeredHotkeys.push_back(std::make_tuple(func, s.L, hotkeys.at(0), "", "")); | |||
| } | |||
| break; | |||
| case 2: | |||
| if (index != -1) { | |||
| registeredHotkeys[index] = std::make_tuple(func, s.L, hotkeys.at(0), "", ""); | |||
| } | |||
| else { | |||
| registeredHotkeys.push_back(std::make_tuple(func, s.L, hotkeys.at(0), hotkeys.at(1), "")); | |||
| } | |||
| break; | |||
| case 3: | |||
| if (index != -1) { | |||
| registeredHotkeys[index] = std::make_tuple(func, s.L, hotkeys.at(0), "", ""); | |||
| } | |||
| else { | |||
| registeredHotkeys.push_back(std::make_tuple(func, s.L, hotkeys.at(0), hotkeys.at(1), hotkeys.at(2))); | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| LeaveCriticalSection(&luaCritSec); | |||
| return 0; | |||
| } | |||
| void BL3Lua::RemoveHotkey(sol::this_state s, sol::this_environment e, uint32_t, sol::function func) { | |||
| lua->collect_garbage(); | |||
| } | |||
| void BL3Lua::RemoveAllHotkeys() { | |||
| EnterCriticalSection(&luaCritSec); | |||
| registeredHotkeys.clear(); | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::AddHook(sol::this_state s, sol::this_environment e, const std::string& hookName, sol::function func, bool preHook) | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| procEventHooks[hookName].push_back(std::make_tuple(func, s.L, preHook)); | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::RemoveAllHooks() | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| if (procEventHooks.size() > 0) { | |||
| procEventHooks.clear(); | |||
| } | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::RemoveHook(sol::this_state s, sol::this_environment e, const std::string& hookName, sol::function func) | |||
| { | |||
| int index = -1; | |||
| EnterCriticalSection(&luaCritSec); | |||
| for (int i = 0; i < procEventHooks[hookName].size(); ++i) { | |||
| if (std::get<0>(procEventHooks[hookName][i]).registry_index() == func.registry_index()) { | |||
| index = i; | |||
| break; | |||
| } | |||
| } | |||
| if (index != -1) | |||
| procEventHooks[hookName].erase(procEventHooks[hookName].begin(), procEventHooks[hookName].begin() + index); | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::AddConsoleCommand(sol::this_state s, sol::this_environment e, const std::string& command, sol::function func) | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| consoleCommands[command] = std::make_tuple(func, s.L, command.size()); | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::RemoveAllConsoleCommands() | |||
| { | |||
| EnterCriticalSection(&luaCritSec); | |||
| if (consoleCommands.size() > 0) { | |||
| consoleCommands.clear(); | |||
| } | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::RemoveConsoleCommand(sol::this_state s, sol::this_environment e, const std::string& command, sol::function func) | |||
| { | |||
| int index = -1; | |||
| EnterCriticalSection(&luaCritSec); | |||
| for (int i = 0; i < consoleCommands.size(); ++i) { | |||
| if (std::get<0>(consoleCommands[command]) == func) { | |||
| index = i; | |||
| break; | |||
| } | |||
| } | |||
| if (index != -1){ | |||
| consoleCommands.erase(command); | |||
| } | |||
| lua->collect_garbage(); | |||
| LeaveCriticalSection(&luaCritSec); | |||
| } | |||
| void BL3Lua::registerBase() | |||
| { | |||
| lua->set_function("IsKeyPressed", sol::overload( | |||
| [](std::string keyName) { return LuaUtility::IsKeyPressed(keyName); }, | |||
| [](std::string keyName, std::string keyName2) {return LuaUtility::IsKeyPressed(keyName, keyName2); }, | |||
| [](std::string keyName, std::string keyName2, std::string keyName3) {return LuaUtility::IsKeyPressed(keyName, keyName2, keyName3); | |||
| })); | |||
| lua->set_function("FindObject", [](std::string name) { | |||
| auto tmp = SDK::UObject::FindObject<SDK::UObject>(name); | |||
| return tmp; | |||
| }); | |||
| lua->set_function("StaticFindObject", [](SDK::UClass* pClass, const std::wstring_view name) | |||
| { | |||
| return StaticFindObject(pClass, reinterpret_cast<SDK::UObject*>(-1), &name.data()[0], false); | |||
| }); | |||
| lua->set_function("RegisterHotkey", [&](sol::this_state s, sol::this_environment e, sol::variadic_args va) { | |||
| RegisterHotkey(s, e, va); | |||
| }); | |||
| lua->set_function("ClearHotkeys", [&]() {RemoveAllHotkeys(); }); | |||
| sol::protected_function_result result = lua->safe_script(R"( | |||
| function RegisterCallback(onEventName, lCallback) | |||
| while true do | |||
| if Callbacks then | |||
| break | |||
| end | |||
| end | |||
| if Callbacks then | |||
| Callbacks[lCallback] = onEventName | |||
| else | |||
| print("Callback-Table does not exist!") | |||
| end | |||
| end | |||
| function RunCallbacks(eventName, data) | |||
| for key, value in pairs(Callbacks) do | |||
| key(data) | |||
| end | |||
| end | |||
| function internalTDump(object) | |||
| if object == nil then | |||
| return | |||
| end | |||
| for key, value in pairs(getmetatable(object)) do | |||
| if not string.find(key, "_") and key ~= "new" then | |||
| -- if type(value) == "function" then | |||
| -- print("[Function] " .. tostring(key)) | |||
| -- else | |||
| -- print(tostring(key)) | |||
| -- end | |||
| print(tostring(key)) | |||
| end | |||
| end | |||
| end | |||
| defPrint = print | |||
| print = function(...) | |||
| for i,v in ipairs{...} do | |||
| if PrintGameConsole then | |||
| PrintGameConsole(tostring(v)) | |||
| end | |||
| end | |||
| defPrint(...) | |||
| end | |||
| )"); | |||
| if (!result.valid()) { | |||
| sol::error err = result; | |||
| std::cout << err.what() << std::endl; | |||
| } | |||
| SDK::UObject::SetupLuaBind(lua); | |||
| loadlibs(); | |||
| adjustRequirePath(); | |||
| removeAbusableFuncs(); | |||
| callbacks = lua->create_named_table("Callbacks"); | |||
| } | |||
| void BL3Lua::loadlibs() | |||
| { | |||
| const char* jsonlua = | |||
| #include "include/json.lua" | |||
| ; | |||
| const char* splitlua = | |||
| #include "include/split.lua" | |||
| ; | |||
| lua->require_script("json", jsonlua); | |||
| lua->require_script("split", splitlua); | |||
| } | |||
| void BL3Lua::adjustRequirePath() { | |||
| const std::string defaultPath = (*lua)["package"]["path"]; | |||
| wchar_t pBuffer[MAX_PATH]; | |||
| GetCurrentDirectory(sizeof(pBuffer), pBuffer); | |||
| std::wstring widePath(pBuffer); | |||
| std::string path(widePath.begin(), widePath.end()); | |||
| path.append("\\lua\\Modules\\?.lua"); | |||
| (*lua)["package"]["path"] = defaultPath + ";" + path; | |||
| } | |||
| void BL3Lua::removeAbusableFuncs() { | |||
| sol::table global = lua->globals(); | |||
| if (global.valid()) { | |||
| global["os"]["remove"] = sol::lua_nil; | |||
| } | |||
| } | |||
| @@ -0,0 +1,61 @@ | |||
| #pragma once | |||
| #define SOL_EXCEPTIONS_SAFE_PROPAGATION 1 | |||
| #define SOL_ALL_SAFETIES_ON 1 | |||
| //#include "SOL/sol.hpp" | |||
| #include "F:/Programmieren/Lua/sol2/single/single/include/sol/sol.hpp" | |||
| #include <iostream> | |||
| #include <unordered_map> | |||
| #include <vector> | |||
| #include <tuple> | |||
| //#include "C:/SDK_GEN/BL3/SDK/BL3_Basic.hpp" | |||
| //#include "C:/SDK_GEN/BL3/SDK/BL3_CoreUObject_classes.hpp" | |||
| #include "C:/SDK_GEN/BL3-2021-4-9/SDK.hpp" | |||
| #include <Windows.h> | |||
| #include "LuaComponent.h" | |||
| class BL3Lua | |||
| { | |||
| public: | |||
| BL3Lua(); | |||
| ~BL3Lua(); | |||
| bool ExecuteScriptFile(const char* filePath, bool printInGame = false); | |||
| bool ExecuteScriptString(const char* scriptCode, bool printInGame = false); | |||
| void RunCallbacks(const char* callbackName, sol::object data); | |||
| void TDump(sol::object tableToDump); | |||
| void ClearCallbacks(); | |||
| void AddHook(sol::this_state s, sol::this_environment e, const std::string& hookName, sol::function func, bool preHook); | |||
| void RemoveHook(sol::this_state s, sol::this_environment e, const std::string& hookName, sol::function func); | |||
| void RemoveAllHooks(); | |||
| void AddConsoleCommand(sol::this_state s, sol::this_environment e, const std::string& command, sol::function func); | |||
| void RemoveConsoleCommand(sol::this_state s, sol::this_environment e, const std::string& command, sol::function func); | |||
| void RemoveAllConsoleCommands(); | |||
| uint32_t RegisterHotkey(sol::this_state s, sol::this_environment e, sol::variadic_args va); | |||
| void RemoveHotkey(sol::this_state s, sol::this_environment e, uint32_t, sol::function func); | |||
| void RemoveAllHotkeys(); | |||
| void ValidateHotkeys(); | |||
| //std::vector<sol::protected_function> GetHooks(const char* hookName); | |||
| //void RegisterUtility(); | |||
| private: | |||
| void registerBase(); | |||
| void loadlibs(); | |||
| void adjustRequirePath(); | |||
| void removeAbusableFuncs(); | |||
| public: | |||
| sol::state* lua; | |||
| CRITICAL_SECTION luaCritSec; | |||
| std::unordered_map<std::string, std::vector<std::tuple<sol::reference, lua_State*, bool>>> procEventHooks; | |||
| std::unordered_map<std::string, std::tuple<sol::reference, lua_State*, size_t>> consoleCommands; | |||
| std::vector<std::tuple<sol::reference, lua_State*, std::string, std::string, std::string>> registeredHotkeys; | |||
| std::vector<LuaComponent*> loadedComponents; | |||
| private: | |||
| sol::table callbacks; | |||
| sol::environment consoleEnvironment; | |||
| }; | |||
| @@ -0,0 +1,188 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <ItemGroup Label="ProjectConfigurations"> | |||
| <ProjectConfiguration Include="Debug-JIT|x64"> | |||
| <Configuration>Debug-JIT</Configuration> | |||
| <Platform>x64</Platform> | |||
| </ProjectConfiguration> | |||
| <ProjectConfiguration Include="Debug|x64"> | |||
| <Configuration>Debug</Configuration> | |||
| <Platform>x64</Platform> | |||
| </ProjectConfiguration> | |||
| <ProjectConfiguration Include="Release|x64"> | |||
| <Configuration>Release</Configuration> | |||
| <Platform>x64</Platform> | |||
| </ProjectConfiguration> | |||
| </ItemGroup> | |||
| <PropertyGroup Label="Globals"> | |||
| <VCProjectVersion>16.0</VCProjectVersion> | |||
| <Keyword>Win32Proj</Keyword> | |||
| <ProjectGuid>{df0b7199-3ed8-49dc-9544-46b6315d4390}</ProjectGuid> | |||
| <RootNamespace>BL3Lua</RootNamespace> | |||
| <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |||
| <ProjectName>BLua</ProjectName> | |||
| </PropertyGroup> | |||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> | |||
| <ConfigurationType>DynamicLibrary</ConfigurationType> | |||
| <UseDebugLibraries>true</UseDebugLibraries> | |||
| <PlatformToolset>ClangCL</PlatformToolset> | |||
| <CharacterSet>Unicode</CharacterSet> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-JIT|x64'" Label="Configuration"> | |||
| <ConfigurationType>DynamicLibrary</ConfigurationType> | |||
| <UseDebugLibraries>true</UseDebugLibraries> | |||
| <PlatformToolset>ClangCL</PlatformToolset> | |||
| <CharacterSet>Unicode</CharacterSet> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> | |||
| <ConfigurationType>DynamicLibrary</ConfigurationType> | |||
| <UseDebugLibraries>false</UseDebugLibraries> | |||
| <PlatformToolset>ClangCL</PlatformToolset> | |||
| <WholeProgramOptimization>true</WholeProgramOptimization> | |||
| <CharacterSet>Unicode</CharacterSet> | |||
| </PropertyGroup> | |||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> | |||
| <ImportGroup Label="ExtensionSettings"> | |||
| </ImportGroup> | |||
| <ImportGroup Label="Shared"> | |||
| </ImportGroup> | |||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||
| </ImportGroup> | |||
| <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-JIT|x64'" Label="PropertySheets"> | |||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||
| </ImportGroup> | |||
| <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||
| <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> | |||
| </ImportGroup> | |||
| <PropertyGroup Label="UserMacros" /> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||
| <LinkIncremental>true</LinkIncremental> | |||
| <IncludePath>C:\SDK_GEN\BL3-2021-4-9\SDK;F:\Programmieren\Lua\sol2\single\single\include;F:\Programmieren\Lua\lua-5.4.2_Win64_vc16_lib\include;F:\Programmieren\Lua;F:\Programmieren\C++\BL3\BL3Lua\include;$(IncludePath)</IncludePath> | |||
| <LibraryPath>F:\Programmieren\C++\BL3\BL3Lua\lib;$(LibraryPath)</LibraryPath> | |||
| <SourcePath>$(SourcePath)</SourcePath> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-JIT|x64'"> | |||
| <LinkIncremental>true</LinkIncremental> | |||
| <IncludePath>C:\SDK_GEN\BL3-2021-4-9\SDK;F:\Programmieren\Lua\sol2\single\single\include;F:\Programmieren\Lua\lua-5.4.2_Win64_vc16_lib\include;F:\Programmieren\Lua;F:\Programmieren\C++\BL3\BL3Lua\include;$(IncludePath)</IncludePath> | |||
| <LibraryPath>F:\Programmieren\C++\BL3\BL3Lua\lib;$(LibraryPath)</LibraryPath> | |||
| <SourcePath>$(SourcePath)</SourcePath> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||
| <LinkIncremental>false</LinkIncremental> | |||
| <IncludePath>C:\SDK_GEN\BL3-2021-4-9\SDK;F:\Programmieren\Lua\sol2\single\single\include;F:\Programmieren\Lua\lua-5.4.2_Win64_vc16_lib\include;F:\Programmieren\Lua;F:\Programmieren\C++\BL3\BL3Lua\include;$(IncludePath)</IncludePath> | |||
| <LibraryPath>F:\Programmieren\C++\BL3\BL3Lua\lib;$(LibraryPath)</LibraryPath> | |||
| <SourcePath>$(SourcePath)</SourcePath> | |||
| </PropertyGroup> | |||
| <PropertyGroup Label="Vcpkg"> | |||
| <VcpkgAutoLink>false</VcpkgAutoLink> | |||
| </PropertyGroup> | |||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||
| <ClCompile> | |||
| <WarningLevel>Level3</WarningLevel> | |||
| <SDLCheck>true</SDLCheck> | |||
| <PreprocessorDefinitions>_DEBUG;BL3LUA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||
| <ConformanceMode>true</ConformanceMode> | |||
| <PrecompiledHeader>NotUsing</PrecompiledHeader> | |||
| <PrecompiledHeaderFile> | |||
| </PrecompiledHeaderFile> | |||
| <LanguageStandard>stdcpp17</LanguageStandard> | |||
| <LanguageStandard_C>stdc17</LanguageStandard_C> | |||
| <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> | |||
| <OmitFramePointers>true</OmitFramePointers> | |||
| <BufferSecurityCheck>false</BufferSecurityCheck> | |||
| <ExceptionHandling>Async</ExceptionHandling> | |||
| <RuntimeTypeInfo>false</RuntimeTypeInfo> | |||
| </ClCompile> | |||
| <Link> | |||
| <SubSystem>Windows</SubSystem> | |||
| <GenerateDebugInformation>true</GenerateDebugInformation> | |||
| <EnableUAC>false</EnableUAC> | |||
| <AdditionalDependencies>lua5.4.2-static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> | |||
| </Link> | |||
| </ItemDefinitionGroup> | |||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-JIT|x64'"> | |||
| <ClCompile> | |||
| <WarningLevel>Level3</WarningLevel> | |||
| <SDLCheck>true</SDLCheck> | |||
| <PreprocessorDefinitions>_DEBUG;BL3LUA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||
| <ConformanceMode>true</ConformanceMode> | |||
| <PrecompiledHeader>NotUsing</PrecompiledHeader> | |||
| <PrecompiledHeaderFile> | |||
| </PrecompiledHeaderFile> | |||
| <LanguageStandard>stdcpp17</LanguageStandard> | |||
| <LanguageStandard_C>stdc17</LanguageStandard_C> | |||
| <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions> | |||
| <OmitFramePointers>true</OmitFramePointers> | |||
| <BufferSecurityCheck>false</BufferSecurityCheck> | |||
| <ExceptionHandling>Async</ExceptionHandling> | |||
| <RuntimeTypeInfo>false</RuntimeTypeInfo> | |||
| </ClCompile> | |||
| <Link> | |||
| <SubSystem>Windows</SubSystem> | |||
| <GenerateDebugInformation>true</GenerateDebugInformation> | |||
| <EnableUAC>false</EnableUAC> | |||
| <AdditionalDependencies>lua5.4.2-static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> | |||
| </Link> | |||
| </ItemDefinitionGroup> | |||
| <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||
| <ClCompile> | |||
| <WarningLevel>Level3</WarningLevel> | |||
| <FunctionLevelLinking>true</FunctionLevelLinking> | |||
| <IntrinsicFunctions>true</IntrinsicFunctions> | |||
| <SDLCheck>true</SDLCheck> | |||
| <PreprocessorDefinitions>NDEBUG;BL3LUA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> | |||
| <ConformanceMode>true</ConformanceMode> | |||
| <PrecompiledHeader>NotUsing</PrecompiledHeader> | |||
| <PrecompiledHeaderFile> | |||
| </PrecompiledHeaderFile> | |||
| <LanguageStandard>stdcpp17</LanguageStandard> | |||
| <LanguageStandard_C>stdc17</LanguageStandard_C> | |||
| <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> | |||
| <OmitFramePointers>true</OmitFramePointers> | |||
| <ExceptionHandling>Async</ExceptionHandling> | |||
| <BufferSecurityCheck>false</BufferSecurityCheck> | |||
| <AdditionalOptions>-m64 /GR- %(AdditionalOptions)</AdditionalOptions> | |||
| <RuntimeTypeInfo>false</RuntimeTypeInfo> | |||
| </ClCompile> | |||
| <Link> | |||
| <SubSystem>Windows</SubSystem> | |||
| <EnableCOMDATFolding>true</EnableCOMDATFolding> | |||
| <OptimizeReferences>true</OptimizeReferences> | |||
| <GenerateDebugInformation>true</GenerateDebugInformation> | |||
| <EnableUAC>false</EnableUAC> | |||
| <AdditionalDependencies>lua5.4.2-static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> | |||
| <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> | |||
| </Link> | |||
| </ItemDefinitionGroup> | |||
| <ItemGroup> | |||
| <ClCompile Include="BL3Lua.cpp" /> | |||
| <ClCompile Include="BL3LuaDLL.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_Basic.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_CoreUObject_functions.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_Engine_functions.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_GbxUI_functions.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_OakGame_functions.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_ScaleformUI_functions.cpp" /> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_UMG_functions.cpp" /> | |||
| <ClCompile Include="LuaComponent.cpp" /> | |||
| <ClCompile Include="LuaUtility.cpp" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ClInclude Include="BitFields.hpp" /> | |||
| <ClInclude Include="BL3Lua.h" /> | |||
| <ClInclude Include="Helper.hpp" /> | |||
| <ClInclude Include="include\LuaComponent.h" /> | |||
| <ClInclude Include="include\Patterns.h" /> | |||
| <ClInclude Include="include\Utility.hpp" /> | |||
| <ClInclude Include="LuaUtility.h" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <None Include="include\json.lua" /> | |||
| <None Include="split.lua" /> | |||
| </ItemGroup> | |||
| <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | |||
| <ImportGroup Label="ExtensionTargets"> | |||
| </ImportGroup> | |||
| </Project> | |||
| @@ -0,0 +1,86 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <ItemGroup> | |||
| <Filter Include="Source Files"> | |||
| <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> | |||
| <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions> | |||
| </Filter> | |||
| <Filter Include="Header Files"> | |||
| <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> | |||
| <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions> | |||
| </Filter> | |||
| <Filter Include="Resource Files"> | |||
| <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> | |||
| <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> | |||
| </Filter> | |||
| <Filter Include="SDK-CPP"> | |||
| <UniqueIdentifier>{f40848c6-786f-425a-aeb2-8f803968ded9}</UniqueIdentifier> | |||
| </Filter> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ClCompile Include="BL3LuaDLL.cpp"> | |||
| <Filter>Source Files</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="BL3Lua.cpp"> | |||
| <Filter>Source Files</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="LuaUtility.cpp"> | |||
| <Filter>Source Files</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="LuaComponent.cpp"> | |||
| <Filter>Source Files</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_CoreUObject_functions.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_Basic.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_OakGame_functions.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_Engine_functions.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_GbxUI_functions.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_ScaleformUI_functions.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="C:\SDK_GEN\BL3-2021-4-9\SDK\BL3_UMG_functions.cpp"> | |||
| <Filter>SDK-CPP</Filter> | |||
| </ClCompile> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <ClInclude Include="BitFields.hpp"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="BL3Lua.h"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="Helper.hpp"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="LuaUtility.h"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="include\LuaComponent.h"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="include\Patterns.h"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="include\Utility.hpp"> | |||
| <Filter>Header Files</Filter> | |||
| </ClInclude> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <None Include="include\json.lua"> | |||
| <Filter>Resource Files</Filter> | |||
| </None> | |||
| <None Include="split.lua"> | |||
| <Filter>Resource Files</Filter> | |||
| </None> | |||
| </ItemGroup> | |||
| </Project> | |||
| @@ -0,0 +1,18 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> | |||
| <LocalDebuggerCommand>E:\SteamLibrary\steamapps\common\Borderlands 3\OakGame\Binaries\Win64\Borderlands3.exe</LocalDebuggerCommand> | |||
| <LocalDebuggerAttach>true</LocalDebuggerAttach> | |||
| <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-JIT|x64'"> | |||
| <LocalDebuggerCommand>E:\SteamLibrary\steamapps\common\Borderlands 3\OakGame\Binaries\Win64\Borderlands3.exe</LocalDebuggerCommand> | |||
| <LocalDebuggerAttach>true</LocalDebuggerAttach> | |||
| <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> | |||
| </PropertyGroup> | |||
| <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> | |||
| <LocalDebuggerCommand>E:\SteamLibrary\steamapps\common\Borderlands 3\OakGame\Binaries\Win64\Borderlands3.exe</LocalDebuggerCommand> | |||
| <LocalDebuggerAttach>true</LocalDebuggerAttach> | |||
| <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> | |||
| </PropertyGroup> | |||
| </Project> | |||
| @@ -0,0 +1,88 @@ | |||
| #pragma once | |||
| #include <cstddef> | |||
| #include <cstdint> | |||
| #include <climits> | |||
| #include <type_traits> | |||
| // https://stackoverflow.com/a/263738 | |||
| /* a=target variable, b=bit number to act upon 0-n */ | |||
| #define BIT_SET(a,b) ((a) |= (1ULL<<(b))) | |||
| #define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b))) | |||
| #define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b))) | |||
| #define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b)))) // '!!' to make sure this returns 0 or 1 | |||
| /* x=target variable, y=mask */ | |||
| #define BITMASK_SET(x,y) ((x) |= (y)) | |||
| #define BITMASK_CLEAR(x,y) ((x) &= (~(y))) | |||
| #define BITMASK_FLIP(x,y) ((x) ^= (y)) | |||
| #define BITMASK_CHECK_ALL(x,y) (!(~(x) & (y))) | |||
| #define BITMASK_CHECK_ANY(x,y) ((x) & (y)) | |||
| namespace itsy_bitsy { | |||
| template <std::size_t sz, typename C = void> | |||
| struct bit_type { | |||
| typedef uint64_t type; | |||
| }; | |||
| template <std::size_t sz> | |||
| struct bit_type<sz, std::enable_if_t<(sz <= 1)>> { | |||
| typedef bool type; | |||
| }; | |||
| template <std::size_t sz> | |||
| struct bit_type<sz, std::enable_if_t<(sz > 2 && sz <= 16)>> { | |||
| typedef uint16_t type; | |||
| }; | |||
| template <std::size_t sz> | |||
| struct bit_type<sz, std::enable_if_t<(sz > 16 && sz <= 32)>> { | |||
| typedef uint32_t type; | |||
| }; | |||
| template <std::size_t sz> | |||
| struct bit_type<sz, std::enable_if_t<(sz > 32 && sz <= 64)>> { | |||
| typedef uint64_t type; | |||
| }; | |||
| template <std::size_t sz> | |||
| using bit_type_t = typename bit_type<sz>::type; | |||
| template <typename T, typename V> | |||
| bool vcxx_warning_crap(std::true_type, V val) { | |||
| return val != 0; | |||
| } | |||
| template <typename T, typename V> | |||
| T vcxx_warning_crap(std::false_type, V val) { | |||
| return static_cast<T>(val); | |||
| } | |||
| template <typename T, typename V> | |||
| auto vcxx_warning_crap(V val) { | |||
| return vcxx_warning_crap<T>(std::is_same<bool, T>(), val); | |||
| } | |||
| template <typename Base, std::size_t baseOffset = 0x0, std::size_t bit_target = 0x0, std::size_t size = 0x1> | |||
| void write(Base& b, bit_type_t<size> bits) { | |||
| uintptr_t baseAddr = reinterpret_cast<uintptr_t>(&b); | |||
| uintptr_t offs = baseOffset; | |||
| unsigned char* byt = reinterpret_cast<unsigned char*>(baseAddr + offs); | |||
| char testb = *byt & (1 << bit_target); | |||
| if (bits) | |||
| BIT_SET(*byt, bit_target); | |||
| else | |||
| BIT_CLEAR(*byt, bit_target); | |||
| } | |||
| template <typename Base, std::size_t baseOffset = 0x0, std::size_t bit_target = 0x0, std::size_t size = 0x1> | |||
| bit_type_t<size> read(Base& b) { | |||
| uintptr_t baseAddr = reinterpret_cast<uintptr_t>(&b); | |||
| uintptr_t offs = baseOffset; | |||
| unsigned char* byt = reinterpret_cast<unsigned char*>(baseAddr + offs); | |||
| char test = *byt & (1 << bit_target); | |||
| if (test) | |||
| return true; | |||
| return false; | |||
| } | |||
| } | |||
| @@ -0,0 +1,78 @@ | |||
| #pragma once | |||
| #include <windows.h> | |||
| /* | |||
| A safer replacement for the obsolete IsBadReadPtr() and IsBadWritePtr() WinAPI functions | |||
| on top of VirtualQuery() which respects Windows guard pages. It does not use SEH | |||
| and is designed to be compatible with the above-mentioned functions. | |||
| The calls to the IsBadReadPtr() and IsBadWritePtr() can be replaced with the calls to | |||
| the IsBadMemPtr() as follows: | |||
| - IsBadReadPtr(...) => IsBadMemPtr(FALSE, ...) | |||
| - IsBadWritePtr(...) => IsBadMemPtr(TRUE, ...) | |||
| */ | |||
| BOOL IsBadMemPtr(/*BOOL write, */void* ptr, size_t size) | |||
| { | |||
| MEMORY_BASIC_INFORMATION mbi; | |||
| BOOL ok; | |||
| DWORD mask; | |||
| BYTE* p = (BYTE*)ptr; | |||
| BYTE* maxp = p + size; | |||
| BYTE* regend = NULL; | |||
| if (size == 0) | |||
| { | |||
| return FALSE; | |||
| } | |||
| if (p == NULL) | |||
| { | |||
| return TRUE; | |||
| } | |||
| /*if (write == FALSE) | |||
| { | |||
| mask = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; | |||
| } | |||
| else | |||
| {*/ | |||
| mask = PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY; | |||
| /*}*/ | |||
| do | |||
| { | |||
| if (p == ptr || p == regend) | |||
| { | |||
| if (VirtualQuery((LPCVOID)p, &mbi, sizeof(mbi)) == 0) | |||
| { | |||
| return TRUE; | |||
| } | |||
| else | |||
| { | |||
| regend = ((BYTE*)mbi.BaseAddress + mbi.RegionSize); | |||
| } | |||
| } | |||
| ok = (mbi.Protect & mask) != 0; | |||
| if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) | |||
| { | |||
| ok = FALSE; | |||
| } | |||
| if (!ok) | |||
| { | |||
| return TRUE; | |||
| } | |||
| if (maxp <= regend) /* the whole address range is inside the current memory region */ | |||
| { | |||
| return FALSE; | |||
| } | |||
| else if (maxp > regend) /* this region is a part of (or overlaps with) the address range we are checking */ | |||
| { | |||
| p = regend; /* lets move to the next memory region */ | |||
| } | |||
| } while (p < maxp); | |||
| return FALSE; | |||
| } | |||
| @@ -0,0 +1,61 @@ | |||
| #include "LuaComponent.h" | |||
| LuaComponent::LuaComponent() { | |||
| this->m_Env = nullptr; | |||
| this->m_FileName = ""; | |||
| } | |||
| LuaComponent::LuaComponent(const std::string& fileName, sol::state* state) { | |||
| this->m_FileName = fileName; | |||
| this->state = state; | |||
| } | |||
| LuaComponent::~LuaComponent() { | |||
| if (m_Env) { | |||
| sol::protected_function releaseFunc = m_Env["OnRelease"]; | |||
| if (releaseFunc.valid()) { | |||
| releaseFunc.call(); | |||
| } | |||
| m_Env.clear(); | |||
| m_Env = sol::lua_nil; | |||
| } | |||
| } | |||
| void LuaComponent::Init() { | |||
| LoadScript(m_FileName); | |||
| OnInit(); | |||
| } | |||
| void LuaComponent::OnInit() { | |||
| if (m_Env) { | |||
| sol::protected_function initFunc = m_Env["OnInit"]; | |||
| if (initFunc.valid()) { | |||
| initFunc.call(); | |||
| } | |||
| } | |||
| } | |||
| void LuaComponent::LoadScript(const std::string& fileName) { | |||
| m_FileName = fileName; | |||
| //m_Env = std::make_unique<sol::environment>(sol::environment(*state, sol::create, state->globals())).get(); | |||
| m_Env = sol::environment(*state, sol::create, state->globals()); | |||
| sol::load_result error = state->load_file(fileName); | |||
| if (error.status() == sol::load_status::ok) { | |||
| try { | |||
| auto func_result = state->safe_script_file(fileName, m_Env); | |||
| if (!func_result.valid()) { | |||
| sol::error err = error; | |||
| std::cout << "[LUA] lua_dofile failed with error: " << err.what() << std::endl; | |||
| sol::protected_function printFunc = (*(state))["PrintGameConsole"]; | |||
| if (printFunc.valid()) { | |||
| std::string errorMessage = std::string("[LUA] failed with error: ").append(err.what()); | |||
| printFunc(errorMessage); | |||
| } | |||
| } | |||
| } | |||
| catch (...) { | |||
| } | |||
| } | |||
| state->collect_garbage(); | |||
| } | |||
| @@ -0,0 +1,151 @@ | |||
| #include "LuaUtility.h" | |||
| #include <windows.h> | |||
| #include <WinUser.h> | |||
| #include <string> | |||
| static std::unordered_map<std::string, uint8_t> keyMap; | |||
| LuaUtility::LuaUtility() | |||
| { | |||
| keyMap = GetKeyMap(); | |||
| } | |||
| bool LuaUtility::IsKeyPressed(std::string keyName) | |||
| { | |||
| if (keyName.length() > 1) { | |||
| std::transform(keyName.begin(), keyName.end(), keyName.begin(), [](unsigned char c) {return std::tolower(c); }); | |||
| auto keycode = GetKeyMap()[keyName]; | |||
| return (GetAsyncKeyState(GetKeyMap()[keyName]) & 0x8000) != 0; | |||
| } | |||
| else { | |||
| std::transform(keyName.begin(), keyName.end(), keyName.begin(), [](unsigned char c) {return std::toupper(c); }); | |||
| return (GetAsyncKeyState(keyName.c_str()[0]) & 0x8000) != 0; | |||
| } | |||
| return false; | |||
| } | |||
| bool LuaUtility::IsKeyPressed(std::string keyName, std::string keyName2) | |||
| { | |||
| std::vector<uint8_t> keys; | |||
| std::string current = keyName; | |||
| for (int i = 0; i < 2; i++) { | |||
| if (current.length() > 1) { | |||
| std::transform(current.begin(), current.end(), current.begin(), [](unsigned char c) {return std::tolower(c); }); | |||
| keys.push_back(GetKeyMap()[current]); | |||
| } | |||
| else { | |||
| std::transform(current.begin(), current.end(), current.begin(), [](unsigned char c) {return std::toupper(c); }); | |||
| keys.push_back(current.c_str()[0]); | |||
| } | |||
| current = keyName2; | |||
| } | |||
| return ((GetAsyncKeyState(keys[0]) & 0x8000) && GetAsyncKeyState(keys[1]) & 0x8000) != 0; | |||
| } | |||
| bool LuaUtility::IsKeyPressed(std::string keyName, std::string keyName2, std::string keyName3) | |||
| { | |||
| std::vector<uint8_t> keys; | |||
| std::string current = keyName; | |||
| for (int i = 0; i < 3; i++) { | |||
| if (current.length() > 1) { | |||
| std::transform(current.begin(), current.end(), current.begin(), [](unsigned char c) {return std::tolower(c); }); | |||
| keys.push_back(GetKeyMap()[current]); | |||
| } | |||
| else { | |||
| std::transform(current.begin(), current.end(), current.begin(), [](unsigned char c) {return std::toupper(c); }); | |||
| keys.push_back(current.c_str()[0]); | |||
| } | |||
| if (i == 0) | |||
| current = keyName2; | |||
| else | |||
| current = keyName3; | |||
| } | |||
| return ((GetAsyncKeyState(keys[0]) & 0x8000) && GetAsyncKeyState(keys[1] & 0x8000) && GetAsyncKeyState(keys[2]) & 0x8000) != 0; | |||
| } | |||
| bool LuaUtility::ContainsKey(std::string keyName) { | |||
| if (keyMap.size() == 0) | |||
| keyMap = GetKeyMap(); | |||
| std::transform(keyName.begin(), keyName.end(), keyName.begin(), [](unsigned char c) {return std::tolower(c); }); | |||
| return keyMap.find(keyName) != keyMap.end(); | |||
| } | |||
| std::unordered_map<std::string, uint8_t> LuaUtility::GetKeyMap() | |||
| { | |||
| if (!keyMap.size()) { | |||
| keyMap.insert(std::pair<std::string, uint8_t>("backspace", VK_BACK)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("tab", VK_TAB)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("clear", VK_CLEAR)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("return", VK_RETURN)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("enter", VK_RETURN)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("shift", VK_SHIFT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("ctrl", VK_CONTROL)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("alt", VK_MENU)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("pause", VK_PAUSE)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("capslock", VK_CAPITAL)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("escape", VK_ESCAPE)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("space", VK_SPACE)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("pageup", VK_PRIOR)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("pagedown", VK_NEXT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("end", VK_END)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("home", VK_HOME)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("left", VK_LEFT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("up", VK_UP)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("right", VK_RIGHT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("down", VK_DOWN)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("printscr", VK_SNAPSHOT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("insert", VK_INSERT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("delete", VK_DELETE)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f1", VK_F1)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f2", VK_F2)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f3", VK_F3)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f4", VK_F4)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f5", VK_F5)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f6", VK_F6)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f7", VK_F7)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f8", VK_F8)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f9", VK_F9)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f10", VK_F10)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f11", VK_F11)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("f12", VK_F12)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad0", VK_NUMPAD0)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad1", VK_NUMPAD1)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad2", VK_NUMPAD2)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad3", VK_NUMPAD3)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad4", VK_NUMPAD4)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad5", VK_NUMPAD5)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad6", VK_NUMPAD6)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad7", VK_NUMPAD7)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad8", VK_NUMPAD8)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numpad9", VK_NUMPAD9)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("multiply", VK_MULTIPLY)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("add", VK_ADD)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("subtract", VK_SUBTRACT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("decimal", VK_DECIMAL)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("divide", VK_DIVIDE)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("numlock", VK_NUMLOCK)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("0", 0x30)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("1", 0x31)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("2", 0x32)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("3", 0x33)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("4", 0x34)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("5", 0x35)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("6", 0x36)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("7", 0x37)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("8", 0x38)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("9", 0x39)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("scrollock", VK_SCROLL)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("lshift", VK_LSHIFT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("rshift", VK_RSHIFT)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("lctrl", VK_LCONTROL)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("rctrl", VK_RCONTROL)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("lalt", VK_LMENU)); | |||
| keyMap.insert(std::pair<std::string, uint8_t>("ralt", VK_RMENU)); | |||
| } | |||
| return keyMap; | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| #pragma once | |||
| #include <algorithm> | |||
| #include <vector> | |||
| #include <unordered_map> | |||
| class LuaUtility | |||
| { | |||
| public: | |||
| LuaUtility(); | |||
| static bool IsKeyPressed(std::string keyName); | |||
| static bool IsKeyPressed(std::string keyName, std::string keyName2); | |||
| static bool IsKeyPressed(std::string keyName, std::string keyName2, std::string keyName3); | |||
| static bool ContainsKey(std::string keyName); | |||
| private: | |||
| static std::unordered_map<std::string, uint8_t> GetKeyMap(); | |||
| }; | |||
| @@ -0,0 +1,21 @@ | |||
| #pragma once | |||
| #include "F:/Programmieren/Lua/sol2/single/single/include/sol/sol.hpp" | |||
| #include <iostream> | |||
| class LuaComponent | |||
| { | |||
| public: | |||
| LuaComponent(); | |||
| LuaComponent(const std::string& fileName, sol::state* state); | |||
| ~LuaComponent(); | |||
| void Init(); | |||
| void OnInit(); | |||
| void LoadScript(const std::string& fileName); | |||
| public: | |||
| std::string m_FileName; | |||
| sol::environment m_Env; | |||
| sol::state* state; | |||
| }; | |||
| @@ -0,0 +1,73 @@ | |||
| #pragma once | |||
| #include "F:/Programmieren/C++/xorstr-master/include/xorstr.hpp" | |||
| auto gObjPattern = xorstr("44 8b 54 24 50 48 8d 05 ?? ?? ?? ?? ?? f6 48 89 01 48 89 71 10"); | |||
| auto gNamesPattern = xorstr("48 83 EC 28 48 8B 05 ?? ?? ?? ?? 48 85 C0 75 5F B9 08 04 ?? ?? 48 89 5C 24 20 E8"); | |||
| auto processEventPattern = xorstr("40 55 56 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 48 8D ?? ?? ?? 48 89 9D ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C5 48 89 85 ?? ?? ?? ?? 8B 41"); | |||
| auto getTransientPackagePattern = xorstr("48 8b 4c 24 50 48 89 05 ?? ?? ?? ?? 48 85 c9 74 05 e8"); | |||
| auto mallocPattern = xorstr("48 89 5C 24 ?? 57 48 83 EC 20 48 8B F9 8B DA 48 8B 0D ?? ?? ?? ?? 48 85 C9 75 0C E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B 01 44 8B C3 48 8B D7 48 8B 5C 24 ?? 48 83 C4 20 5F 48 FF 60 10"); | |||
| auto reallocPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F1 41 8B D8 48 8B 0D ?? ?? ?? ?? 48 8B FA 48 85 C9 75 0C E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B 01 44 8B CB 4C 8B C7 48 8B D6 48 8B 5C 24 ?? 48 8B 74 24 ?? 48 83 C4 20 5F 48 FF 60 18"); | |||
| auto fnamectorPattern = xorstr("40 53 48 83 EC 30 C7 44 24"); | |||
| auto ufunctionBindPattern = xorstr("40 ?? 48 83 EC ?? 48 8B ?? E8 ?? ?? ?? ?? F7 83 88 00 00 00"); | |||
| auto ftextfromstringPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 48 63 7A ?? 33 C0 48 8B 32 48 8B D9 48 89 44 24 ?? 89 7C 24 ?? 85 FF 75 ?? 89 44 24 ?? EB ?? 45 33 C0 48 8D 4C 24 ?? 8B D7 E8 ?? ?? ?? ?? 48 8B"); | |||
| auto getWorldFromContextObjectPattern = xorstr("48 89 5c 24 18 56 48 83 ec 40 41 8b d8 48 8b f2 48 85 d2 75 2a 83 fb 01 75 18 33 c0 48 8d"); | |||
| auto isValidLowLevelPattern = xorstr("4C 8B C1 48 85 C9 74 4F"); | |||
| auto staticConstructObjectPattern = xorstr("48 89 5C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 85 ?? ?? ?? ?? 44 8B A5"); | |||
| auto staticDuplicateObjectPattern = xorstr("4C 89 44 24 ?? 55 53 56 57 41 54 41 56 41 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 8B 05"); | |||
| auto newObjectPattern = xorstr("48 89 5c 24 18 55 56 57 41 54 41 55 41 56 41 57 48 8d ac 24 40 ff ff ff 48 81 ec c0 01 00 00 48 8b 05 ?? ?? ?? ?? 48 33 c4 48 89 85 b0 00 00 00 44 8b a5 20 01 00 00"); | |||
| auto getWorldPattern = xorstr("40 53 48 83 EC 20 8B 41 ?? 48 8B D9 C1 E8 04 A8 01 75 ?? 48 8B 49"); | |||
| auto spawnActorPattern = xorstr("40 53 56 57 48 83 EC 70 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 44 24 ?? 0F 28 1D"); | |||
| auto getMapNamePattern = xorstr("48 89 5C 24 ?? 56 48 83 EC 30 33 F6 48 8B D9 48 89 31 44 8B C6"); | |||
| auto functionInvokePattern = xorstr("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 20 8B 41 08 4D 8B F1"); | |||
| auto callFuncPattern = xorstr("48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 83 EC ?? 48 8B ?? ?? 48 8B ?? 49 8B ?? 48 8B ?? F2 0F"); | |||
| auto staticExecPattern = xorstr("4C 89 ?? ?? ?? 55 53 56 41 ?? 41 ?? 48 8B"); | |||
| auto getGlobalLogSingletonPattern = xorstr("48 83 EC 28 65 48 8B 04 25 ?? ?? ?? ?? 8B 0D ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8B 0C C8 8B 04 0A 39 05 ?? ?? ?? ?? 7F 0C 48 8D 05 ?? ?? ?? ?? 48 83 C4 28 C3 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 3D ?? ?? ?? ?? ?? 75 DF 48 8D 05 ?? ?? ?? ?? 66 C7 05"); | |||
| auto consoleOutputDeviceShowPattern = xorstr("40 55 53 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 45 2F 48 8B 41 20"); | |||
| auto addOutputDevicePattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 54 24 ?? 57 48 83 EC 20 48 8B F1 48 8B FA 48 83 C1 48"); | |||
| auto createConsoleOutputDevice = xorstr("48 83 EC 28 B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 C9 48 85 C0 74 25 66 C7 40"); | |||
| auto consoleOutputTextPattern = xorstr("48 8B C4 55 56 48 8D 68 A1 48 81 EC ?? ?? ?? ?? 48 89 58 08 48 63 5A 08"); | |||
| auto consoleClearOutputPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B 59 50 48 8D 71 50"); | |||
| auto addToViewportPattern = xorstr("48 8B 01 44 8B C2 33 D2"); | |||
| auto registerFunctionAPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 49 8B F0 48 8B D9 41 B8"); | |||
| auto registerFunctionOtherPattern = xorstr("45 85 C0 0F 84 ?? ?? ?? ?? 4C 8B DC 41 56"); | |||
| auto staticLoadObjectPattern = xorstr("40 ?? 53 56 57 41 ?? 41 ?? 41 ?? 41 ?? 48 8D ?? ?? ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? ?? ?? ?? 0F B6 ?? ?? ?? ?? ?? 49 8B ?? 4C 8B ?? ?? ?? ?? ?? 33 DB"); | |||
| auto staticFindObjectPattern = xorstr("48 89 5C 24 ?? 48 89 74 24 ?? 55 57 41 54 41 56 41 57 48 8B EC 48 83 EC 60 80 3D"); | |||
| auto dumpObjectToStringPattern = xorstr("4C 8B ?? 53 48 81 EC ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? ?? ?? ?? ?? 49 89 ?? ?? B9"); | |||
| auto FOakPlayerManager__DoSparkAuthenticationPattern = xorstr("48 8B ?? 55 53 56 48 8D ?? ?? 48 81 EC ?? ?? ?? ?? 48 89 ?? ?? 33 FF"); | |||
| auto FOakStartupProcess__PerformStepPattern = xorstr("40 ?? 53 56 57 48 8D ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B ?? ?? 48 8B ?? 48 89"); | |||
| auto FGbxSparkModuleGetPattern = xorstr("48 83 EC ?? 48 8B ?? ?? ?? ?? ?? 48 85 ?? 75 ?? 44 8D ?? ?? 48 89 ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 48 8D ?? ?? ?? E8 ?? ?? ?? ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 8B ?? ?? ?? 48 83 C4 ?? C3 CC CC 48 89 ?? ?? ?? 57"); | |||
| auto FSparkInitProcessStartProcessPattern = xorstr("40 57 48 83 EC 20 48 83 3D ?? ?? ?? ?? ?? 48 8B F9 75 34"); | |||
| auto FSparkInitProcessReadDiscoveryPattern = xorstr("48 8B ?? 55 48 8D ?? ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 89 ?? ?? 48 89 ?? ?? 0F B6"); | |||
| auto oakGameInstanceProcessPendingMicropatchesPattern = xorstr("4C 8B ?? 55 56 41 ?? 49 8D ?? ?? 48 81 EC ?? ?? ?? ?? 4C 8D"); | |||
| auto oakGameStateRefreshMicropatchSwitchesPattern = xorstr("40 ?? 48 83 EC ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? ?? 80 B9 28 01 00 00"); | |||
| auto buildMainMenuPattern = xorstr("40 ?? 56 41 ?? 48 8D ?? ?? ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? ?? ?? ?? 45 33"); | |||
| auto buildPauseMenuPattern = xorstr("48 8B ?? 55 53 57 48 8D ?? ?? 48 81 EC ?? ?? ?? ?? 48 89 ?? ?? 48 8B ?? 4C 89 ?? ?? 4C 89 ?? ?? 4C 89"); | |||
| auto buildOptionsMenuPattern = xorstr("48 8B C4 55 56 48 8D 68 A1 48 81 EC ?? ?? ?? ?? 48 83 B9 ?? ?? ?? ?? ?? 48 8B F1 0F 84 ?? ?? ?? ?? 80 B9 ?? ?? ?? ?? ?? 48 89 58 E8"); | |||
| auto mainAndPauseMenuAddMenuItemPattern = xorstr("48 89 54 24 ?? 48 89 4C 24 ?? 55 53 56 57 41 55 41 56 41 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 83 B9"); | |||
| auto mainAndPauseMenuRemoveAllItemsPattern = xorstr("40 ?? 48 83 EC ?? 48 8B ?? 48 81 C1 ?? ?? ?? ?? 83 79 0C ?? C7 41 08 ?? ?? ?? ?? 74 ?? 33 D2 E8 ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 85"); | |||
| auto mainAndPauseMenuStartMenuTransitionPattern = xorstr("48 89 5C 24 ?? 55 57 41 56 48 81 EC ?? ?? ?? ?? 83 B9"); | |||
| auto scrollingListInsertListItemPattern = xorstr("48 8B ?? 4C 89 ?? ?? 55 48 8D ?? ?? 48 81 EC ?? ?? ?? ?? 48 89 ?? ?? 4C 8B"); | |||
| auto listItemNumberInitializeItemPattern = xorstr("40 ?? 48 83 EC ?? 0F 29 ?? ?? ?? 48 8B ?? 48 8B ?? ?? ?? ?? ?? 0F 28 ?? 0F 29 ?? ?? ?? 0F 28 ?? 48 85 ?? 74 ?? 48 8B ?? 45 33"); | |||
| auto optionBaseCreateContentPanelPattern = xorstr("40 ?? 48 83 EC ?? 48 8B ?? ?? ?? 48 8B ?? 48 89 ?? ?? 48 8B"); | |||
| auto optionBaseCreateContentPanelItemPattern = xorstr("48 85 ?? 0F 84 ?? ?? ?? ?? 56 57 48 83 EC ?? 48 8B ?? 48 8B ?? E8 ?? ?? ?? ?? 84 C0"); | |||
| auto optionBaseMenuLoadBaseOptionsMenuPattern = xorstr("40 ?? 41 ?? 48 8B ?? 48 83 EC ?? 4C 8B ?? E8 ?? ?? ?? ?? 49 83 BE 10 06 00 00"); | |||
| auto gfxOptionsMenuCreateOptionPanelPattern = xorstr("89 54 ?? ?? 55 56 41 ?? 48 8D ?? ?? ?? ?? ?? ?? 48 81 EC"); | |||
| auto gfxOptionsMenuOnGFxMenuIsInitedAndStartedBeginPattern = xorstr("40 ?? 48 83 EC ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? E8 ?? ?? ?? ?? 8B 15"); | |||
| auto optionBaseSetupSpinnerItemPattern = xorstr("48 89 ?? ?? ?? 48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 83 EC ?? 49 8B ?? 41 8B ?? 48 8B ?? 48 8B ?? 48 85 ?? 0F 84 ?? ?? ?? ?? 48 8D ?? ?? ?? 48 8B ?? E8 ?? ?? ?? ?? 4C 8D ?? ?? ?? ?? ?? 48 89 ?? ?? ?? 44 8B ?? 48 8D ?? ?? ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? 48 85 ?? 74 ?? 48 8B ?? 48 8B ?? E8 ?? ?? ?? ?? 48 83 7F 70"); | |||
| auto optionBaseSetupSpinnerItemAsBooleanPattern = xorstr("48 8B ?? 48 89 ?? ?? 55 57 41 ?? 48 81 EC ?? ?? ?? ?? 49 8B ?? 41 0F"); | |||
| auto optionBaseSetupSpinnerItemWithTextPattern = xorstr("48 89 ?? ?? ?? 56 57 41 ?? 48 83 EC ?? 48 83 B9 80 00 00 00 ?? 41 8B"); | |||
| auto optionBaseSetupTitleItemPattern = xorstr("4C 8B ?? 55 53 57 49 8D ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? 48 89 ?? ?? 48 83 B9 80 00 00 00"); | |||
| auto optionBaseSetupButtonItemPattern = xorstr("48 89 ?? ?? ?? 48 89 ?? ?? ?? 41 ?? 48 83 EC ?? 49 8B ?? 48 8B ?? 4C 8B ?? 48 85 ?? 0F 84"); | |||
| auto optionBaseSetupSliderItemPattern = xorstr("48 8B ?? 55 56 41 ?? 48 81 EC ?? ?? ?? ?? 0F 29 ?? ?? 0F 28 ?? 4D 8B"); | |||
| auto optionBaseSetupDropdownListItemPattern = xorstr("48 89 ?? ?? ?? 48 89 ?? ?? ?? 48 89 ?? ?? ?? 57 48 83 EC ?? 41 8B ?? 49 8B ?? 48 8B ?? 48 8B ?? 48 85 ?? 0F 84 ?? ?? ?? ?? 48 8D ?? ?? ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? ?? 48 8D ?? ?? ?? 44 8B ?? 48 89 ?? ?? ?? 4C 8B ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? 48 85 ?? 74 ?? 48 8B ?? 48 8B ?? E8 ?? ?? ?? ?? 48 83 7F 70 ?? 74 ?? 80 BB 17 01 00 00 ?? 74 ?? 48 8B ?? ?? 48 85 ?? 74 ?? E8 ?? ?? ?? ?? 84 C0 74 ?? B2 ?? EB ?? 32 D2 48 8D ?? ?? ?? ?? ?? 48 8B ?? FF 50 ?? 48 8B"); | |||
| auto optionBaseSetupControlsItemPattern = xorstr("48 8B ?? 57 41 ?? 41 ?? 41 ?? 48 83 EC ?? 4D 8B"); | |||
| auto listItemSpinnerSetDefaultValuePattern = xorstr("48 8B ?? 89 91 ?? ?? ?? ?? C6 81 3C 03 00 00"); | |||
| auto listItemNumberGetCurrentValuePattern = xorstr("48 89 ?? ?? ?? 57 48 83 EC ?? 48 8B ?? 48 8B ?? 48 8B ?? ?? ?? ?? ?? 48 85 ?? 74 ?? E8 ?? ?? ?? ?? 48 85 ?? 74 ?? 48 8B ?? E8 ?? ?? ?? ?? F3 0F ?? ?? ?? ?? ?? ?? 65 48 ?? ?? ?? ?? ?? ?? ?? 8B 0D ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8B ?? ?? 8B 04 ?? 39 05 ?? ?? ?? ?? 0F 8F ?? ?? ?? ?? F3 0F ?? ?? ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? F3 0F"); | |||
| auto listItemNumberSetDefaultValuePattern = xorstr("40 ?? 48 83 EC ?? F3 0F ?? ?? ?? ?? ?? ?? 48 8B ?? C6 81 84 03 00 00"); | |||
| auto listItemComboBoxSetDefaultValuePattern = xorstr("48 8B ?? ?? ?? ?? ?? 89 91 ?? ?? ?? ?? C6 81 2C 03 00 00"); | |||
| auto listItemComboBoxGetSelectedIndexPattern = xorstr("48 8B ?? ?? ?? ?? ?? 48 85 ?? 74 ?? 48 8B ?? ?? ?? ?? ?? 8B 80 ?? ?? ?? ?? C3"); | |||
| auto listItemSpinnerGetCurrentSelectionIndexPattern = xorstr("48 8B ?? ?? ?? ?? ?? 48 85 ?? 0F 85 ?? ?? ?? ?? B8 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC CC CC 48 8B"); | |||
| @@ -0,0 +1,14 @@ | |||
| #pragma once | |||
| std::string Replace(std::string str, const std::string& strToFind, const std::string& replaceWith) { | |||
| size_t index = 0; | |||
| std::string result = str; | |||
| while (true) { | |||
| index = result.find(strToFind, index); | |||
| if (index == std::string::npos) | |||
| break; | |||
| result.replace(index, strToFind.size(), replaceWith); | |||
| index += replaceWith.size(); | |||
| } | |||
| return result; | |||
| } | |||
| @@ -0,0 +1,390 @@ | |||
| R"( | |||
| -- | |||
| -- json.lua | |||
| -- | |||
| -- Copyright (c) 2020 rxi | |||
| -- | |||
| -- Permission is hereby granted, free of charge, to any person obtaining a copy of | |||
| -- this software and associated documentation files (the "Software"), to deal in | |||
| -- the Software without restriction, including without limitation the rights to | |||
| -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |||
| -- of the Software, and to permit persons to whom the Software is furnished to do | |||
| -- so, subject to the following conditions: | |||
| -- | |||
| -- The above copyright notice and this permission notice shall be included in all | |||
| -- copies or substantial portions of the Software. | |||
| -- | |||
| -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| -- SOFTWARE. | |||
| -- | |||
| local json = { _version = "0.1.2" } | |||
| ------------------------------------------------------------------------------- | |||
| -- Encode | |||
| ------------------------------------------------------------------------------- | |||
| local encode | |||
| local escape_char_map = { | |||
| [ "\\" ] = "\\", | |||
| [ "\"" ] = "\"", | |||
| [ "\b" ] = "b", | |||
| [ "\f" ] = "f", | |||
| [ "\n" ] = "n", | |||
| [ "\r" ] = "r", | |||
| [ "\t" ] = "t", | |||
| } | |||
| local escape_char_map_inv = { [ "/" ] = "/" } | |||
| for k, v in pairs(escape_char_map) do | |||
| escape_char_map_inv[v] = k | |||
| end | |||
| local function escape_char(c) | |||
| return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) | |||
| end | |||
| local function encode_nil(val) | |||
| return "null" | |||
| end | |||
| local function encode_table(val, stack) | |||
| local res = {} | |||
| stack = stack or {} | |||
| -- Circular reference? | |||
| if stack[val] then error("circular reference") end | |||
| stack[val] = true | |||
| if rawget(val, 1) ~= nil or next(val) == nil then | |||
| -- Treat as array -- check keys are valid and it is not sparse | |||
| local n = 0 | |||
| for k in pairs(val) do | |||
| if type(k) ~= "number" then | |||
| error("invalid table: mixed or invalid key types") | |||
| end | |||
| n = n + 1 | |||
| end | |||
| if n ~= #val then | |||
| error("invalid table: sparse array") | |||
| end | |||
| -- Encode | |||
| for i, v in ipairs(val) do | |||
| table.insert(res, encode(v, stack)) | |||
| end | |||
| stack[val] = nil | |||
| return "[" .. table.concat(res, ",") .. "]" | |||
| else | |||
| -- Treat as an object | |||
| for k, v in pairs(val) do | |||
| if type(k) ~= "string" then | |||
| error("invalid table: mixed or invalid key types") | |||
| end | |||
| table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) | |||
| end | |||
| stack[val] = nil | |||
| return "{" .. table.concat(res, ",") .. "}" | |||
| end | |||
| end | |||
| local function encode_string(val) | |||
| return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' | |||
| end | |||
| local function encode_number(val) | |||
| -- Check for NaN, -inf and inf | |||
| if val ~= val or val <= -math.huge or val >= math.huge then | |||
| error("unexpected number value '" .. tostring(val) .. "'") | |||
| end | |||
| return string.format("%.14g", val) | |||
| end | |||
| local type_func_map = { | |||
| [ "nil" ] = encode_nil, | |||
| [ "table" ] = encode_table, | |||
| [ "string" ] = encode_string, | |||
| [ "number" ] = encode_number, | |||
| [ "boolean" ] = tostring, | |||
| } | |||
| encode = function(val, stack) | |||
| local t = type(val) | |||
| local f = type_func_map[t] | |||
| if f then | |||
| return f(val, stack) | |||
| end | |||
| error("unexpected type '" .. t .. "'") | |||
| end | |||
| function json.encode(val) | |||
| return ( encode(val) ) | |||
| end | |||
| ------------------------------------------------------------------------------- | |||
| -- Decode | |||
| ------------------------------------------------------------------------------- | |||
| local parse | |||
| local function create_set(...) | |||
| local res = {} | |||
| for i = 1, select("#", ...) do | |||
| res[ select(i, ...) ] = true | |||
| end | |||
| return res | |||
| end | |||
| local space_chars = create_set(" ", "\t", "\r", "\n") | |||
| local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") | |||
| local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") | |||
| local literals = create_set("true", "false", "null") | |||
| local literal_map = { | |||
| [ "true" ] = true, | |||
| [ "false" ] = false, | |||
| [ "null" ] = nil, | |||
| } | |||
| local function next_char(str, idx, set, negate) | |||
| for i = idx, #str do | |||
| if set[str:sub(i, i)] ~= negate then | |||
| return i | |||
| end | |||
| end | |||
| return #str + 1 | |||
| end | |||
| local function decode_error(str, idx, msg) | |||
| local line_count = 1 | |||
| local col_count = 1 | |||
| for i = 1, idx - 1 do | |||
| col_count = col_count + 1 | |||
| if str:sub(i, i) == "\n" then | |||
| line_count = line_count + 1 | |||
| col_count = 1 | |||
| end | |||
| end | |||
| error( string.format("%s at line %d col %d", msg, line_count, col_count) ) | |||
| end | |||
| local function codepoint_to_utf8(n) | |||
| -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa | |||
| local f = math.floor | |||
| if n <= 0x7f then | |||
| return string.char(n) | |||
| elseif n <= 0x7ff then | |||
| return string.char(f(n / 64) + 192, n % 64 + 128) | |||
| elseif n <= 0xffff then | |||
| return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) | |||
| elseif n <= 0x10ffff then | |||
| return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, | |||
| f(n % 4096 / 64) + 128, n % 64 + 128) | |||
| end | |||
| error( string.format("invalid unicode codepoint '%x'", n) ) | |||
| end | |||
| local function parse_unicode_escape(s) | |||
| local n1 = tonumber( s:sub(1, 4), 16 ) | |||
| local n2 = tonumber( s:sub(7, 10), 16 ) | |||
| -- Surrogate pair? | |||
| if n2 then | |||
| return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) | |||
| else | |||
| return codepoint_to_utf8(n1) | |||
| end | |||
| end | |||
| local function parse_string(str, i) | |||
| local res = "" | |||
| local j = i + 1 | |||
| local k = j | |||
| while j <= #str do | |||
| local x = str:byte(j) | |||
| if x < 32 then | |||
| decode_error(str, j, "control character in string") | |||
| elseif x == 92 then -- `\`: Escape | |||
| res = res .. str:sub(k, j - 1) | |||
| j = j + 1 | |||
| local c = str:sub(j, j) | |||
| if c == "u" then | |||
| local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) | |||
| or str:match("^%x%x%x%x", j + 1) | |||
| or decode_error(str, j - 1, "invalid unicode escape in string") | |||
| res = res .. parse_unicode_escape(hex) | |||
| j = j + #hex | |||
| else | |||
| if not escape_chars[c] then | |||
| decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") | |||
| end | |||
| res = res .. escape_char_map_inv[c] | |||
| end | |||
| k = j + 1 | |||
| elseif x == 34 then -- `"`: End of string | |||
| res = res .. str:sub(k, j - 1) | |||
| return res, j + 1 | |||
| end | |||
| j = j + 1 | |||
| end | |||
| decode_error(str, i, "expected closing quote for string") | |||
| end | |||
| local function parse_number(str, i) | |||
| local x = next_char(str, i, delim_chars) | |||
| local s = str:sub(i, x - 1) | |||
| local n = tonumber(s) | |||
| if not n then | |||
| decode_error(str, i, "invalid number '" .. s .. "'") | |||
| end | |||
| return n, x | |||
| end | |||
| local function parse_literal(str, i) | |||
| local x = next_char(str, i, delim_chars) | |||
| local word = str:sub(i, x - 1) | |||
| if not literals[word] then | |||
| decode_error(str, i, "invalid literal '" .. word .. "'") | |||
| end | |||
| return literal_map[word], x | |||
| end | |||
| local function parse_array(str, i) | |||
| local res = {} | |||
| local n = 1 | |||
| i = i + 1 | |||
| while 1 do | |||
| local x | |||
| i = next_char(str, i, space_chars, true) | |||
| -- Empty / end of array? | |||
| if str:sub(i, i) == "]" then | |||
| i = i + 1 | |||
| break | |||
| end | |||
| -- Read token | |||
| x, i = parse(str, i) | |||
| res[n] = x | |||
| n = n + 1 | |||
| -- Next token | |||
| i = next_char(str, i, space_chars, true) | |||
| local chr = str:sub(i, i) | |||
| i = i + 1 | |||
| if chr == "]" then break end | |||
| if chr ~= "," then decode_error(str, i, "expected ']' or ','") end | |||
| end | |||
| return res, i | |||
| end | |||
| local function parse_object(str, i) | |||
| local res = {} | |||
| i = i + 1 | |||
| while 1 do | |||
| local key, val | |||
| i = next_char(str, i, space_chars, true) | |||
| -- Empty / end of object? | |||
| if str:sub(i, i) == "}" then | |||
| i = i + 1 | |||
| break | |||
| end | |||
| -- Read key | |||
| if str:sub(i, i) ~= '"' then | |||
| decode_error(str, i, "expected string for key") | |||
| end | |||
| key, i = parse(str, i) | |||
| -- Read ':' delimiter | |||
| i = next_char(str, i, space_chars, true) | |||
| if str:sub(i, i) ~= ":" then | |||
| decode_error(str, i, "expected ':' after key") | |||
| end | |||
| i = next_char(str, i + 1, space_chars, true) | |||
| -- Read value | |||
| val, i = parse(str, i) | |||
| -- Set | |||
| res[key] = val | |||
| -- Next token | |||
| i = next_char(str, i, space_chars, true) | |||
| local chr = str:sub(i, i) | |||
| i = i + 1 | |||
| if chr == "}" then break end | |||
| if chr ~= "," then decode_error(str, i, "expected '}' or ','") end | |||
| end | |||
| return res, i | |||
| end | |||
| local char_func_map = { | |||
| [ '"' ] = parse_string, | |||
| [ "0" ] = parse_number, | |||
| [ "1" ] = parse_number, | |||
| [ "2" ] = parse_number, | |||
| [ "3" ] = parse_number, | |||
| [ "4" ] = parse_number, | |||
| [ "5" ] = parse_number, | |||
| [ "6" ] = parse_number, | |||
| [ "7" ] = parse_number, | |||
| [ "8" ] = parse_number, | |||
| [ "9" ] = parse_number, | |||
| [ "-" ] = parse_number, | |||
| [ "t" ] = parse_literal, | |||
| [ "f" ] = parse_literal, | |||
| [ "n" ] = parse_literal, | |||
| [ "[" ] = parse_array, | |||
| [ "{" ] = parse_object, | |||
| } | |||
| parse = function(str, idx) | |||
| local chr = str:sub(idx, idx) | |||
| local f = char_func_map[chr] | |||
| if f then | |||
| return f(str, idx) | |||
| end | |||
| decode_error(str, idx, "unexpected character '" .. chr .. "'") | |||
| end | |||
| function json.decode(str) | |||
| if type(str) ~= "string" then | |||
| error("expected argument of type string, got " .. type(str)) | |||
| end | |||
| local res, idx = parse(str, next_char(str, 1, space_chars, true)) | |||
| idx = next_char(str, idx, space_chars, true) | |||
| if idx <= #str then | |||
| decode_error(str, idx, "trailing garbage") | |||
| end | |||
| return res | |||
| end | |||
| return json | |||
| )" | |||
| @@ -0,0 +1,129 @@ | |||
| R"( | |||
| ------------------------------------------------------------------ | |||
| -- | |||
| -- Author: Alexey Melnichuk <alexeymelnichuck@gmail.com> | |||
| -- | |||
| -- Copyright (C) 2016 Alexey Melnichuk <alexeymelnichuck@gmail.com> | |||
| -- | |||
| -- Licensed according to the included 'LICENSE' document | |||
| -- | |||
| -- This file is part of lua-split library. | |||
| -- | |||
| ------------------------------------------------------------------ | |||
| --- | |||
| -- @usage | |||
| -- split = require "split" | |||
| -- lines = split(str, '\r?\n') | |||
| -- key, val = split.first(str, '=', true) | |||
| -- a,b,c,d = split.unpack(str, ':', true) | |||
| local unpack = unpack or table.unpack | |||
| local function is_match_empty(pat, plain) | |||
| return not not string.find('', pat, nil, plain) | |||
| end | |||
| local function split(str, sep, plain) | |||
| local b, res = 0, {} | |||
| sep = sep or '%s+' | |||
| assert(type(sep) == 'string') | |||
| assert(type(str) == 'string') | |||
| if #sep == 0 then | |||
| for i = 1, #str do | |||
| res[#res + 1] = string.sub(str, i, i) | |||
| end | |||
| return res | |||
| end | |||
| assert(not is_match_empty(sep, plain), 'delimiter can not match empty string') | |||
| while b <= #str do | |||
| local e, e2 = string.find(str, sep, b, plain) | |||
| if e then | |||
| res[#res + 1] = string.sub(str, b, e-1) | |||
| b = e2 + 1 | |||
| if b > #str then res[#res + 1] = "" end | |||
| else | |||
| res[#res + 1] = string.sub(str, b) | |||
| break | |||
| end | |||
| end | |||
| return res | |||
| end | |||
| local function split_iter(str, sep, plain) | |||
| sep = sep or '%s+' | |||
| assert(type(sep) == 'string') | |||
| assert(type(str) == 'string') | |||
| if #sep == 0 then | |||
| local i = 0 | |||
| return function() | |||
| i = i + 1 | |||
| if i > #str then return end | |||
| return (string.sub(str, i, i)) | |||
| end | |||
| end | |||
| assert(not is_match_empty(sep, plain), 'delimiter can not match empty string') | |||
| local b, eol = 0 | |||
| return function() | |||
| if b > #str then | |||
| if eol then | |||
| eol = nil | |||
| return "" | |||
| end | |||
| return | |||
| end | |||
| local e, e2 = string.find(str, sep, b, plain) | |||
| if e then | |||
| local s = string.sub(str, b, e-1) | |||
| b = e2 + 1 | |||
| if b > #str then eol = true end | |||
| return s | |||
| end | |||
| local s = string.sub(str, b) | |||
| b = #str + 1 | |||
| return s | |||
| end | |||
| end | |||
| local function usplit(...) return unpack(split(...)) end | |||
| local function split_first(str, sep, plain) | |||
| sep = sep or '%s+' | |||
| assert(type(sep) == 'string') | |||
| assert(type(str) == 'string') | |||
| if #sep == 0 then | |||
| return string.sub(str, 1, 1), string.sub(str, 2) | |||
| end | |||
| assert(not is_match_empty(sep, plain), 'delimiter can not match empty string') | |||
| local e, e2 = string.find(str, sep, nil, plain) | |||
| if e then | |||
| return string.sub(str, 1, e - 1), string.sub(str, e2 + 1) | |||
| end | |||
| return str | |||
| end | |||
| return setmetatable({ | |||
| split = split; | |||
| unpack = usplit; | |||
| first = split_first; | |||
| each = split_iter; | |||
| },{ | |||
| __call = function(_, ...) | |||
| return split(...) | |||
| end | |||
| }) | |||
| )" | |||