// dllmain.cpp : Defines the entry point for the DLL application. #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include #include #include #include #include #include #include // Link with ws2_32.lib #pragma comment(lib, "Ws2_32.lib") #include "F:/Programmieren/C++/json.hpp" using json = nlohmann::json; #include "include/easywsclient.hpp" #include "include/easywsclient.cpp" #include "include/MinHook.h" #ifdef __clang__ #pragma comment(lib, "lib/libMinHook-MD.x64.Clang.lib") #else #pragma comment(lib, "lib/libMinHook-MD.x64.lib") #endif //#include "F:/Programmieren/C++/myhelpers/xorstr.h" #define JM_XORSTR_DISABLE_AVX_INTRINSICS 1 #include "F:/Programmieren/C++/xorstr-master/include/xorstr.hpp" #include "F:/Programmieren/C++/myhelpers/SuspendResume.hpp" #include "include/patternscan.hpp" // #include "F:/Programmieren/C++/myhelpers/DebugHelper.hpp" // //#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 "BL3Lua.h" #include "LuaUtility.h" #include "Patterns.h" #include "spdlog/spdlog.h" #include "spdlog/sinks/basic_file_sink.h" #pragma comment(lib, "lib/spdlog.lib") using namespace SDK; std::string proxyURLA = "https://127.0.0.1:"; std::string proxyPort = "9999"; //static bool alreadyRunning = false; static bool gObjInit; static bool gNameInit; static bool wantsExit; static bool inCustomOptionsMenu; //CRITICAL_SECTION critsec; BL3Lua *luamgr = NULL; sol::environment* nonScriptEnv; using easywsclient::WebSocket; WebSocket::pointer ws = NULL; WebSocket::pointer iws = NULL; bool disconnected = false; bool idisconnected = false; spdlog::logger* Logger; struct UIData { public: std::string DisplayName; EOptionItemType UIElementType; }; struct UITitle : UIData { public: }; struct UIButton : UIData { public: std::string DescriptionTitle; std::string DescriptionText; sol::function OnChangedOrClicked; lua_State* state; }; struct UISlider : UIData { std::string DescriptionTitle; std::string DescriptionText; sol::function OnChangedOrClicked; float Value; float Min; float Max; float Step; bool bIsInt; lua_State* state; }; struct UISpinner : UIData { std::string DescriptionTitle; std::string DescriptionText; sol::function OnChangedOrClicked; int Index; sol::table Options; lua_State* state; }; struct UIBoolSpinner : UIData { std::string DescriptionTitle; std::string DescriptionText; sol::function OnChangedOrClicked; bool Value; std::string OnText; std::string OffText; lua_State* state; }; struct UIDropdown : UIData { std::string DescriptionTitle; std::string DescriptionText; sol::function OnChangedOrClicked; int Index; sol::table Options; lua_State* state; }; struct UIControl : UIData { std::string DescriptionTitle; std::string DescriptionText; sol::function OnChangedOrClicked; lua_State* state; }; struct MenuToCreate { lua_State* s; std::string ButtonText; sol::function OnClick; sol::function BuildUI; sol::function ConditionToShow; MenuToCreate() { s = NULL; ButtonText = ""; OnClick = sol::lua_nil; BuildUI = sol::lua_nil; ConditionToShow = sol::lua_nil; } }; static UFunction* onGraphicsClickedFunc = NULL; UGbxGFxButton* lastPressedButton = NULL; UGbxGFxButton* bLuaMenuBtn = NULL; std::unordered_map> createdMenuItems; std::unordered_map uiData; std::stack myMenuStack; MenuToCreate* bluaMenu = new MenuToCreate; std::vector menusToCreate; sol::table b3hmTable; void WebSocketClientThread() { INT rc; WSADATA wsaData; rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if (rc) { printf("WSAStartup Failed.\n"); return; } EnterCriticalSection(&luamgr->luaCritSec); b3hmTable.set_function("Send", [](const std::string& message) {if (ws) ws->send(message); }); LeaveCriticalSection(&luamgr->luaCritSec); while (true) { ws = WebSocket::from_url("ws://localhost:9998/ws", "",true); if (!ws) continue; while (ws->getReadyState() != easywsclient::WebSocket::OPEN) { Sleep(5); } EnterCriticalSection(&luamgr->luaCritSec); luamgr->lua->set("websocket", std::ref(ws)); LeaveCriticalSection(&luamgr->luaCritSec); disconnected = false; while (ws->getReadyState() != WebSocket::CLOSED) { ws->poll(); ws->dispatch([&](const std::string &msg) { json j = json::from_msgpack(msg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); auto output = std::string(bindata.begin(), bindata.end()); json fin; fin["EventName"] = j["EventName"]; fin["Content"] = output; fin["Error"] = j["Error"]; if (luamgr) { luamgr->RunCallbacks("OnSocketMessage", sol::make_object(*luamgr->lua, fin.dump())); } }); } EnterCriticalSection(&luamgr->luaCritSec); luamgr->lua->set("websocket", sol::nil); LeaveCriticalSection(&luamgr->luaCritSec); disconnected = true; delete ws; ws = NULL; } } void iWebSocketClientThread() { INT rc; WSADATA wsaData; rc = WSAStartup(MAKEWORD(2, 2), &wsaData); if (rc) { printf("WSAStartup Failed.\n"); return; } EnterCriticalSection(&luamgr->luaCritSec); /*luamgr->lua->new_usertype( "ImmediateWebSocket", sol::no_constructor,*/ b3hmTable.set_function("Connected", []() {return iws != NULL; }); b3hmTable.set_function("SendAndReceive", /*"SendData", */[](/*WebSocket::pointer pSocket,*/sol::this_state s, const std::string& msg, const std::string& eventToReceive = "") { if (!iws) return sol::make_object(s.L, sol::lua_nil); if (iws && iws->getReadyState() != WebSocket::CLOSED) iws->send(msg); while (iws && iws->getReadyState() != WebSocket::CLOSED) { iws->poll(); std::string response; iws->dispatch([&](const std::string& incMsg) { try { json j = json::from_msgpack(incMsg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); auto output = std::string(bindata.begin(), bindata.end()); json fin; fin["EventName"] = j["EventName"]; fin["Content"] = output; fin["Error"] = j["Error"]; if (eventToReceive.size() > 0 && eventName == eventToReceive) response = fin.dump(); } catch (...) {} }); if (response.size() > 0) return sol::make_object(s.L, response); }}); /*});*/ LeaveCriticalSection(&luamgr->luaCritSec); while (true) { iws = WebSocket::from_url("ws://localhost:9998/ws", "", false); if (!iws || !ws) continue; while (iws->getReadyState() != easywsclient::WebSocket::OPEN) { Sleep(5); } EnterCriticalSection(&luamgr->luaCritSec); //luamgr->lua->set("iwebsocket", std::ref(iws)); //luamgr->lua->set("iwebsocket", [&]() {return iws; }); LeaveCriticalSection(&luamgr->luaCritSec); idisconnected = false; while (ws && ws->getReadyState() != WebSocket::CLOSED) { /*iws->poll(-1); iws->dispatch([&](const std::string& msg) { json j = json::from_msgpack(msg); auto eventName = j["EventName"]; auto content = j["Content"]; auto bindata = content.get_binary(); auto output = std::string(bindata.begin(), bindata.end()); json fin; fin["EventName"] = j["EventName"]; fin["Content"] = output; fin["Error"] = j["Error"]; if (luamgr) { luamgr->RunCallbacks("OnSocketMessage", sol::make_object(*luamgr->lua, fin.dump())); } });*/ Sleep(10); } EnterCriticalSection(&luamgr->luaCritSec); luamgr->lua->set("iwebsocket", sol::nil); LeaveCriticalSection(&luamgr->luaCritSec); idisconnected = true; delete iws; iws = NULL; } } void callAtExit() { wantsExit = true; if (!disconnected) { if (ws) ws->close(); } if (!idisconnected) { if (iws) iws->close(); } MH_DisableHook(MH_ALL_HOOKS); MH_Uninitialize(); if (luamgr && luamgr->lua) { b3hmTable.clear(); b3hmTable = sol::lua_nil; lua_close(*luamgr->lua); } } static UConsole *console = NULL; void ConsoleSetup() { while (!*GEngine) Sleep(20); if (*GEngine && !console) { UEngine *eng = *GEngine; UInputSettings *settings = NULL; FName key = FName("F6"); static FKey consoleKey = {0}; consoleKey.KeyName = key; while (!settings) settings = UObject::FindObject("InputSettings Engine.Default__InputSettings"); UInputSettings *staticSettings = settings->GetInputSettings(); staticSettings->ConsoleKeys.Data = nullptr; staticSettings->ConsoleKeys.Count = 0; staticSettings->ConsoleKeys.Add(consoleKey); while (!eng->GameViewport) { Sleep(20); } if (eng && eng->GameViewport && eng->GameViewport->ViewportConsole) { console = eng->GameViewport->ViewportConsole; } else { UConsole *defaultCon = UObject::FindObject("Console Engine.Default__Console"); console = reinterpret_cast(StaticConstructObject(defaultCon->Class, defaultCon->Outer, FName("UConsole"), EObjectFlags(0))); } while (true) { try { if (eng->GameViewport && eng->GameViewport->World && eng->GameViewport->World->OwningGameInstance && eng->GameViewport->World->OwningGameInstance->LocalPlayers.Num() > 0) { console->ConsoleTargetPlayer = eng->GameViewport->World->OwningGameInstance->LocalPlayers[0]; eng->GameViewport->ViewportConsole = console; break; } } catch (...) { } Sleep(10); } } } void AddConsoleKey(const std::string &keyName) { static UInputSettings *settings = NULL; FName key = FName(keyName); FKey consoleKey = {0}; consoleKey.KeyName = key; while (!settings) settings = UObject::FindObject("InputSettings Engine.Default__InputSettings"); UInputSettings *staticSettings = settings->GetInputSettings(); staticSettings->ConsoleKeys.Add(consoleKey); staticSettings->ConsoleKeys.Count++; } void SetConsoleKey(const std::string &keyName) { static UInputSettings *settings = NULL; FName key = FName(keyName); FKey consoleKey = {0}; consoleKey.KeyName = key; while (!settings) settings = UObject::FindObject("InputSettings Engine.Default__InputSettings"); if (settings && settings->IsValidLowLevel()) { UInputSettings *staticSettings = settings->GetInputSettings(); staticSettings->ConsoleKeys.Data = nullptr; staticSettings->ConsoleKeys.Count = 0; staticSettings->ConsoleKeys.Add(consoleKey); } } static UOakCheatManager *cheatManager = NULL; void CreateCheatManager() { AOakPlayerController* pc = UObject::GetPlayerController(); while (!pc) { pc = UObject::GetPlayerController(); Sleep(20); } if (!pc->CheatManager) { pc->CheatManager = static_cast(StaticConstructObject(pc->CheatClass, pc, FName("UOakCheatManager"))); pc->CheatManager->ReceiveInitCheatManager(); } if (pc->CheatManager) { EnterCriticalSection(&luamgr->luaCritSec); UWorld* world = UObject::GetCurrentWorld(); while (!world){ world = UObject::GetCurrentWorld(); Sleep(20); } luamgr->lua->set_function("TutorialMessage", []() {((UOakCheatManager*)UObject::GetPlayerController()->CheatManager)->TestTutorialWidget(); }); luamgr->lua->set_function("DumpSave2Json", []() {((UOakCheatManager*)UObject::GetPlayerController()->CheatManager)->DumpSaveToJson(); }); LeaveCriticalSection(&luamgr->luaCritSec); } } sol::object GetParamData(lua_State *s, UProperty *property, void *params) { int32_t currentOffset = property->Offset_Internal; if (property->IsA(UObjectProperty::StaticClass())) { sol::table objectData(s, sol::create); UProperty *current = static_cast(property->Next); if (!current) { return sol::make_object(s, reinterpret_cast((uintptr_t)params + currentOffset)); } while (current && current->IsValidLowLevel()) { std::string propName = current->GetName(); if (propName.size() > 0) { objectData[propName] = GetParamData(s, current, params); } current = static_cast(current->Next); } return objectData; } else if (property->IsA(UStrProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else if (property->IsA(UIntProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else if (property->IsA(UFloatProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else if (property->IsA(USoftObjectProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } // I don't think this is working correctly else if (property->IsA(UStructProperty::StaticClass())) { std::string currentName = property->GetName(); UStructProperty *currentStructProperty = reinterpret_cast((uintptr_t)property); if (!currentStructProperty) return sol::nil; UStruct *currentStruct = currentStructProperty->Struct; sol::table objectData(s, sol::create); while (currentStruct) { for (UProperty *current = static_cast(currentStruct->Children); current; current = static_cast(current->Next)) { std::string propName = current->GetName(); if (propName.size() > 0) { objectData[propName] = GetParamData(s, current, reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } } currentStruct = currentStruct->SuperField; } return objectData; } // Implement proper reading/writing of these else if (property->IsA(UBoolProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else if (property->IsA(UNameProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else if (property->IsA(UInt64Property::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else if (property->IsA(UUInt64Property::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } //else if (property->IsA(UFunction::StaticClass())) { // return sol::make_object(s, *reinterpret_cast(property); //} else if (property->IsA(UEnumProperty::StaticClass())) { return sol::make_object(s, *reinterpret_cast((uintptr_t)params + property->Offset_Internal)); } else { char buffer[255]; sprintf_s(buffer, "\"%s\" is a property that is currently not being handled!", property->Class->GetName().c_str()); std::cout << buffer << std::endl; return sol::make_object(s, sol::nil); //throw(buffer); } return sol::nil; } sol::object GetObjectMembers(lua_State *s, UObject *obj) { if (!obj) return sol::nil; UStruct *currentClass = static_cast(obj->Class); sol::table objectData(s, sol::create); while (currentClass) { for (UProperty *current = static_cast(currentClass->Children); current; current = reinterpret_cast(current->Next)) { std::string propName = current->GetName(); if (propName.size() > 0 && !current->IsA(UFunction::StaticClass())) { objectData[propName] = GetParamData(s, current, obj); } } currentClass = currentClass->SuperField; } return objectData; } sol::object GetFuncParams(lua_State *s, UFunction *func, void *params) { uint8_t numParams = func->NumParms; uint16_t returnValueOffset = func->ReturnValueOffset; bool doesReturnAnything = returnValueOffset != 0xFFFF; sol::table paramTable(s, sol::create); UProperty *current = static_cast(func->Children); while (current && current->IsValidLowLevel()) { std::string name = current->GetName(); if (name.size() > 0) paramTable[name] = GetParamData(s, current, params); current = static_cast(current->Next); } //if (!doesReturnAnything) // return sol::nil; return paramTable; } std::string GetFuncReturnType(UFunction *func) { uint8_t numParams = func->NumParms; uint16_t returnValueOffset = func->ReturnValueOffset; bool doesReturnAnything = returnValueOffset != 0xFFFF; if (!doesReturnAnything) return ""; UProperty *current = static_cast(func->Children); while (current && current->IsValidLowLevel()) { std::string name = current->GetName(); if (name.size() > 0) if (current->PropertyFlags & EPropertyFlags::CPF_ReturnParm) return current->Class->GetName(); current = static_cast(current->Next); } } static void PrintGameConsole(const std::string &text) { if (console) { FString fStringToPrint = FString(text.c_str()); console->OutputText(&fStringToPrint); } } void hkProcessEvent(UObject *obj, UFunction *fn, void *parms) { std::string fName = fn->GetFullName(); const char* funcName = fName.c_str(); /* Possibly interesting to inject menudata Function GbxUI.GbxHintBarWidgetContainer.HintBarInitOwnerInfo Function GbxUI.GbxHintBarWidgetContainer.HintBarSetVisible Function GbxUI.GbxGFxButton.K2_HandleFocusableWidgetStateChanged Function OakGame.OakPlayerController.OnUIMenuActivated Function OakGame.OakPlayerController.ServerOnUIMenuActivated Function OakGame.GFxFrontendMenu.OnMenuStackChanged Function OakGame.MenuMapMenuFlow.OnMenuStackPush Function GbxUI.GbxHintBarWidgetContainer.HintBarClearAllHints Function GbxUI.GbxHintBarWidgetContainer.HintBarAppendHint Function GbxUI.GbxHintWidget.HintWidgetSetVisible */ //if (funcName.find("Function OakGame.GFxFrontendMenu.OnMenuStackChanged") != std::string::npos) { //if (funcName.find("Function OakGame.GFxLoadedNewsImage.OnNewsImageLoadComplete") != std::string::npos) { /*if (funcName.find("Function Engine.HUD.ReceiveDrawHUD") != std::string::npos) { }*/ /*if(strcmp(funcName, "Function Engine.Actor.ReceiveTick") != 0 && strcmp(funcName, "Function Engine.ActorComponent.ReceiveTick") != 0 && strcmp(funcName, "Function Engine.HUD.ReceiveDrawHUD") != 0 && strcmp(funcName, "Function Engine.CameraModifier.BlueprintModifyCamera") != 0 && strcmp(funcName, "Function Engine.CameraModifier.BlueprintModifyPostProcess") != 0 && strcmp(funcName, "Function Engine.GameMode.ReadyToEndMatch") != 0 && strcmp(funcName, "Function GbxCameraModes.CameraBehavior.Update") != 0 && strcmp(funcName, "Function MenuMap_P.MenuMap_P_C.HandRotate__UpdateFunc") != 0 && strcmp(funcName, "Function BP_TimeOfDay_Base.BP_TimeOfDay_Base_C.ReceiveTick") != 0 && strcmp(funcName, "Function Engine.AnimNotifyState.Received_NotifyTick") != 0 && strcmp(funcName, "Function Engine.ActorComponent.ReceiveEndPlay") != 0 && strcmp(funcName, "Function Engine.AnimInstance.BlueprintInitializeAnimation") != 0 && strcmp(funcName, "Function Engine.ActorComponent.ReceiveBeginPlay") != 0 && strcmp(funcName, "Function Engine.Actor.ReceiveBeginPlay") != 0 && strcmp(funcName, "Function Engine.AnimInstance.BlueprintPostEvaluateAnimation") != 0) std::cout << funcName << std::endl;*/ if (strcmp(funcName, "Function GbxUI.GbxGFxListItemSpinner.OnSpinnerValueUpdated") == 0) { EnterCriticalSection(&luamgr->luaCritSec); if (uiData.find(obj) != uiData.end()) { UGbxGFxListItemSpinner* current = reinterpret_cast(obj); int index = current->GetSelectionIndex(); UISpinner* spinner = static_cast(uiData[obj]); spinner->Index = index; sol::protected_function func = spinner->OnChangedOrClicked; if (func.valid()) { sol::protected_function_result result; if (spinner->UIElementType == EOptionItemType::BooleanSpinner) { UIBoolSpinner* bSp = reinterpret_cast(spinner); result = func(bSp, bSp->Value); } else { result = func(spinner, index); } if (!result.valid()) { PrintGameConsole("Failed to call spinner-callback"); sol::error err = result; PrintGameConsole(err.what()); Logger->error(err.what()); } else { LeaveCriticalSection(&luamgr->luaCritSec); // Call default handler to update UI-Value and such return oProcessEvent(obj, fn, parms); } } } LeaveCriticalSection(&luamgr->luaCritSec); } else if (strcmp(funcName, "Function GbxUI.GbxGFxListItemNumber.OnSliderUpdated") == 0) { EnterCriticalSection(&luamgr->luaCritSec); if (uiData.find(obj) != uiData.end()) { UGbxGFxListItemNumber* current = reinterpret_cast(obj); float value = current->GetCurrentValue(); UISlider* slider = static_cast(uiData[obj]); slider->Value = value; sol::protected_function func = slider->OnChangedOrClicked; if (func.valid()) { sol::protected_function_result result; if(slider->bIsInt) result = func(slider, (int64_t)value); else result = func(slider, value); if (!result.valid()) { PrintGameConsole("Failed to call slider-callback"); sol::error err = result; PrintGameConsole(err.what()); Logger->error(err.what()); } else { LeaveCriticalSection(&luamgr->luaCritSec); // Call default handler to update UI-Value and such return oProcessEvent(obj, fn, parms); } } } LeaveCriticalSection(&luamgr->luaCritSec); } else if (strcmp(funcName, "Function OakGame.GFxGraphicsOptions.OnResolutionDropDownSelectionChanged") == 0) { UGFxGraphicsOptions_OnResolutionDropDownSelectionChanged_Params* thisParams = reinterpret_cast(parms); EnterCriticalSection(&luamgr->luaCritSec); if (uiData.find(thisParams->ComboBoxItem) != uiData.end()) { UGbxGFxListItemComboBox* current = thisParams->ComboBoxItem; int index = current->GetSelectedIndex(); UIDropdown* dropdown = static_cast(uiData[thisParams->ComboBoxItem]); dropdown->Index = index; sol::protected_function func = dropdown->OnChangedOrClicked; if (func.valid()) { sol::protected_function_result result = func(dropdown, index); if (!result.valid()) { PrintGameConsole("Failed to call slider-callback"); sol::error err = result; PrintGameConsole(err.what()); Logger->error(err.what()); } } LeaveCriticalSection(&luamgr->luaCritSec); // Call default handler to update UI-Value and such return oProcessEvent(obj, fn, parms); } LeaveCriticalSection(&luamgr->luaCritSec); } else if (strcmp(funcName, "Function OakGame.GFxGraphicsOptions.OnBenchmarkRunClicked") == 0) { EnterCriticalSection(&luamgr->luaCritSec); UGFxMainAndPauseBaseMenu_OnGraphicsClicked_Params* thisParams = reinterpret_cast(parms); if (uiData.find(thisParams->PressedButton) != uiData.end()) { UIButton* btn = static_cast(uiData[thisParams->PressedButton]); sol::protected_function func = btn->OnChangedOrClicked; if (func.valid()) { sol::protected_function_result result = func(btn); if (!result.valid()) { PrintGameConsole("Failed to call button-callback"); sol::error err = result; PrintGameConsole(err.what()); Logger->error(err.what()); } else { LeaveCriticalSection(&luamgr->luaCritSec); return; } } } // This really can only be the intended "benchmark"-button else { LeaveCriticalSection(&luamgr->luaCritSec); // Call default handler to update UI-Value and such return oProcessEvent(obj, fn, parms); } } // Handle button-submenu MAIN menu else if (strcmp(funcName, "Function OakGame.GFxOakMainMenu.OnOptionsClicked") == 0) { UGFxOakMainMenu_OnOptionsClicked_Params* thisParams = static_cast(parms); if(thisParams->PressedButton == bLuaMenuBtn){ lastPressedButton = bLuaMenuBtn; inCustomOptionsMenu = true; EnterCriticalSection(&luamgr->luaCritSec); UGFxOakMainMenu* menuToUse = NULL; if (oGetMapName && oGetMapName().ToString().find("MenuMap_P") != std::string::npos) { menuToUse = mainMenu; oProcessEvent(obj, fn, parms); UGbxGFxGridScrollingList* list = menuToUse->MenuList; if (list) { menuToUse->RemoveAllItems(); for (auto& c : menusToCreate) { if (menuToUse && menuToUse->IsValidLowLevel()) { bool bShow = false; if (c.ConditionToShow.valid()) { sol::protected_function_result result = c.ConditionToShow(); if (result.valid()) bShow = result; } else { bShow = true; } if (bShow) { int newIndex = menuToUse->AddMenuItem(c.ButtonText, "", false, -1); if (menuToUse->MenuItems.Data && menuToUse->MenuItems[newIndex].MenuItem) { createdMenuItems[menuToUse->MenuItems[newIndex].MenuItem] = std::make_tuple(c.OnClick, c.BuildUI, c.s); /*if (c.BuildUI.valid()) {*/ menuToUse->MenuItems[newIndex].MenuItem->OnClicked.FunctionName = onGraphicsClickedFunc->Name; //} } } } } LeaveCriticalSection(&luamgr->luaCritSec); return; } } LeaveCriticalSection(&luamgr->luaCritSec); return; } else { lastPressedButton = thisParams->PressedButton; } } // Handle button-submenu PAUSE menu else if (strcmp(funcName, "Function OakGame.GFxPauseMenu.OnOptionsClicked") == 0) { UGFxPauseMenu_OnOptionsClicked_Params* thisParams = static_cast(parms); if (thisParams->PressedButton == bLuaMenuBtn) { lastPressedButton = bLuaMenuBtn; inCustomOptionsMenu = true; EnterCriticalSection(&luamgr->luaCritSec); UGFxPauseMenu* menuToUse = NULL; if (oGetMapName && oGetMapName().ToString().find("MenuMap_P") == std::string::npos) { menuToUse = pauseMenu; oProcessEvent(obj, fn, parms); UGbxGFxGridScrollingList* list = menuToUse->MenuList; if (list) { menuToUse->RemoveAllItems(); for (auto& c : menusToCreate) { if (menuToUse && menuToUse->IsValidLowLevel()) { bool bShow = false; if (c.ConditionToShow.valid()) { sol::protected_function_result result = c.ConditionToShow(); if (result.valid()) bShow = result; } else { bShow = true; } if (bShow) { int newIndex = menuToUse->AddMenuItem(c.ButtonText, "", false, -1); if (menuToUse->MenuItems.Data && menuToUse->MenuItems[newIndex].MenuItem) { createdMenuItems[menuToUse->MenuItems[newIndex].MenuItem] = std::make_tuple(c.OnClick, c.BuildUI, c.s); /*if (c.BuildUI.valid()) {*/ menuToUse->MenuItems[newIndex].MenuItem->OnClicked.FunctionName = onGraphicsClickedFunc->Name; //} } } } } LeaveCriticalSection(&luamgr->luaCritSec); return; } } LeaveCriticalSection(&luamgr->luaCritSec); return; } else { lastPressedButton = NULL; } } //else if (strcmp(funcName, "Function GbxUI.GbxGFxButton.K2_HandleFocusableWidgetStateChanged") == 0) { // UGbxGFxButton_K2_HandleFocusableWidgetStateChanged_Params* params = reinterpret_cast(parms); // if (!parms || !reinterpret_cast(obj)->IsFocusableWidgetStateDown(params->NewState)) // { // return oProcessEvent(obj, fn, parms); // } // EnterCriticalSection(&luamgr->luaCritSec); // for (auto& cell : createdMenuItems) { // UGbxGFxListCell* target = reinterpret_cast(cell.first); // if (target) { // if (target == obj) { // lua_State* lua = std::get<2>(cell.second); // // Check if there is a "buildUI"-function bound to this // //sol::reference current(lua, sol::ref_index(std::get<1>(cell.second).registry_index())); // sol::reference current = std::get<1>(cell.second); // if (current.valid()) { // // We don't need to actually call the "buildUI"-func in here. That's handled somewhere else // UGFxMainAndPauseBaseMenu* menuToUse = NULL; // if (oGetMapName && oGetMapName().ToString().find("MenuMap_P") != std::string::npos) { // menuToUse = mainMenu; // if (menuToUse->MenuItems.Count == 5) // createdMenuItems.clear(); // } // else { // menuToUse = pauseMenu; // if (menuToUse->MenuItems.Count == 6) // createdMenuItems.clear(); // } // if (menuToUse) { // FGbxMenuInputEvent irrelevant; // // TODO: This appears to cause the bug that randomly opens the graphics options menu // menuToUse->OnGraphicsClicked(target, irrelevant); // } // LeaveCriticalSection(&luamgr->luaCritSec); // return; // // } // // If there's no "buildUI"-function assigned to this, this is a simple click-handler // else { // //sol::reference current(lua, sol::ref_index(std::get<0>(cell.second).registry_index())); // sol::protected_function current = std::get<0>(cell.second); // if (current.valid()) { // //sol::protected_function func(lua, sol::ref_index(std::get<0>(cell.second).registry_index())); // //sol::protected_function func = std::get<0>(cell.second); // sol::protected_function_result result = current(obj, fn, parms); // if (!result.valid()) // { // sol::error err = result; // std::cout << "Error running button handler: " << err.what() << std::endl; // } // else // { // LeaveCriticalSection(&luamgr->luaCritSec); // return; // } // } // } // } // } // } // LeaveCriticalSection(&luamgr->luaCritSec); //} else if (strcmp(funcName, "Function OakGame.GFxMainAndPauseBaseMenu.OnGraphicsClicked") == 0) { UGFxMainAndPauseBaseMenu_OnGraphicsClicked_Params* thisParam = reinterpret_cast(parms); lastPressedButton = thisParam->PressedButton; EnterCriticalSection(&luamgr->luaCritSec); for (auto& cell : createdMenuItems) { UGbxGFxListCell* target = reinterpret_cast(cell.first); if (target) { if (target == lastPressedButton) { sol::reference clickHandler = std::get<0>(cell.second); if (clickHandler.valid()) { // Call click-handler if there is one sol::protected_function current = clickHandler; if (current.valid()) { sol::protected_function_result result = current(obj, fn, parms); if (!result.valid()) { sol::error err = result; std::cout << "Error running button handler: " << err.what() << std::endl; Logger->error(err.what()); } } } //Check if there is a "buildUI"-function bound to this sol::reference buildUIFunc = std::get<1>(cell.second); if (!buildUIFunc.valid()) { LeaveCriticalSection(&luamgr->luaCritSec); return; } /*for (auto& m : menusToCreate) { if (m.BuildUI.valid() && m.BuildUI == buildUIFunc) { myMenuStack.push(m); break; } }*/ } } } LeaveCriticalSection(&luamgr->luaCritSec); return oProcessEvent(obj, fn, parms); } else if (strcmp(funcName, "Function OakGame.GFxFrontendMenu.OnMenuStackChanged") == 0) { UGFxFrontendMenu_OnMenuStackChanged_Params* thisParam = reinterpret_cast(parms); UGFxMainAndPauseBaseMenu* menuToUse = NULL; if (oGetMapName && oGetMapName().ToString().find("MenuMap_P") != std::string::npos) { menuToUse = mainMenu; if (menuToUse->MenuItems.Count == 5) createdMenuItems.clear(); } else { menuToUse = pauseMenu; if (menuToUse->MenuItems.Count == 6) createdMenuItems.clear(); } // TODO: If other projects figure out or use the same approach, this will most likely fail again :( // TODO: Properly work out a solution with my own MenuStack if (menuToUse && menuToUse->MenuList && inCustomOptionsMenu && wcscmp(menuToUse->MenuList->AllCells[0].Cell->Label->TextFieldData->Text, L"VISUALS") == NULL && wcscmp(menuToUse->MenuList->AllCells[1].Cell->Label->TextFieldData->Text, L"SOUND") == NULL) { //if (menuToUse && menuToUse->MenuList && inCustomOptionsMenu && !myMenuStack.empty()) { oProcessEvent(obj, fn, parms); menuToUse->RemoveAllItems(); for (auto& c : menusToCreate) { if (menuToUse && menuToUse->IsValidLowLevel()) { bool bShow = false; if (c.ConditionToShow.valid()) { sol::protected_function_result result = c.ConditionToShow(); if (result.valid()) bShow = result; } else { bShow = true; } if (bShow) { int newIndex = menuToUse->AddMenuItem(c.ButtonText, "", false, -1); if (menuToUse->MenuItems.Data && menuToUse->MenuItems[newIndex].MenuItem) { createdMenuItems[mainMenu->MenuItems[newIndex].MenuItem] = std::make_tuple(c.OnClick, c.BuildUI, c.s); /*if (c.BuildUI.valid()) {*/ menuToUse->MenuItems[newIndex].MenuItem->OnClicked.FunctionName = onGraphicsClickedFunc->Name; //} } } } } //LeaveCriticalSection(&luamgr->luaCritSec); //myMenuStack.pop(); return; } return oProcessEvent(obj, fn, parms); } //if (strstr(funcName, "GbxGFxButton") != 0) { // std::cout << funcName << std::endl; //} //if (strstr(funcName, "MenuStack") != 0) { // std::cout << funcName << std::endl; //} //if (strstr(funcName, "OnBLuaClicked") != 0) { // std::cout << funcName << std::endl; //} //if (strcmp(funcName, "Function ScaleformUI.GFxMoviePlayer.ReceiveGFxCommand") == 0) { // std::cout << funcName << std::endl; //} if (luamgr && luamgr->lua) { EnterCriticalSection(&luamgr->luaCritSec); // TODO: Probably need to move this into a lua-function to avoid jumping into and out of lua if (luamgr->procEventHooks.find(funcName) != luamgr->procEventHooks.end()) { for (auto &hook : luamgr->procEventHooks[funcName]) { try { lua_State* lua = std::get<1>(hook); //sol::protected_function current(lua, sol::ref_index(std::get<0>(hook).registry_index())); sol::reference current = std::get<0>(hook); if (current.valid()) { /* sol::object objData = GetObjectMembers(lua, obj); sol::object paramObj = GetFuncParams(lua, fn, parms); if (!objData.valid())*/ //sol::object objData = sol::make_object(lua, obj); //if (!paramObj.valid()) //sol::object paramObj = sol::make_object(lua, parms); bool isPreHook = std::get<2>(hook); if (isPreHook) { /*sol::protected_function func(lua, sol::ref_index(std::get<0>(hook).registry_index())); if (!func.valid()) { LeaveCriticalSection(&luamgr->procEventCritSec); return oProcessEvent(obj, fn, parms); }*/ sol::protected_function_result result; //result = func(objData, fn, paramObj); sol::protected_function func = current; result = func(obj); if (!result.valid()) { sol::error err = result; std::cout << "Error running hook: " << err.what() << std::endl; Logger->error(err.what()); } else { if (result.return_count() == 1) { bool returnValue = result; if (returnValue) { LeaveCriticalSection(&luamgr->luaCritSec); return; } } //else if (result.return_count() == 3) { // /*std::tuple returnedObjects = result; // obj = std::get<0>(returnedObjects); // fn = reinterpret_cast(std::get<1>(returnedObjects)); // parms = std::get<2>(returnedObjects);*/ //} } } else { oProcessEvent(obj, fn, parms); if (fn->ReturnValueOffset == 0xFFFF) { LeaveCriticalSection(&luamgr->luaCritSec); return; } //Handle postHook to pass and return result sol::object paramObj = GetFuncParams(lua, fn, parms); std::string returnValueTypeName = GetFuncReturnType(fn); //sol::protected_function func(lua, sol::ref_index(std::get<0>(hook).registry_index())); sol::reference funcRef = std::get<0>(hook); if (funcRef.valid()) { sol::protected_function func = std::get<0>(hook); sol::protected_function_result result; result = func(obj, fn, parms); if (!result.valid()) { sol::error err = result; std::cout << "Error running hook: " << err.what() << std::endl; Logger->error(err.what()); } else { if (result.return_count() == 1) { sol::object returnValue = result; if (returnValue.valid()) { if (returnValueTypeName == "FloatProperty") { if (returnValue.is()) { (*(float*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "DoubleProperty") { if (returnValue.is()) { (*(double*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "BoolProperty") { if (returnValue.is()) { (*(bool*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "ByteProperty") { if (returnValue.is()) { (*(uint8_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "IntProperty") { if (returnValue.is()) { (*(int*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "Int8Property") { if (returnValue.is()) { (*(int8_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "Int16Property") { if (returnValue.is()) { (*(int16_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "Int64Property") { if (returnValue.is()) { (*(int64_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "UInt16Property") { if (returnValue.is()) { (*(uint32_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "UInt32Property") { if (returnValue.is()) { (*(uint32_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "UInt64Property") { if (returnValue.is()) { (*(uint64_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "UInt64Property") { if (returnValue.is()) { (*(uint64_t*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "StrProperty") { if (returnValue.is()) { (*(FString*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "TextProperty") { if (returnValue.is()) { (*(FText*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "NameProperty") { if (returnValue.is()) { (*(FName*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "VectorProperty") { if (returnValue.is()) { (*(FVector*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } else if (returnValueTypeName == "RotatorProperty") { if (returnValue.is()) { (*(FRotator*)((uintptr_t)parms + fn->ReturnValueOffset)) = returnValue.as(); } } } LeaveCriticalSection(&luamgr->luaCritSec); return; } } } } } } catch(...){} } } LeaveCriticalSection(&luamgr->luaCritSec); } return oProcessEvent(obj, fn, parms); } static bool endsWith(std::wstring str, std::wstring suffix) { return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix); } /* * Find Case Insensitive Sub String in a given substring */ static size_t findCaseInsensitive(std::string data, std::string toSearch, size_t pos = 0) { // Convert complete given String to lower case std::transform(data.begin(), data.end(), data.begin(), ::tolower); // Convert complete given Sub String to lower case std::transform(toSearch.begin(), toSearch.end(), toSearch.begin(), ::tolower); // Find sub string in given string return data.find(toSearch, pos); } static void ToggleNoclip() { static bool flyIsActive = false; AOakPlayerController *pc = UObject::GetPlayerController(); if (pc) { ACharacter *character = pc->GetAssociatedCharacter(); if (character) { if (flyIsActive) { character->CharacterMovement->bCheatFlying = 0; character->CharacterMovement->MovementMode = EMovementMode::MOVE_Walking; character->CharacterMovement->MaxFlySpeed.Value = 600.0f; character->SetActorEnableCollision(true); flyIsActive = false; PrintGameConsole("noclip off"); } else { character->CharacterMovement->bCheatFlying = 1; character->CharacterMovement->MovementMode = EMovementMode::MOVE_Flying; character->CharacterMovement->MaxFlySpeed.Value = 2000.0f; character->SetActorEnableCollision(false); flyIsActive = true; PrintGameConsole("noclip on"); } } } } static void ToggleCam() { static bool isThirdPerson = false; static FName defaultCam = FName("Default"); static FName thirdPerson = FName("ThirdPerson"); AOakPlayerController *pc = UObject::GetPlayerController(); if (pc) { if (!isThirdPerson) { pc->ClientSetCameraMode(thirdPerson); isThirdPerson = true; PrintGameConsole("Thirdperson cam activated!"); } else { pc->ClientSetCameraMode(defaultCam); isThirdPerson = false; PrintGameConsole("Firstperson cam activated!"); } } } bool hkStaticExec(UWorld *world, const wchar_t *input, FOutputDevice &outputDevice) { if (wcsncmp(input, L"cls", 3) == NULL) { console->ClearOutput(); console->SBHead = 0; system("cls"); return true; } else if (wcsncmp(input, L"noclip", 6) == NULL) { ToggleNoclip(); return true; } else if (wcsncmp(input, L"togglecam", 9) == NULL) { ToggleCam(); return true; } else if (wcsncmp(input, L"lua ", 4) == NULL) { if (wcslen(input) <= 5) return false; std::wstring data(input + 5); std::string luaData(data.begin(), data.end()); if (luamgr) luamgr->ExecuteScriptString(luaData.c_str(), true); return true; } else if (wcsncmp(input, L"luaex", 5) == NULL) { if (wcslen(input) <= 6) return false; std::wstring data(input + 6); std::string luaData(data.begin(), data.end()); if (findCaseInsensitive(luaData, "./lua/") == std::string::npos) { luaData = "./lua/" + luaData; } if (luamgr) return luamgr->ExecuteScriptFile(luaData.c_str(), true); return true; } // The returned numbers did not make any sense? // Memory usage was the same with this injected and without /*else if (wcsncmp(input, L"luamem", 6) == NULL) { sol::protected_function func = (*luamgr->lua)["PrintGameConsole"]; if (func.valid()) { char buf[150]; size_t memory = sol::total_memory_used(luamgr->lua->lua_state()); sprintf_s(buf, sizeof(buf), "%dkB (%dMB) memory in use by sol (lua).", memory, memory / 1024); func(buf); } return true; }*/ if (luamgr && luamgr->lua) { EnterCriticalSection(&luamgr->luaCritSec); for (auto &commands : luamgr->consoleCommands) { size_t prefixLength = std::get<2>(commands.second); std::wstring widenedPrefix = std::wstring(commands.first.begin(), commands.first.end()); if (!endsWith(widenedPrefix, std::wstring(L" "))) widenedPrefix.append(L" "); if (widenedPrefix.size() >= wcslen(input)) { LeaveCriticalSection(&luamgr->luaCritSec); return false; } if (wcsncmp(widenedPrefix.c_str(), input, widenedPrefix.size()) == NULL) { lua_State *lua = std::get<1>(commands.second); //sol::reference current(lua, sol::ref_index(std::get<0>(commands.second).registry_index())); sol::protected_function current = std::get<0>(commands.second); if (current.valid()) { //sol::protected_function func(lua, sol::ref_index(std::get<0>(commands.second).registry_index())); sol::protected_function_result result = current(input + prefixLength + 1); if (!result.valid()) { sol::error err = result; std::cout << "Error running console command: " << err.what() << std::endl; Logger->error(err.what()); } else { if (result.return_count() == 1) { bool returnValue = result; LeaveCriticalSection(&luamgr->luaCritSec); return returnValue; } } } } } LeaveCriticalSection(&luamgr->luaCritSec); } bool returnVal = oStaticExec(world, input, outputDevice); // This was not handled by anything. Possibly invalid, but still trying to run it as lua-code if (!returnVal) { if (luamgr) { EnterCriticalSection(&luamgr->luaCritSec); std::wstring tmp(input); std::string narrowed(tmp.begin(), tmp.end()); bool result = luamgr->ExecuteScriptString(narrowed.c_str()); LeaveCriticalSection(&luamgr->luaCritSec); return result; } } return returnVal; } void hkCallFunction(UObject* thisZ, FFrame& frame, void* paramResult, UFunction* func) { const char* funcName = func->GetFullNameC(); if (strstr(funcName, "BLua") != 0) { std::cout << "Tried to call a func containing \"BLua\"" << std::endl; } if (thisZ == bLuaMenuBtn) { std::cout << "BLuaMenuBtn called: " << funcName << std::endl; } if (!oCallFunc) return; return oCallFunc(thisZ, frame, paramResult, func); } struct FUniqueNetId { char unknown[0x18]; }; typedef void(__fastcall* tDoSparkAuth)(void* FOakPlayerManager, const TSharedRef& something, void* something2); tDoSparkAuth oDoSparkAuth = NULL; void* oakPlayerManager = NULL; TSharedRef* Something = new TSharedRef; void* Something2 = NULL; void hkDoSparkAuth(void* FOakPlayerManager, const TSharedRef& something, void* something2) { oakPlayerManager = FOakPlayerManager; //Something = something; something2 = something2; memcpy(Something, &something, sizeof(TSharedRef)); return oDoSparkAuth(FOakPlayerManager, something, something2); } class FOakStartupProcess { public: char pad_0000[60]; //0x0000 uint8_t StepToPerform; //0x003C bool bInitDone; //0x003D char pad_003E[162]; //0x003E }; //Size: 0x00E0 static_assert(sizeof(FOakStartupProcess) == 0xE0); typedef void(__fastcall* tStartupProcessPerformStep)(FOakStartupProcess* startupProcess/*, const FName& seemsWrong*/); tStartupProcessPerformStep oStartupProcessPerformStep = NULL; FOakStartupProcess* oakStartupProcess = new FOakStartupProcess; //void* Something2 = NULL; void hkStartupProcessPerformStep(FOakStartupProcess* startupProcess/*, void* seemsWrong*/) { if (startupProcess->StepToPerform == 0) memcpy(oakStartupProcess, startupProcess, sizeof(FOakStartupProcess)); //oakStartupProcess = startupProcess; return oStartupProcessPerformStep(startupProcess/*, NULL*/); } void* FGbxSparkModule = NULL; typedef void* (__fastcall* tGbxSparkModuleGet)(); tGbxSparkModuleGet oGbxSparkModuleGet = NULL; struct testStruct { char unknown[0x340]; }; typedef bool (__fastcall* tFSparkInitProcessStartProcess)(testStruct*); tFSparkInitProcessStartProcess oFSparkInitProcessStartProcess = NULL; testStruct* sparkInitProcess = new testStruct; testStruct* gameSparkInitProcess = NULL; bool hkSparkInitProcessStartProcess(testStruct* thisZ) { bool result = false; gameSparkInitProcess = thisZ; if (oFSparkInitProcessStartProcess && thisZ != sparkInitProcess) { memcpy(sparkInitProcess, thisZ, sizeof(testStruct)); } result = oFSparkInitProcessStartProcess(thisZ); return result; } typedef void* (__fastcall* tFSparkInitProcessReadDiscovery)(testStruct*, bool baseInitWasDone); tFSparkInitProcessReadDiscovery oFSparkInitProcessReadDiscovery = NULL; void* hkSparkInitProcessReadDiscovery(testStruct* thisZ, bool baseInitWasDone) { void* result = NULL; if (oFSparkInitProcessReadDiscovery) result = oFSparkInitProcessReadDiscovery(thisZ, baseInitWasDone); return result; } static void* somethingNecessary = NULL; static void* somethingNecessary2 = NULL; void* hkOakGameInstanceProcessPendingMicropatches(UOakGameInstance* thisZ) { if(!somethingNecessary) somethingNecessary = *(void**)((uintptr_t)thisZ + 0x11A0); if(!somethingNecessary2) somethingNecessary2 = *(void**)((uintptr_t)thisZ + 0x11A8); //void* somethingNecessary = (void*)&thisZ->UnknownData10[0x27B]; void* result = NULL; result = oOakGameInstanceProcessPendingMicropatches(thisZ); return result; } FOakStartupProcess* test = NULL; void RefreshHotfixes() { if (oFSparkInitProcessReadDiscovery && gameSparkInitProcess){ UOakGameInstance* instance = UObject::GetGameInstance(); if (instance) { if (somethingNecessary && somethingNecessary2) { *(void**)((uintptr_t)instance + 0x11A0) = somethingNecessary; *(void**)((uintptr_t)instance + 0x11A8) = somethingNecessary2; } oFSparkInitProcessReadDiscovery(gameSparkInitProcess, false); oFSparkInitProcessReadDiscovery(gameSparkInitProcess, true); //hkOakGameInstanceProcessPendingMicropatches(instance); if (somethingNecessary && somethingNecessary2) { *(void**)((uintptr_t)instance + 0x11A0) = somethingNecessary; *(void**)((uintptr_t)instance + 0x11A8) = somethingNecessary2; } FGbxMenuInputEvent event = { 0 }; instance->OnConfirmApplyMicropatches(NULL, FName("Yes"), event); AOakGameState* state = UObject::GetGameState(); if (state) state->RefreshMicropatchSwitches(); } } /*if (oFSparkInitProcessStartProcess && sparkInitProcess) hkSparkInitProcessStartProcess(sparkInitProcess);*/ /*if (oGbxSparkModuleGet) FGbxSparkModule = oGbxSparkModuleGet();*/ /*if (oStartupProcessPerformStep && oakStartupProcess) { if (test) free(test); test = new FOakStartupProcess; memcpy(test, oakStartupProcess, sizeof(FOakStartupProcess)); test->bInitDone = true; oStartupProcessPerformStep(test); }*/ /*if (oDoSparkAuth && oakPlayerManager) { AOakPlayerController* pc = UObject::GetPlayerController(); if(pc){ FUniqueNetIdRepl id = ((AOakPlayerState*)(pc->PlayerState))->ShiftUniqueId; oDoSparkAuth(oakPlayerManager, *Something, Something2); } }*/ /*static uintptr_t doSparkAuth = PatternScan::FindSignature(NULL, FOakPlayerManager__DoSparkAuthentication.crypt_get()); while(!doSparkAuth) doSparkAuth = PatternScan::FindSignature(NULL, FOakPlayerManager__DoSparkAuthentication.crypt_get());*/ /*UOakGameInstance* gameInstance = UObject::GetGameInstance(); while(!gameInstance) gameInstance = UObject::GetGameInstance();*/ /*typedef char(__fastcall* tProcessPendingMicropatches)(UOakGameInstance*); static tProcessPendingMicropatches oProcessPendingMicropatches = (tProcessPendingMicropatches)test;*/ //char result = oProcessPendingMicropatches(gameInstance); /*typedef LRESULT(__cdecl * tRefresh)(); static tRefresh oRefresh = NULL; if (!oRefresh) { HMODULE proxyDLLHandle = GetModuleHandleA("BL3ProxySettings.dll"); if (proxyDLLHandle) { FARPROC address = GetProcAddress(proxyDLLHandle, "RefreshHotfixes"); if (address) { oRefresh = (tRefresh)address; } } } if (oRefresh) oRefresh();*/ } HMODULE thisDLL; static HMODULE forRefCount; void FindPatternsForTypedefs() { while (!oGetTransientPackage) { uintptr_t patternAddress = PatternScan::FindSignature(NULL, getTransientPackagePattern.crypt_get()); if (patternAddress) { patternAddress -= 72 + 5; int32_t offset = *(int32_t *)(patternAddress + 1); if (offset) { oGetTransientPackage = (tGetTransientPackage)(patternAddress + offset + 5); } } } while (!oMalloc) oMalloc = (tMalloc)PatternScan::FindSignature(NULL, mallocPattern.crypt_get()); while (!oRealloc) oRealloc = (tRealloc)PatternScan::FindSignature(NULL, reallocPattern.crypt_get()); while (!oFNameCtor) oFNameCtor = (tFNameCtor)PatternScan::FindSignature(NULL, fnamectorPattern.crypt_get()); while (!oFTextFromString) oFTextFromString = (tFtextFromString)PatternScan::FindSignature(NULL, ftextfromstringPattern.crypt_get()); while (!oGetWorldFromContextObject) oGetWorldFromContextObject = (tGetWorldFromContextObject)PatternScan::FindSignature(NULL, getWorldFromContextObjectPattern.crypt_get()); while (!oIsValidLowLevel) oIsValidLowLevel = (tIsValidLowLevel)PatternScan::FindSignature(NULL, isValidLowLevelPattern.crypt_get()); while (!oStaticConstructObject) oStaticConstructObject = (tStaticConstructObject)PatternScan::FindSignature(NULL, staticConstructObjectPattern.crypt_get()); while (!oStaticDuplicateObject) oStaticDuplicateObject = (tStaticDuplicateObject)PatternScan::FindSignature(NULL, staticDuplicateObjectPattern.crypt_get()); /*while (!oNewObject) oNewObject = (tNewObject)PatternScan::FindSignature(NULL, newObjectPattern.crypt_get());*/ while (!oGetWorld) oGetWorld = (tGetWorld)PatternScan::FindSignature(NULL, getWorldPattern.crypt_get()); while (!oSpawnActor) oSpawnActor = (tSpawnActor)PatternScan::FindSignature(NULL, spawnActorPattern.crypt_get()); while (!oGetMapName) oGetMapName = (tGetMapName)PatternScan::FindSignature(NULL, getMapNamePattern.crypt_get()); while (!oFuncInvoke) oFuncInvoke = (tFuncInvoke)PatternScan::FindSignature(NULL, functionInvokePattern.crypt_get()); while (!oCallFunc) { uintptr_t patternAddress = PatternScan::FindSignature(NULL, callFuncPattern.crypt_get()); if (patternAddress) { patternAddress += 100; int32_t offset = *(int32_t *)(patternAddress + 1); if (offset) { oCallFunc = (tCallFunc)(patternAddress + offset + 5); } } } while (!oStaticExec) { uintptr_t patternAddress = PatternScan::FindSignature(NULL, staticExecPattern.crypt_get()); if (patternAddress) { patternAddress += 102; int32_t offset = *(int32_t *)(patternAddress + 1); if (offset) { oStaticExec = (tStaticExec)(patternAddress + offset + 5); } } } while (!oGetGlobalLogSingleton) oGetGlobalLogSingleton = (tGetGlobalLogSingleton)PatternScan::FindSignature(NULL, getGlobalLogSingletonPattern.crypt_get()); while (!oOutputDeviceShow) oOutputDeviceShow = (tOutputDeviceShow)PatternScan::FindSignature(NULL, consoleOutputDeviceShowPattern.crypt_get()); while (!oAddOutputDevice) oAddOutputDevice = (tAddOutputDevice)PatternScan::FindSignature(NULL, addOutputDevicePattern.crypt_get()); while (!oCreateConsoleOutputDevice) oCreateConsoleOutputDevice = (tCreateConsoleOutputDevice)PatternScan::FindSignature(NULL, createConsoleOutputDevice.crypt_get()); while (!oConsoleOutputText) oConsoleOutputText = (tConsoleOutputText)PatternScan::FindSignature(NULL, consoleOutputTextPattern.crypt_get()); while (!oConsoleClearOutput) oConsoleClearOutput = (tConsoleClearOutput)PatternScan::FindSignature(NULL, consoleClearOutputPattern.crypt_get()); while (!oAddToViewport) oAddToViewport = (tAddToViewport)PatternScan::FindSignature(NULL, addToViewportPattern.crypt_get()); while (!oStaticFindObject) oStaticFindObject = (tStaticFindObject)PatternScan::FindSignature(NULL, staticFindObjectPattern.crypt_get()); while (!oMainAndPauseMenuAddMenuItem) oMainAndPauseMenuAddMenuItem = (tMainAndPauseMenuAddMenuItem)PatternScan::FindSignature(NULL, mainAndPauseMenuAddMenuItemPattern.crypt_get()); while (!oMainAndPauseMenuRemoveAllItems) oMainAndPauseMenuRemoveAllItems = (tMainAndPauseMenuRemoveAllItems)PatternScan::FindSignature(NULL, mainAndPauseMenuRemoveAllItemsPattern.crypt_get()); while (!oMainAndPauseMenuStartMenuTransition) oMainAndPauseMenuStartMenuTransition = (tMainAndPauseMenuStartMenuTransition)PatternScan::FindSignature(NULL, mainAndPauseMenuStartMenuTransitionPattern.crypt_get()); while (!oGridScrollingListInsertListItem) oGridScrollingListInsertListItem = (tGridScrollingListInsertListItem)PatternScan::FindSignature(NULL, scrollingListInsertListItemPattern.crypt_get()); while (!oListItemNumberInitializeItem) oListItemNumberInitializeItem = (tListItemNumberInitializeItem)PatternScan::FindSignature(NULL, listItemNumberInitializeItemPattern.crypt_get()); while (!oOptionBaseCreateContentPanel) oOptionBaseCreateContentPanel = (tOptionBaseCreateContentPanel)PatternScan::FindSignature(NULL, optionBaseCreateContentPanelPattern.crypt_get()); while (!oOptionBaseCreateContentPanelItem) oOptionBaseCreateContentPanelItem = (tOptionBaseCreateContentPanelItem)PatternScan::FindSignature(NULL, optionBaseCreateContentPanelItemPattern.crypt_get()); while (!oOptionBaseSetupSpinnerItem) oOptionBaseSetupSpinnerItem = (tOptionBaseSetupSpinnerItem)PatternScan::FindSignature(NULL, optionBaseSetupSpinnerItemPattern.crypt_get()); while (!oOptionBaseSetupSpinnerItemAsBoolean) oOptionBaseSetupSpinnerItemAsBoolean = (tOptionBaseSetupSpinnerItemAsBoolean)PatternScan::FindSignature(NULL, optionBaseSetupSpinnerItemAsBooleanPattern.crypt_get()); while (!oOptionBaseSetupSpinnerItemWithText) oOptionBaseSetupSpinnerItemWithText = (tOptionBaseSetupSpinnerItemWithText)PatternScan::FindSignature(NULL, optionBaseSetupSpinnerItemWithTextPattern.crypt_get()); while (!oOptionBaseSetupButtonItem) oOptionBaseSetupButtonItem = (tOptionBaseSetupButtonItem)PatternScan::FindSignature(NULL, optionBaseSetupButtonItemPattern.crypt_get()); while (!oOptionBaseSetupTitleItem) oOptionBaseSetupTitleItem = (tOptionBaseSetupTitleItem)PatternScan::FindSignature(NULL, optionBaseSetupTitleItemPattern.crypt_get()); while (!oOptionBaseSetupSliderItem) oOptionBaseSetupSliderItem = (tOptionBaseSetupSliderItem)PatternScan::FindSignature(NULL, optionBaseSetupSliderItemPattern.crypt_get()); while (!oOptionBaseSetupDropdownListItem) oOptionBaseSetupDropdownListItem = (tOptionBaseSetupDropdownListItem)PatternScan::FindSignature(NULL, optionBaseSetupDropdownListItemPattern.crypt_get()); while (!oOptionBaseSetupControlsItem) oOptionBaseSetupControlsItem = (tOptionBaseSetupControlsItem)PatternScan::FindSignature(NULL, optionBaseSetupControlsItemPattern.crypt_get()); while (!oGFxOptionsMenuLoadBaseOptionsMenu) oGFxOptionsMenuLoadBaseOptionsMenu = (tGFxOptionsMenuLoadBaseOptionsMenu)PatternScan::FindSignature(NULL, optionBaseMenuLoadBaseOptionsMenuPattern.crypt_get()); while (!oGFxOptionsMenuCreateOptionPanel) oGFxOptionsMenuCreateOptionPanel = (tGFxOptionsMenuCreateOptionPanel)PatternScan::FindSignature(NULL, gfxOptionsMenuCreateOptionPanelPattern.crypt_get()); while (!oGFxOptionsMenuOnGFxMenuIsInitedAndStartedBegin) oGFxOptionsMenuOnGFxMenuIsInitedAndStartedBegin = (tGFxOptionsMenuOnGFxMenuIsInitedAndStartedBegin)PatternScan::FindSignature(NULL, gfxOptionsMenuOnGFxMenuIsInitedAndStartedBeginPattern.crypt_get()); while (!oListItemSpinnerSetDefaultValue) oListItemSpinnerSetDefaultValue = (tListItemSpinnerSetDefaultValue)PatternScan::FindSignature(NULL, listItemSpinnerSetDefaultValuePattern.crypt_get()); while (!oListItemNumberGetCurrentValue) { uintptr_t patternAddress = PatternScan::FindSignature(NULL, listItemNumberGetCurrentValuePattern.crypt_get()); if (patternAddress) { patternAddress += 41; int32_t offset = *(int32_t*)(patternAddress + 1); if (offset) { oListItemNumberGetCurrentValue = (tListItemNumberGetCurrentValue)(patternAddress + offset + 5); } } } while (!oListItemNumberSetDefaultValue) oListItemNumberSetDefaultValue = (tListItemNumberSetDefaultValue)PatternScan::FindSignature(NULL, listItemNumberSetDefaultValuePattern.crypt_get()); while (!oListItemComboBoxGetSelectedIndex) oListItemComboBoxGetSelectedIndex = (tListItemComboBoxGetSelectedIndex)PatternScan::FindSignature(NULL, listItemComboBoxGetSelectedIndexPattern.crypt_get()); while (!oListItemComboBoxSetDefaultValue) oListItemComboBoxSetDefaultValue = (tListItemComboBoxSetDefaultValue)PatternScan::FindSignature(NULL, listItemComboBoxSetDefaultValuePattern.crypt_get()); while (!oListItemSpinnerGetSelectionIndex) oListItemSpinnerGetSelectionIndex = (tListItemSpinnerGetSelectionIndex)PatternScan::FindSignature(NULL, listItemSpinnerGetCurrentSelectionIndexPattern.crypt_get()); while (!oGbxSparkModuleGet) oGbxSparkModuleGet = (tGbxSparkModuleGet)PatternScan::FindSignature(NULL, FGbxSparkModuleGetPattern.crypt_get()); while (!oFSparkInitProcessStartProcess) oFSparkInitProcessStartProcess = (tFSparkInitProcessStartProcess)PatternScan::FindSignature(NULL, FSparkInitProcessStartProcessPattern.crypt_get()); while (!oFSparkInitProcessReadDiscovery) oFSparkInitProcessReadDiscovery = (tFSparkInitProcessReadDiscovery)PatternScan::FindSignature(NULL, FSparkInitProcessReadDiscoveryPattern.crypt_get()); while (!oOakGameInstanceProcessPendingMicropatches) oOakGameInstanceProcessPendingMicropatches = (tOakGameInstanceProcessPendingMicropatches)PatternScan::FindSignature(NULL, oakGameInstanceProcessPendingMicropatchesPattern.crypt_get()); while (!oOakGameStateRefreshMicropatchSwitches) oOakGameStateRefreshMicropatchSwitches = (tOakGameStateRefreshMicropatchSwitches)PatternScan::FindSignature(NULL, oakGameStateRefreshMicropatchSwitchesPattern.crypt_get()); /*while (!oDumpObjectToString) oDumpObjectToString = (tDumpObjectToString)PatternScan::FindSignature(NULL, dumpObjectToStringPattern.crypt_get());*/ } static FWindowsConsoleOutputDevice *myConsoleOutputDevice; static AOakPlayerController *Test(UOakDeveloperPerks *thisz) { return UObject::GetPlayerController(); } void hkAddToViewport(UUserWidget *thisZ, int32_t ZOrder) { std::cout << thisZ->GetFullName() << std::endl; return oAddToViewport(thisZ, ZOrder); } typedef void(__fastcall *tRegisterFunction)(UClass *pClass, const char *funcName, void *pFunc); tRegisterFunction oRegisterFunction = NULL; // // Blueprint VM intrinsic return value declaration. // #define RESULT_PARAM Z_Param__Result #define RESULT_DECL void *const RESULT_PARAM /** The type of a native function callable by script */ typedef void (*FNativeFuncPtr)(UObject *Context, FFrame &TheStack, RESULT_DECL); // This class is deliberately simple (i.e. POD) to keep generated code size down. struct FNameNativePtrPair { const char *NameUTF8; FNativeFuncPtr Pointer; }; typedef void(__fastcall *tRegisterFunctionOther)(UClass *pClass, const FNameNativePtrPair *InArray, int32_t NumFunctions); tRegisterFunctionOther oRegisterFunctionOther = NULL; void hkRegisterFunction(UClass *pClass, const char *funcName, void *pFunc) { char buffer[1024]; sprintf_s(buffer, sizeof(buffer), "Function \"%s\" is at %X", funcName, (uintptr_t)pFunc); std::cout << buffer << std::endl; return oRegisterFunction(pClass, funcName, pFunc); } void hkRegisterFunctionOther(UClass *pClass, const FNameNativePtrPair *InArray, int32_t NumFunctions) { //char buffer[1024]; uintptr_t startArray = (uintptr_t)InArray; int32_t oldNumFunctions = NumFunctions; /*for (; NumFunctions; ++InArray, --NumFunctions) { uintptr_t address = (uintptr_t)InArray->Pointer; sprintf_s(buffer, sizeof(buffer), "Function %s is at 0x%" PRIx64"", InArray->NameUTF8, address); std::cout << buffer << std::endl; }*/ return oRegisterFunctionOther(pClass, reinterpret_cast(startArray), oldNumFunctions); } /*const FLinkerInstancingContext**/ typedef UObject *(__fastcall *tStaticLoadObject)(UClass *pClass, UObject *pObj, const wchar_t *pName, const wchar_t *pFileName, uint32_t LoadFlags, UPackageMap *Sandbox, bool bAllowObjectReconciliation/*, void *InstancingContext*/); tStaticLoadObject oStaticLoadObject = NULL; UObject *hkStaticLoadObject(UClass *pClass, UObject *pOuter, const wchar_t *pName, const wchar_t *pFileName, uint32_t LoadFlags, UPackageMap *Sandbox, bool bAllowObjectReconciliation/*, void *InstancingContext*/) { //std::wcout << L"******* StaticLoadObject *******" << std::endl; //std::wcout << L"Class: " << pClass->GetName().c_str() << std::endl; //if (pOuter) // std::wcout << L"Outer: " << pOuter->GetName().c_str() << std::endl; //std::wcout << L"Name: " << pName << std::endl; //if (pFileName) // std::wcout << L"FileName: " << pFileName << std::endl; //std::wcout << std::endl; //if (wcsstr(pName, L"/Game/UI/MainMenu/MainMenu.MainMenu") != NULL) //{ // USwfMovie *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // if (result && result->RawData.Count > 0) // { // std::ofstream fout; // fout.open("mainmenu.swf", std::ios::binary | std::ios::out); // fout.write((char *)result->RawData.Data, result->RawData.Max); // fout.close(); // } // return result; //} //else if (wcsstr(pName, L"/Game/UI/FrontEndContainers/FrontEndContainer.FrontEndContainer") != NULL) //{ // USwfMovie *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // if (result && result->RawData.Count > 0) // { // std::ofstream fout; // fout.open("frontendContainer.swf", std::ios::binary | std::ios::out); // fout.write((char *)result->RawData.Data, result->RawData.Max); // fout.close(); // } // return result; //} //else if (wcsstr(pName, L"/Game/UI/_Shared/Fonts/fonts_en.fonts_en") != NULL) //{ // USwfMovie *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // if (result && result->RawData.Count > 0) // { // std::ofstream fout; // fout.open("../_Shared/Fonts/fonts_en.swf", std::ios::binary | std::ios::out); // fout.write((char *)result->RawData.Data, result->RawData.Max); // fout.close(); // } // return result; //} //else if (wcsstr(pName, L"/Game/UI/HintBar/HintBar.HintBar") != NULL) //{ // USwfMovie *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // if (result && result->RawData.Count > 0) // { // std::ofstream fout; // fout.open("../HintBar/HintBar.swf", std::ios::binary | std::ios::out); // fout.write((char *)result->RawData.Data, result->RawData.Max); // fout.close(); // } // return result; //} //else if (wcsstr(pName, L"/Game/UI/DialogWindow/DialogWindow.DialogWindow") != NULL) //{ // USwfMovie *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // if (result && result->RawData.Count > 0) // { // std::ofstream fout; // fout.open("DialogWindow.swf", std::ios::binary | std::ios::out); // fout.write((char *)result->RawData.Data, result->RawData.Max); // fout.close(); // } // return result; //} //else if (wcsstr(pName, L"/Game/UI/MainMenu/BPMenu_GFxMainMenu.BPMenu_GFxMainMenu_C") != NULL) //{ // UGFxOakMainMenu *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // return result; //} //else if (wcsstr(pName, L"/Game/UI/Options/OptionsMenu.OptionsMenu") != NULL) //{ // UObject *result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // std::cout << pClass->GetFullName() << std::endl; // return result; //} //else if (wcsstr(pName, L"/Game/UI/Options/BPMenu_OptionsMenu.BPMenu_OptionsMenu_C") != NULL) //{ // UObject* result = static_cast(oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation)); // /*std::cout << pClass->GetFullName() << std::endl; // for (auto super = result->Class; super; super = static_cast(super->SuperField)) // { // std::cout << super->GetFullName() << std::endl; // }*/ // return result; //} return oStaticLoadObject(pClass, pOuter, pName, pFileName, LoadFlags, Sandbox, bAllowObjectReconciliation); } void CreateMenuItems(sol::this_state s, const std::string& btnText, sol::function func) { EnterCriticalSection(&luamgr->luaCritSec); UGFxMainAndPauseBaseMenu* menuToUse = NULL; if (oGetMapName && oGetMapName().ToString().find("MenuMap_P") != std::string::npos) { menuToUse = mainMenu; if (menuToUse->MenuItems.Count == 5) { createdMenuItems.clear(); /*createdButtonItems.clear(); createdDropdownListItems.clear(); createdSliderItems.clear(); createdSpinnerItems.clear();*/ } } else { menuToUse = pauseMenu; if (menuToUse->MenuItems.Count == 6) { createdMenuItems.clear(); /*createdButtonItems.clear(); createdDropdownListItems.clear(); createdSliderItems.clear(); createdSpinnerItems.clear();*/ } } if (menuToUse && menuToUse->IsValidLowLevel()) { int newIndex = menuToUse->AddMenuItem(btnText, "OnGraphicsClicked", false, -1); if (menuToUse->MenuItems.Data && menuToUse->MenuItems[newIndex].MenuItem) { createdMenuItems[menuToUse->MenuItems[newIndex].MenuItem] = std::make_tuple(func, sol::lua_nil, s.L); } } LeaveCriticalSection(&luamgr->luaCritSec); } void CreateMenuItemUI(sol::this_state s, const std::string& btnText, sol::function clickFunc, sol::function buildUIFunc, sol::function conditionToShow) { EnterCriticalSection(&luamgr->luaCritSec); MenuToCreate menuToCreate; menuToCreate.s = s.L; menuToCreate.ButtonText = btnText; if(clickFunc.valid()) menuToCreate.OnClick = clickFunc; if(buildUIFunc.valid()) menuToCreate.BuildUI = buildUIFunc; if(conditionToShow.valid()) menuToCreate.ConditionToShow = conditionToShow; if (!buildUIFunc.valid()) menuToCreate.BuildUI = sol::lua_nil; menusToCreate.push_back(menuToCreate); LeaveCriticalSection(&luamgr->luaCritSec); return; } typedef void* (__fastcall* tFuncBind)(UObject* thisZ, const FFrame& frame, void* something, void* something2); tFuncBind oFuncBind = NULL; void* hkUFuncBind(UObject* thisZ, FFrame& frame, UFunction* something, void* something2) { //std::cout << thisZ->GetFullName() << " wants to bind: " << something->GetFullName() << std::endl; void* result = oFuncBind(thisZ, frame, something, something2); return result; } typedef void *(__fastcall *tBuildMainMenu)(UGFxOakMainMenu *); tBuildMainMenu oBuildMainMenu = NULL; void MyTest(class UGbxGFxButton* PressedButton, const struct FGbxMenuInputEvent& InputInfo) { std::cout << "Hello" << std::endl; } void* hkBuildMainMenu(UGFxOakMainMenu* menuToUse) { inCustomOptionsMenu = false; static UFunction* onOptionsClickedFunc = UObject::FindObject("Function OakGame.GFxOakMainMenu.OnOptionsClicked"); void* result = oBuildMainMenu(menuToUse); if (menuToUse && menuToUse->MenuList) menuToUse->MenuList->PositionOfFirstItem.Y = 0.0f; int newIndex = menuToUse->AddMenuItem("BLua", "", false, -1); if (newIndex > 0) { bLuaMenuBtn = menuToUse->MenuItems.Data[newIndex].MenuItem; bLuaMenuBtn->OnClicked.FunctionName = onOptionsClickedFunc->Name; } while (!onGraphicsClickedFunc) onGraphicsClickedFunc = UObject::FindObject("Function OakGame.GFxMainAndPauseBaseMenu.OnGraphicsClicked"); return result; } typedef void* (__fastcall* tBuildPauseMenu)(UGFxPauseMenu*); tBuildPauseMenu oBuildPauseMenu = NULL; void* hkBuildPauseMenu(UGFxPauseMenu* menuToUse) { inCustomOptionsMenu = false; static UFunction* onOptionsClickedFunc = UObject::FindObject("Function OakGame.GFxPauseMenu.OnOptionsClicked"); void* result = oBuildPauseMenu(menuToUse); if(menuToUse && menuToUse->MenuList) menuToUse->MenuList->PositionOfFirstItem.Y = 0.0f; int newIndex = menuToUse->AddMenuItem("BLua", "", false, -1); if (newIndex > 0) { bLuaMenuBtn = menuToUse->MenuItems.Data[newIndex].MenuItem; bLuaMenuBtn->OnClicked.FunctionName = onOptionsClickedFunc->Name; } return result; } void* hkOptionBaseCreatePanel(UGFxOptionBase* thisZ, UGFxOptionsMenu* pMenu, TArray& items, UGbxGFxGridScrollingList* scrollingList, AOakPlayerController* pc, UOakProfile* profile, UOakGameInstance* instance) { if (!thisZ->IsA(UGFxGraphicsOptions::StaticClass())) { void* result = oOptionBaseCreateContentPanel(thisZ, pMenu, items, scrollingList, pc, profile, instance); return result; } EnterCriticalSection(&luamgr->luaCritSec); for (auto& cell : createdMenuItems) { UGbxGFxListCell* target = reinterpret_cast(cell.first); if (target) { if (target == lastPressedButton && inCustomOptionsMenu) { lastPressedButton = NULL; lua_State* lua = std::get<2>(cell.second); sol::protected_function current = std::get<1>(cell.second); if (current.valid()) { sol::protected_function_result result = current(); if (!result.valid()) { sol::error err = result; std::cout << "Error creating UI: " << err.what() << std::endl; PrintGameConsole(err.what()); Logger->error(err.what()); } else { if (result.return_count() == 1) { sol::table elements = result; std::vector returnValue = elements.as>(); if (returnValue.size() > 0) { UOptionDescriptionItem** tempPrevious = items.Data; int32_t prevCount = items.Count; int32_t prevMax = items.Max; // Save previous items, otherwise they'll be gone "forever" items.Data = NULL; items.Count = 0; items.Max = 0; ZeroMemory(&pMenu->MainPanel->SubtitleBarItems, sizeof(FSubtitleBarItems)); void* result = oOptionBaseCreateContentPanel(thisZ, pMenu, items, scrollingList, pc, profile, instance); items.Data = tempPrevious; items.Count = prevCount; items.Max = prevMax; for (auto& i : returnValue) { switch (i->UIElementType) { case EOptionItemType::Title:{ thisZ->SetupTitleItem(i->DisplayName); break; } case EOptionItemType::Spinner:{ UISpinner* current = static_cast(i); UOptionDescriptionItem* item = static_cast(StaticConstructObject(UOptionDescriptionItem::StaticClass(), GetTransientPackage(), FName(""))); if(item){ item->OptionItemType = i->UIElementType; item->OptionDescriptionText = current->DescriptionText; item->OptionDescriptionTitle = current->DescriptionTitle; item->OptionItemName = current->DisplayName; std::vector options = current->Options.as>(); for (auto& o : options) item->SpinnerOptions.Add(FText(o)); UGbxGFxListItemSpinner* spinner = thisZ->SetupSpinnerItem(item, current->Index, "OnAnisotropicFilteringChanged"); if (spinner) { if (current->Index < 0 || current->Index > options.size() - 1) spinner->SetDefaultValue(0); else spinner->SetDefaultValue(current->Index); uiData[spinner] = i; } } break; } case EOptionItemType::BooleanSpinner: { UIBoolSpinner* current = static_cast(i); UOptionDescriptionItem* item = static_cast(StaticConstructObject(UOptionDescriptionItem::StaticClass(), GetTransientPackage(), FName(""))); if (item) { item->OptionItemType = i->UIElementType; item->OptionDescriptionText = current->DescriptionText; item->OptionDescriptionTitle = current->DescriptionTitle; item->OptionItemName = current->DisplayName; item->BooleanOnText = current->OnText; item->BooleanOffText = current->OffText; UGbxGFxListItemSpinner* spinner = thisZ->SetupSpinnerItemAsBoolean(item, current->Value, "OnAnisotropicFilteringChanged"); if (spinner) { spinner->SetDefaultValue((int)current->Value); //spinner->SetDefaultValue(current->Index); //createdSpinnerItems.push_back(spinner); uiData[spinner] = i; } } break; } case EOptionItemType::Button:{ UIButton* current = static_cast(i); UOptionDescriptionItem* item = static_cast(StaticConstructObject(UOptionDescriptionItem::StaticClass(), GetTransientPackage(), FName(""))); if (item) { item->OptionItemType = i->UIElementType; item->OptionDescriptionText = current->DescriptionText; item->OptionDescriptionTitle = current->DescriptionTitle; item->OptionItemName = current->DisplayName; UGbxGFxListCellWithData* btn = thisZ->SetupButtonItem(item, "OnBenchmarkRunClicked"); //createdButtonItems.push_back(btn); uiData[btn] = i; } break; } case EOptionItemType::Slider: { UISlider* current = static_cast(i); UOptionDescriptionItem* item = static_cast(StaticConstructObject(UOptionDescriptionItem::StaticClass(), GetTransientPackage(), FName(""))); if (item) { item->OptionItemType = i->UIElementType; item->OptionDescriptionText = current->DescriptionText; item->OptionDescriptionTitle = current->DescriptionTitle; item->OptionItemName = current->DisplayName; item->SliderMax = current->Max; item->SliderMin = current->Min; item->SliderStep = current->Step; item->SliderIsInteger = current->bIsInt; UGbxGFxListItemNumber* number = thisZ->SetupSliderItem(item, current->Value, ""); if (current->Value < current->Min || current->Value > current->Max) number->SetDefaultValue(current->Min); else number->SetDefaultValue(current->Value); // TODO: Add function to set default value //createdSliderItems.push_back(number); uiData[number] = i; } break; } case EOptionItemType::DropDownList: { UIDropdown* current = static_cast(i); UOptionDescriptionItem* item = static_cast(StaticConstructObject(UOptionDescriptionItem::StaticClass(), GetTransientPackage(), FName(""))); if (item) { item->OptionItemType = i->UIElementType; item->OptionDescriptionText = current->DescriptionText; item->OptionDescriptionTitle = current->DescriptionTitle; item->OptionItemName = current->DisplayName; std::vector options = current->Options.as>(); for (auto& o : options) item->DropDownOptions.Add(FText(o)); UGbxGFxListItemComboBox* obj = thisZ->SetupDropDownlistItem(item, item->DropDownOptions, current->Index, "OnResolutionDropDownSelectionChanged"); if(current->Index < 0 || current->Index > options.size() - 1) obj->SetDefaultValue(0); else obj->SetDefaultValue(current->Index); //createdDropdownListItems.push_back(obj); uiData[obj] = i; } break; } // TODO: Figure out how to get this to work instead of crashing case EOptionItemType::Keybinding_Button: { UIControl* current = static_cast(i); UOptionDescriptionItem* item = static_cast(StaticConstructObject(UOptionDescriptionItem::StaticClass(), GetTransientPackage(), FName(""))); if (item) { item->OptionItemType = i->UIElementType; item->OptionDescriptionText = current->DescriptionText; item->OptionDescriptionTitle = current->DescriptionTitle; item->OptionItemName = current->DisplayName; UGFxObject* obj = thisZ->SetupControlsItem( item, FText(R"()"), FText(R"()"), EBindingType::Common, NULL); //createdDropdownListItems.push_back(obj); uiData[obj] = i; } break; } } } LeaveCriticalSection(&luamgr->luaCritSec); return result; } } } } } } } LeaveCriticalSection(&luamgr->luaCritSec); void* result = oOptionBaseCreateContentPanel(thisZ, pMenu, items, scrollingList, pc, profile, instance); return result; } void hkOptionBaseCreatePanelItem(UGFxOptionBase* thisZ, UOptionDescriptionItem* item) { return oOptionBaseCreateContentPanelItem(thisZ, item); } typedef void* (__fastcall* tBuildOptionsMenu)(UGFxOptionsMenu*); tBuildOptionsMenu oBuildOptionsMenu = NULL; void* hkBuildOptionsMenu(UGFxOptionsMenu* menuToUse) { void* result = oBuildOptionsMenu(menuToUse); return result; } UGFxObject* hkSetupControlsItem(UGFxOptionBase* thisZ, UOptionDescriptionItem* item, const FText& unknownText, const FText& unknownText2, EBindingType type, void* someThing) { void* mysomething = oRealloc(0, 144, 0); UGFxObject* result = oOptionBaseSetupControlsItem(thisZ, item, unknownText, unknownText2, type, someThing); return result; } void ApplyBaseHooks() { uintptr_t staticExec = NULL; while (!staticExec) { uintptr_t patternAddress = PatternScan::FindSignature(NULL, staticExecPattern.crypt_get()); if (patternAddress) { patternAddress += 110; int32_t offset = *(int32_t *)(patternAddress + 1); if (offset) { staticExec = (patternAddress + offset + 5); } } } /*uintptr_t addToViewport = PatternScan::FindSignature(NULL, addToViewportPattern.crypt_get()); while (addToViewport == NULL) { addToViewport = PatternScan::FindSignature(NULL, addToViewportPattern.crypt_get()); Sleep(20); }*/ /*uintptr_t registerFunc = PatternScan::FindSignature(NULL, registerFunctionAPattern.crypt_get()); while (registerFunc == NULL) { registerFunc = PatternScan::FindSignature(NULL, registerFunctionAPattern.crypt_get()); Sleep(20); } oRegisterFunction = (tRegisterFunction)registerFunc;*/ /* uintptr_t registerFuncOther = PatternScan::FindSignature(NULL, registerFunctionOtherPattern.crypt_get()); while (registerFuncOther == NULL) { registerFuncOther = PatternScan::FindSignature(NULL, registerFunctionOtherPattern.crypt_get()); Sleep(20); }*/ /*uintptr_t callFunc = NULL; while (!callFunc) { uintptr_t patternAddress = PatternScan::FindSignature(NULL, callFuncPattern.crypt_get()); if (patternAddress) { patternAddress += 100; int32_t offset = *(int32_t*)(patternAddress + 1); if (offset) { oCallFunc = (tCallFunc)(patternAddress + offset + 5); callFunc = (patternAddress + offset + 5); } } }*/ uintptr_t staticLoadObject = PatternScan::FindSignature(NULL, staticLoadObjectPattern.crypt_get()); while(!staticLoadObject){ staticLoadObject = PatternScan::FindSignature(NULL, staticLoadObjectPattern.crypt_get()); Sleep(20); } /*uintptr_t funcBind = PatternScan::FindSignature(NULL, ufunctionBindPattern.crypt_get()); while (!funcBind) { funcBind = PatternScan::FindSignature(NULL, ufunctionBindPattern.crypt_get()); Sleep(20); }*/ /*uintptr_t staticFindObject = PatternScan::FindSignature(NULL, staticFindObjectPattern.crypt_get()); while (!staticFindObject) { staticFindObject = PatternScan::FindSignature(NULL, staticFindObjectPattern.crypt_get()); Sleep(20); }*/ uintptr_t staticConstructObject = PatternScan::FindSignature(NULL, staticConstructObjectPattern.crypt_get()); while (!staticConstructObject) { staticConstructObject = PatternScan::FindSignature(NULL, staticConstructObjectPattern.crypt_get()); Sleep(20); } uintptr_t optionBaseCreateContentPanel = PatternScan::FindSignature(NULL, optionBaseCreateContentPanelPattern.crypt_get()); while (!optionBaseCreateContentPanel) { optionBaseCreateContentPanel = PatternScan::FindSignature(NULL, optionBaseCreateContentPanelPattern.crypt_get()); Sleep(20); } uintptr_t optionBaseCreateContentPanelItem = PatternScan::FindSignature(NULL, optionBaseCreateContentPanelItemPattern.crypt_get()); while (!optionBaseCreateContentPanelItem) { optionBaseCreateContentPanelItem = PatternScan::FindSignature(NULL, optionBaseCreateContentPanelItemPattern.crypt_get()); Sleep(20); } uintptr_t buildMainMenu = PatternScan::FindSignature(NULL, buildMainMenuPattern.crypt_get()); while (!buildMainMenu) { buildMainMenu = PatternScan::FindSignature(NULL, buildMainMenuPattern.crypt_get()); Sleep(20); } uintptr_t buildPauseMenu = PatternScan::FindSignature(NULL, buildPauseMenuPattern.crypt_get()); while (!buildPauseMenu) { buildPauseMenu = PatternScan::FindSignature(NULL, buildPauseMenuPattern.crypt_get()); Sleep(20); } uintptr_t buildOptionsMenu = PatternScan::FindSignature(NULL, buildOptionsMenuPattern.crypt_get()); while (!buildOptionsMenu) { buildOptionsMenu = PatternScan::FindSignature(NULL, buildOptionsMenuPattern.crypt_get()); Sleep(20); } uintptr_t doSparkAuth = PatternScan::FindSignature(NULL, FOakPlayerManager__DoSparkAuthenticationPattern.crypt_get()); while (!doSparkAuth) { doSparkAuth = PatternScan::FindSignature(NULL, FOakPlayerManager__DoSparkAuthenticationPattern.crypt_get()); Sleep(20); } uintptr_t startupProcessPerformstep = PatternScan::FindSignature(NULL, FOakStartupProcess__PerformStepPattern.crypt_get()); while (!startupProcessPerformstep) { startupProcessPerformstep = PatternScan::FindSignature(NULL, FOakStartupProcess__PerformStepPattern.crypt_get()); Sleep(20); } uintptr_t gbxSparkModuleGet = PatternScan::FindSignature(NULL, FGbxSparkModuleGetPattern.crypt_get()); while (!gbxSparkModuleGet) { gbxSparkModuleGet = PatternScan::FindSignature(NULL, FGbxSparkModuleGetPattern.crypt_get()); Sleep(20); } uintptr_t sparkInitProcessStartProcess = PatternScan::FindSignature(NULL, FSparkInitProcessStartProcessPattern.crypt_get()); while (!sparkInitProcessStartProcess) { sparkInitProcessStartProcess = PatternScan::FindSignature(NULL, FSparkInitProcessStartProcessPattern.crypt_get()); Sleep(20); } uintptr_t sparkInitProcessReadDiscovery = PatternScan::FindSignature(NULL, FSparkInitProcessReadDiscoveryPattern.crypt_get()); while (!sparkInitProcessReadDiscovery) { sparkInitProcessReadDiscovery = PatternScan::FindSignature(NULL, FSparkInitProcessReadDiscoveryPattern.crypt_get()); Sleep(20); } uintptr_t oakGameInstanceProcessPendingMicropatches = PatternScan::FindSignature(NULL, oakGameInstanceProcessPendingMicropatchesPattern.crypt_get()); while (!oakGameInstanceProcessPendingMicropatches) { oakGameInstanceProcessPendingMicropatches = PatternScan::FindSignature(NULL, oakGameInstanceProcessPendingMicropatchesPattern.crypt_get()); Sleep(20); } uintptr_t setupControlsItem = PatternScan::FindSignature(NULL, optionBaseSetupControlsItemPattern.crypt_get()); while (!setupControlsItem) { setupControlsItem = PatternScan::FindSignature(NULL, optionBaseSetupControlsItemPattern.crypt_get()); Sleep(20); } /*std::string test = xorstr("4D 89 ?? ?? 4D 89 ?? ?? 4C 8B ?? 44 89 ?? ?? ?? 4C 39 ?? ?? 0F 84 ?? ?? ?? ?? 48 8B ?? ?? 48 85 ?? 0F 84 ?? ?? ?? ?? 33 C0 F0 44 ?? ?? ?? ?? 85 C0 7E ?? 49 8B ?? ?? 4C 89 ?? ?? ?? 48 89 ?? ?? ?? 48 85 ?? 74 ?? 33 C0 F0 44 ?? ?? ?? ?? 74 ?? 8D 48 ?? F0 0F ?? ?? ?? 74 ?? 33 C0 F0 44 ?? ?? ?? ?? 75 ?? 4C 8B ?? ?? ?? 48 8D ?? ?? ?? 4C 89 ?? ?? ?? 41 BE ?? ?? ?? ?? EB ?? 48 8B ?? ?? ?? 48 85 ?? 74 ?? 49 8B ?? ?? 48 89 ?? ?? ?? 4C 8B ?? ?? ?? 48 8D ?? ?? ?? 41 BE ?? ?? ?? ?? EB ?? 0F 57 ?? 48 8D ?? ?? ?? F3 0F ?? ?? ?? ?? 41 BE ?? ?? ?? ?? 4D 8B ?? 48 8B ?? ?? BF ?? ?? ?? ?? 4C 89 ?? ?? 4C 89 ?? 48 89 ?? ?? ?? ?? ?? ?? 41 F6 C6 ?? 74 ?? 48 8B ?? ?? 41 83 E6 ?? 48 85 ?? 74 ?? 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? ?? 48 8B ?? 48 8B ?? FF 10 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? ?? 8D 57 ?? 48 8B ?? FF 50 ?? 41 F6 C6 ?? 4C 8B ?? ?? ?? ?? ?? ?? 74 ?? 48 8B ?? ?? ?? 48 85 ?? 74 ?? 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? ?? ?? 48 8B ?? 48 8B ?? FF 10 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? ?? ?? BA ?? ?? ?? ?? 48 8B ?? FF 50 ?? 4D 85 ?? 0F 84 ?? ?? ?? ?? 48 8D ?? ?? 4C 89 ?? ?? B9 ?? ?? ?? ?? 44 89 ?? ?? E8 ?? ?? ?? ?? 48 85 ?? 74 ?? 48 8D ?? ?? ?? ?? ?? 4C 89 ?? ?? 48 89 ?? 48 8D ?? ?? ?? ?? ?? 4C 89 ?? ?? ?? 33 D2 48 89 ?? ?? 48 8D ?? ?? ?? 48 C7 44 24 60 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? 4C 8D ?? ?? ?? ?? ?? 41 B9 ?? ?? ?? ?? B8 ?? ?? ?? ?? 41 8B ?? 66 89 ?? ?? ?? E8 ?? ?? ?? ?? 4C 8D ?? ?? 48 8D ?? ?? ?? 48 8D ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8D ?? ?? FF 15 ?? ?? ?? ?? 48 8B ?? ?? B9 ?? ?? ?? ?? 48 89 ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 ?? 74 ?? 48 8B ?? E8 ?? ?? ?? ?? 48 8B ?? EB ?? 49 8B ?? B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 ?? 74 ?? 48 8D ?? ?? ?? ?? ?? C7 40 08 ?? ?? ?? ?? 48 89 ?? C7 40 0C ?? ?? ?? ?? 48 89 ?? ?? EB ?? 49 8B ?? 4C 8B ?? 48 89 ?? ?? ?? 48 8B ?? 48 89 ?? ?? ?? 48 8D ?? ?? ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? C6 40 10 ?? 48 8B ?? ?? 48 8B ?? 48 85 ?? 74 ?? F0 FF ?? ?? 48 89 ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 48 89 ?? ?? ?? ?? ?? 48 8D ?? ?? ?? 4C 89 ?? ?? ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? 48 85 ?? 74 ?? 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? ?? ?? 48 8B ?? 48 8B ?? FF 10 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? ?? ?? BA ?? ?? ?? ?? 48 8B ?? FF 50 ?? 48 8D ?? ?? ?? ?? ?? 4C 89 ?? ?? ?? ?? ?? B9 ?? ?? ?? ?? 44 89 ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 ?? 74 ?? 48 8D ?? ?? ?? ?? ?? 48 89 ?? 48 8D ?? ?? ?? ?? ?? 48 89 ?? ?? 48 8D ?? ?? ?? ?? ?? 48 89 ?? ?? ?? ?? ?? 48 8B ?? ?? ?? 48 89 ?? ?? 48 8B ?? ?? ?? 48 89 ?? ?? 48 85 ?? 74 ?? F0 FF ?? ?? 48 8D ?? ?? ?? ?? ?? 48 8D ?? ?? E8 ?? ?? ?? ?? 48 8D ?? ?? 4C 89 ?? ?? B9 ?? ?? ?? ?? 44 89 ?? ?? E8 ?? ?? ?? ?? 48 8B ?? 48 85 ?? 74 ?? 48 8D ?? ?? ?? ?? ?? 48 89 ?? 48 8B ?? ?? 48 89 ?? ?? 48 8B ?? ?? 48 89 ?? ?? 48 85 ?? 74 ?? 48 8B ?? ?? F0 FF ?? ?? 48 8D ?? ?? 48 8D ?? ?? E8 ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 48 8B ?? ?? 48 89 ?? ?? 44 39 ?? ?? ?? ?? ?? 74 ?? 48 85 ?? 4C 8D ?? ?? 4D 0F ?? ?? 4C 0B ?? 74 ?? 49 8B ?? 33 D2 49 8B ?? FF 50 ?? 48 8B ?? ?? 48 85 ?? 74 ?? E8 ?? ?? ?? ?? 48 8B ?? ?? 48 85 ?? 74 ?? 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? 48 8B ?? FF 10 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? BA ?? ?? ?? ?? 48 8B ?? FF 50 ?? 48 8B ?? ?? ?? ?? ?? 44 39 ?? ?? ?? ?? ?? 74 ?? 48 85 ?? 4C 8D ?? ?? ?? ?? ?? 4D 0F ?? ?? 4C 0B ?? 74 ?? 49 8B ?? 33 D2 49 8B ?? FF 50 ?? 48 8B ?? ?? ?? ?? ?? 48 85 ?? 74 ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? 48 85 ?? 74 ?? 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? 48 8B ?? FF 10 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? BA ?? ?? ?? ?? 48 8B ?? FF 50 ?? 48 8D ?? ?? 49 8B ?? E8 ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 4C 8B ?? ?? ?? ?? ?? ?? 4C 8B ?? ?? ?? ?? ?? ?? 4C 8B ?? ?? ?? ?? ?? ?? 48 8B ?? ?? ?? ?? ?? ?? 48 85 ?? 74 ?? 8B C7 F0 0F ?? ?? ?? 83 F8 ?? 75 ?? 48 8B ?? 48 8B ?? FF 10 F0 0F ?? ?? ?? 83 FF ?? 75 ?? 48 8B ?? 8B D7 48 8B ?? FF 50 ?? 48 8B ?? ?? ?? ?? ?? 48 33 ?? E8 ?? ?? ?? ?? 48 81 C4 ?? ?? ?? ?? 5F 5E 5D C3 CC CC CC CC CC CC CC CC CC 4C 8B"); uintptr_t removeAllListItems = PatternScan::FindSignature(NULL, test.crypt_get()); while (!removeAllListItems) { removeAllListItems = PatternScan::FindSignature(NULL, test.crypt_get()); Sleep(20); }*/ SuspendResume::Suspend(); while (MH_CreateHookEx((LPVOID)staticExec, &hkStaticExec, &oStaticExec) != MH_OK) Sleep(200); /*while (MH_CreateHookEx((LPVOID)addToViewport, &hkAddToViewport, &oAddToViewport) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)registerFunc, &hkRegisterFunction, &oRegisterFunction) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)registerFuncOther, &hkRegisterFunctionOther, &oRegisterFunctionOther) != MH_OK) Sleep(200);*/ while (MH_CreateHookEx((LPVOID)staticLoadObject, &hkStaticLoadObject, &oStaticLoadObject) != MH_OK) Sleep(200); /*while (MH_CreateHookEx((LPVOID)staticFindObject, &StaticFindObject, &oStaticFindObject) != MH_OK) Sleep(200);*/ /*while (MH_CreateHookEx((LPVOID)callFunc, &hkCallFunction, &oCallFunc) != MH_OK) Sleep(200); */ /*while (MH_CreateHookEx((LPVOID)funcBind, &hkUFuncBind, &oFuncBind) != MH_OK) Sleep(200);*/ while (MH_CreateHookEx((LPVOID)staticConstructObject, &StaticConstructObject, &oStaticConstructObject) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)optionBaseCreateContentPanel, &hkOptionBaseCreatePanel, &oOptionBaseCreateContentPanel) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)optionBaseCreateContentPanelItem, &hkOptionBaseCreatePanelItem, &oOptionBaseCreateContentPanelItem) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)buildMainMenu, &hkBuildMainMenu, &oBuildMainMenu) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)buildPauseMenu, &hkBuildPauseMenu, &oBuildPauseMenu) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)buildOptionsMenu, &hkBuildOptionsMenu, &oBuildOptionsMenu) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)doSparkAuth, &hkDoSparkAuth, &oDoSparkAuth) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)startupProcessPerformstep, &hkStartupProcessPerformStep, &oStartupProcessPerformStep) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)sparkInitProcessStartProcess, &hkSparkInitProcessStartProcess, &oFSparkInitProcessStartProcess) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)sparkInitProcessReadDiscovery, &hkSparkInitProcessReadDiscovery, &oFSparkInitProcessReadDiscovery) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)oakGameInstanceProcessPendingMicropatches, &hkOakGameInstanceProcessPendingMicropatches, &oOakGameInstanceProcessPendingMicropatches) != MH_OK) Sleep(200); while (MH_CreateHookEx((LPVOID)setupControlsItem, &hkSetupControlsItem, &oOptionBaseSetupControlsItem) != MH_OK) Sleep(200); /*while (MH_CreateHookEx((LPVOID)removeAllListItems, &hkRemoveAllListItems, &oRemoveAllListItems) != MH_OK) Sleep(200);*/ MH_EnableHook(MH_ALL_HOOKS); SuspendResume::Resume(); } void HotkeyThread() { std::string hk1; std::string hk2; std::string hk3; while (true) { if (wantsExit) ExitThread(0); //SetConsoleKey("F6"); if (!luamgr) { Sleep(50); continue; } luamgr->ValidateHotkeys(); EnterCriticalSection(&luamgr->luaCritSec); std::unordered_map funcToCall; for (auto &hk : luamgr->registeredHotkeys) { hk1 = std::get<2>(hk); hk2 = std::get<3>(hk); hk3 = std::get<4>(hk); if (hk1.size() > 0) { if (hk2.size() > 0) { if (hk3.size() > 0) { if (LuaUtility::IsKeyPressed(hk1, hk2, hk3)) { lua_State *lua = std::get<1>(hk); //sol::protected_function func(lua, sol::ref_index(std::get<0>(hk).registry_index())); sol::protected_function func = std::get<0>(hk); if (func.valid()) { funcToCall.insert_or_assign(std::get<0>(hk).registry_index(), func); } } } else { if (LuaUtility::IsKeyPressed(hk1, hk2)) { lua_State *lua = std::get<1>(hk); //sol::protected_function func(lua, sol::ref_index(std::get<0>(hk).registry_index())); sol::protected_function func = std::get<0>(hk); if (func.valid()) { funcToCall.insert_or_assign(std::get<0>(hk).registry_index(), func); } } } } else { if (LuaUtility::IsKeyPressed(hk1)) { lua_State *lua = std::get<1>(hk); //sol::protected_function func(lua, sol::ref_index(std::get<0>(hk).registry_index())); sol::protected_function func = std::get<0>(hk); if (func.valid()) { funcToCall.insert_or_assign(std::get<0>(hk).registry_index(), func); } } } } } if (hk1.size() > 0) { if (hk2.size() > 0) { if (hk3.size() > 0) { while (LuaUtility::IsKeyPressed(hk1, hk2, hk3)) Sleep(5); } else { while (LuaUtility::IsKeyPressed(hk1, hk2)) Sleep(5); } } else { while (LuaUtility::IsKeyPressed(hk1)) Sleep(5); } } for (auto &f : funcToCall) { f.second(); } LeaveCriticalSection(&luamgr->luaCritSec); Sleep(20); } } void CreateGUIBindings() { // UIData sol::usertype uidatatype = luamgr->lua->new_usertype("UIData", sol::no_constructor); // UIButton sol::usertype uibuttontype = luamgr->lua->new_usertype("UIButton", sol::no_constructor, sol::base_classes, sol::bases()); uibuttontype.set_function("New", [](sol::this_state s) {UIButton* data = new UIButton; data->UIElementType = EOptionItemType::Button; data->state = s.L; return data; }); uibuttontype.set("DisplayName", &UIButton::DisplayName); uibuttontype.set("DescriptionText", &UIButton::DescriptionText); uibuttontype.set("DescriptionTitle", &UIButton::DescriptionTitle); uibuttontype.set("OnClicked", &UIButton::OnChangedOrClicked); // UISlider sol::usertype uislidertype = luamgr->lua->new_usertype("UISlider", sol::no_constructor, sol::base_classes, sol::bases()); uislidertype.set_function("New", [](sol::this_state s) {UISlider* data = new UISlider; data->UIElementType = EOptionItemType::Slider; data->state = s.L; return data; }); uislidertype.set("DisplayName", &UISlider::DisplayName); uislidertype.set("DescriptionText", &UISlider::DescriptionText); uislidertype.set("DescriptionTitle", &UISlider::DescriptionTitle); uislidertype.set("OnValueChanged", &UISlider::OnChangedOrClicked); uislidertype.set("Value", &UISlider::Value); uislidertype.set("Min", &UISlider::Min); uislidertype.set("Max", &UISlider::Max); uislidertype.set("Step", &UISlider::Step); uislidertype.set("bIsInt", &UISlider::bIsInt); // UISpinner sol::usertype uispinnertype = luamgr->lua->new_usertype("UISpinner", sol::no_constructor, sol::base_classes, sol::bases()); uispinnertype.set_function("New", [](sol::this_state s) {UISpinner* data = new UISpinner; data->UIElementType = EOptionItemType::Spinner; data->state = s.L; return data; }); uispinnertype.set("DisplayName", &UISpinner::DisplayName); uispinnertype.set("DescriptionText", &UISpinner::DescriptionText); uispinnertype.set("DescriptionTitle", &UISpinner::DescriptionTitle); uispinnertype.set("OnSelectionChanged", &UISpinner::OnChangedOrClicked); uispinnertype.set("Index", &UISpinner::Index); uispinnertype.set("Options", &UISpinner::Options); // UIBoolSpinner sol::usertype uiboolspinnertype = luamgr->lua->new_usertype("UIBoolSpinner", sol::no_constructor, sol::base_classes, sol::bases()); uiboolspinnertype.set_function("New", [](sol::this_state s) {UIBoolSpinner* data = new UIBoolSpinner; data->UIElementType = EOptionItemType::BooleanSpinner; data->state = s.L; return data; }); uiboolspinnertype.set("DisplayName", &UIBoolSpinner::DisplayName); uiboolspinnertype.set("DescriptionText", &UIBoolSpinner::DescriptionText); uiboolspinnertype.set("DescriptionTitle", &UIBoolSpinner::DescriptionTitle); uiboolspinnertype.set("OnSelectionChanged", &UIBoolSpinner::OnChangedOrClicked); uiboolspinnertype.set("Value", &UIBoolSpinner::Value); uiboolspinnertype.set("OnText", &UIBoolSpinner::OnText); uiboolspinnertype.set("OffText", &UIBoolSpinner::OffText); // UIDropdown sol::usertype uidropdowntype = luamgr->lua->new_usertype("UIDropdown", sol::no_constructor, sol::base_classes, sol::bases()); uidropdowntype.set_function("New", [](sol::this_state s) {UIDropdown* data = new UIDropdown; data->UIElementType = EOptionItemType::DropDownList; data->state = s.L; return data; }); uidropdowntype.set("DisplayName", &UIDropdown::DisplayName); uidropdowntype.set("DescriptionText", &UIDropdown::DescriptionText); uidropdowntype.set("DescriptionTitle", &UIDropdown::DescriptionTitle); uidropdowntype.set("OnSelectionChanged", &UIDropdown::OnChangedOrClicked); uidropdowntype.set("Index", &UIDropdown::Index); uidropdowntype.set("Options", &UIDropdown::Options); // UIControl sol::usertype uicontrolstype = luamgr->lua->new_usertype("UIControl", sol::no_constructor, sol::base_classes, sol::bases()); uicontrolstype.set_function("New", [](sol::this_state s) {UIControl* data = new UIControl; data->UIElementType = EOptionItemType::Keybinding_Button; data->state = s.L; return data; }); uicontrolstype.set("DisplayName", &UIControl::DisplayName); uicontrolstype.set("DescriptionText", &UIControl::DescriptionText); uicontrolstype.set("DescriptionTitle", &UIControl::DescriptionTitle); uicontrolstype.set("OnSelectionChanged", &UIControl::OnChangedOrClicked); // UITitle sol::usertype uititletype = luamgr->lua->new_usertype("UITitle", sol::no_constructor, sol::base_classes, sol::bases()); uititletype.set_function("New", [](sol::this_state s) {UITitle* data = new UITitle; data->UIElementType = EOptionItemType::Title; return data; }); uititletype.set("DisplayName", &UITitle::DisplayName); luamgr->lua->set_function("AddMenuButton", sol::overload( [](sol::this_state s, const std::string& btnText, sol::object clickFunc) { CreateMenuItemUI(s, btnText, clickFunc, sol::lua_nil, sol::lua_nil); }, [](sol::this_state s, const std::string& btnText, sol::lua_nil_t clickFunc, sol::object buildGUIFunc) { CreateMenuItemUI(s, btnText, sol::lua_nil, buildGUIFunc, sol::lua_nil); }, [](sol::this_state s, const std::string& btnText, sol::lua_nil_t clickFunc, sol::object buildGUIFunc, sol::object conditionToShow) { CreateMenuItemUI(s, btnText, sol::lua_nil, buildGUIFunc, conditionToShow); }, [](sol::this_state s, const std::string& btnText, sol::lua_nil_t clickFunc, sol::object buildGUIFunc, sol::lua_nil_t conditionToShow) { CreateMenuItemUI(s, btnText, sol::lua_nil, buildGUIFunc, sol::lua_nil); }, [](sol::this_state s, const std::string& btnText, sol::object clickFunc, sol::object buildGUIFunc) { CreateMenuItemUI(s, btnText, clickFunc, buildGUIFunc, sol::lua_nil); }, [](sol::this_state s, const std::string& btnText, sol::object clickFunc, sol::object buildGUIFunc, sol::object conditionToShow) { CreateMenuItemUI(s, btnText, clickFunc, buildGUIFunc, conditionToShow); } )); // UEditableText /*sol::usertype editabletexttype = luamgr->lua->new_usertype("UEditableText", sol::no_constructor, sol::meta_function::index, &UObject::GetPropertyByName, sol::meta_function::new_index, &UObject::SetPropertyByNameLua, sol::meta_function::to_string, &UObject::to_string, sol::base_classes, sol::bases()); editabletexttype.set_function("New", []() { UEditableText* rv = static_cast(StaticConstructObject(UEditableText::StaticClass(), GetTransientPackage(), FName("EditableText"))); if (rv) rv->SetText(FText("Testtext")); rv->SetIsEnabled(true); rv->SetVisibility(ESlateVisibility::Visible); return rv; }); editabletexttype.set("HintText", &UEditableText::HintText); editabletexttype.set("MinWidth", &UEditableText::MinimumDesiredWidth); editabletexttype.set("Text", &UEditableText::Text); editabletexttype.set("TooltipText", &UEditableText::ToolTipText);*/ } void CreateBLuaMenu() { bluaMenu->ButtonText = "BLua"; } void LoadAllCustomUIScripts() { EnterCriticalSection(&luamgr->luaCritSec); if (!std::filesystem::exists("./lua")) std::filesystem::create_directory("./lua"); if(!std::filesystem::exists("./lua/UI")) std::filesystem::create_directory("./lua/UI"); for (auto& p : std::filesystem::directory_iterator("./lua/UI")) { try{ sol::protected_function_result result = luamgr->lua->safe_script_file(p.path().string()); if (!result.valid()) { sol::error err = result; PrintGameConsole(err.what()); Logger->error(err.what()); } } catch(...){} } LeaveCriticalSection(&luamgr->luaCritSec); } void RefreshCustomUIs() { EnterCriticalSection(&luamgr->luaCritSec); createdMenuItems.clear(); menusToCreate.clear(); LoadAllCustomUIScripts(); LeaveCriticalSection(&luamgr->luaCritSec); } void SetupB3HMTable() { sol::table globals = luamgr->lua->globals(); b3hmTable = luamgr->lua->create_table(); globals["B3HM"] = b3hmTable; } void BindLogger() { if (!Logger) return; luamgr->lua->set_function("LogInfo", [](const std::string& message) {if (Logger) Logger->info(message); }); luamgr->lua->set_function("LogError", [](const std::string& message) {if (Logger) Logger->error(message); }); luamgr->lua->set_function("LogCritical", [](const std::string& message) {if (Logger) Logger->critical(message); }); luamgr->lua->set_function("LogWarning", [](const std::string& message) {if (Logger) Logger->warn(message); }); } void ReadAndBindConfig() { sol::table global = luamgr->lua->globals(); sol::protected_function_result funcResult = luamgr->lua->safe_script_file("./lua/Configs/config.lua"); if (!funcResult.valid()) { sol::error err = funcResult; PrintGameConsole(err.what()); Logger->error("Failed to read config-file: {}", err.what()); } if (!global["config"].valid()) { sol::table configTable = luamgr->lua->create_table(); global["config"] = configTable; } } DWORD WINAPI MainThread(LPVOID param) { atexit(callAtExit); DebugHelper::CreateConsole(); GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, L"BL3Lua.dll", &forRefCount); uintptr_t procEvent = PatternScan::FindSignature(NULL, processEventPattern.crypt_get()); while (procEvent == NULL) { procEvent = PatternScan::FindSignature(NULL, processEventPattern.crypt_get()); Sleep(50); } MH_STATUS status; status = MH_Initialize(); while (status == MH_ERROR_NOT_INITIALIZED) { Sleep(200); status = MH_Initialize(); if (status == MH_ERROR_ALREADY_INITIALIZED) break; } try { Logger = spdlog::basic_logger_mt("Testlogger", "./logs/BLua.log", true).get(); Logger->set_pattern("[%H:%M:%S %z] [%l] %v"); spdlog::flush_on(spdlog::level::level_enum::info); } catch (spdlog::spdlog_ex& ex) { std::cout << "Failed to initialize logger: " << ex.what() << std::endl; } uintptr_t gObjAddress = NULL; uintptr_t gNameAddress = NULL; int tries = 0; while (tries < 20) { if (gObjAddress == NULL) { gObjAddress = PatternScan::FindSignature(NULL, gObjPattern.crypt_get()); } if (gObjAddress != NULL) { const auto gObjOffset = *reinterpret_cast(gObjAddress + 8); UObject::GObjects = reinterpret_cast(gObjAddress + 12 + (int)gObjOffset); gObjInit = true; } if (gNameAddress == NULL) { gNameAddress = PatternScan::FindSignature(NULL, gNamesPattern.crypt_get()); } if (gNameAddress != NULL) { const auto gNameOffset = *reinterpret_cast(gNameAddress + 7); FName::GNames = reinterpret_cast(*reinterpret_cast(gNameAddress + 4 + 7 + (int)gNameOffset)); gNameInit = true; } if (gObjInit && gNameInit) { SuspendResume::Suspend(); while (MH_CreateHookEx((LPVOID)procEvent, &hkProcessEvent, &oProcessEvent) != MH_OK) Sleep(200); MH_EnableHook(MH_ALL_HOOKS); SuspendResume::Resume(); Logger->info("Create LuaMgr"); luamgr = new BL3Lua(); luamgr->lua->set_function("AddHook", sol::overload( [](sol::this_state s, sol::this_environment e, const std::string &funcName, sol::function func) { luamgr->AddHook(s, e, funcName, func, true); }, [](sol::this_state s, sol::this_environment e, const std::string &funcName, sol::function func, bool isPreHook) { luamgr->AddHook(s, e, funcName, func, isPreHook); })); luamgr->lua->set_function("RemoveHook", &BL3Lua::RemoveHook, luamgr); luamgr->lua->set_function("tdump", &BL3Lua::TDump, luamgr); luamgr->lua->set_function("AddConsoleCommand", &BL3Lua::AddConsoleCommand, luamgr); luamgr->lua->set_function("RemoveConsoleCommand", &BL3Lua::RemoveConsoleCommand, luamgr); luamgr->lua->set_function("togglecam", &ToggleCam); luamgr->lua->set_function("noclip", &ToggleNoclip); luamgr->lua->set_function("AddConsoleKey", &AddConsoleKey); luamgr->lua->set_function("SetConsoleKey", &SetConsoleKey); //luamgr->lua->set_function("GetGlobalLog", []() { return GetGlobalLogSingleton(); }); /*luamgr->lua->set_function("SetConsoleLogging", [&](bool enable) { FOutputDeviceRedirector *logSingleton = GetGlobalLogSingleton(); if (!myConsoleOutputDevice) { myConsoleOutputDevice = static_cast(oCreateConsoleOutputDevice()); logSingleton->AddOutputDevice(myConsoleOutputDevice); } myConsoleOutputDevice->Show(enable); });*/ BindLogger(); Logger->info("Create GUI-Bindings"); CreateGUIBindings(); CreateBLuaMenu(); luamgr->lua->set_function("PrintGameConsole", &PrintGameConsole); luamgr->lua->set_function("RefreshHotfixes", &RefreshHotfixes); luamgr->lua->set_function("ReloadUI", &RefreshCustomUIs); //ReadAndBindConfig(); Logger->info("Applying BaseHooks"); ApplyBaseHooks(); Logger->info("Scanning for more patterns."); FindPatternsForTypedefs(); Logger->info("Create & setup Console"); ConsoleSetup(); Logger->info("Load UI-Files"); LoadAllCustomUIScripts(); nonScriptEnv = std::make_unique(sol::environment(luamgr->lua->lua_state(), sol::create, luamgr->lua->globals())).get(); luamgr->lua->collect_garbage(); UObject::GetGameplayGlobals(); SetupB3HMTable(); //CreateCheatManager(); break; } Sleep(150); } CreateThread(nullptr, NULL, (LPTHREAD_START_ROUTINE)WebSocketClientThread, NULL, NULL, nullptr); CreateThread(nullptr, NULL, (LPTHREAD_START_ROUTINE)iWebSocketClientThread, NULL, NULL, nullptr); CreateThread(nullptr, NULL, (LPTHREAD_START_ROUTINE)HotkeyThread, NULL, NULL, nullptr); return TRUE; } //extern "C" __declspec(dllexport) DWORD __stdcall RunScriptFile(const char *filePath) //{ // while (!luamgr) // { // Sleep(50); // } // if (luamgr) // if (strstr(filePath, "NewDevScript") != NULL) // { // luamgr->ClearCallbacks(); // luamgr->RemoveAllHooks(); // } // luamgr->ExecuteScriptFile(filePath); // return true; //} //extern "C" __declspec(dllexport) DWORD __stdcall RunLuaFunc(const char *funcName) //{ // while (!luamgr) // { // Sleep(50); // } // if (luamgr) // { // sol::protected_function f = (*luamgr->lua)[funcName]; // sol::protected_function_result result = f(); // if (!result.valid()) // { // sol::error err = result; // std::cout << err.what() << std::endl; // Logger->error(err.what()); // } // } // return true; //} //extern "C" __declspec(dllexport) LRESULT CALLBACK WndProc(int nCode, WPARAM wParam, LPARAM lParam) //{ // //std::cout << "Looks like this is working!" << std::endl; // return CallNextHookEx(0, nCode, wParam, lParam); //}; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: //InitializeCriticalSection(&critsec); DisableThreadLibraryCalls(hModule); thisDLL = hModule; CreateThread(nullptr, NULL, (LPTHREAD_START_ROUTINE)MainThread, hModule, NULL, nullptr); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }