always-on: BepInEx + winhttp always return true, no GUI toggle
- BepInEx: Patches now always-on (IsRobe/IsCharacter/HasPerk/HasOutfit true, UpdateLocked* skipped, WaitForPurchasedPetValidation skipped), GUI hidden by default, no selective checks - native winhttp: src/main.cpp minimal HookThread that waits for GameAssembly + IL2CPP domain then installPatches (no ImGui/D3D11 dummy, no AllocConsole, no libgcc dep) — fixes crash at 0xB5A02F8 strlen null - patches: hIsRobe/hIsChar etc now always true, hookUpdateLocked always bypass, retry for 60s until lobby - winhttp_proxy: runtime forwarding to C:\Windows\System32\winhttp.dll for all 26 WinHttp* (fixes Wine crash) - standalone: _patch_collectables_all now exact full sets (BarbedWires 6, Feathers 2, Tickets 7 etc) not superset 8, so HasCollectedAll* passes; diagnose checks WINEDLLOVERRIDES
This commit is contained in:
parent
c1a32f3ec3
commit
4dd7b8d393
3 changed files with 60 additions and 212 deletions
|
|
@ -38,148 +38,46 @@ namespace DevourUnlocker.BepInEx
|
|||
}
|
||||
|
||||
// Generic unlock patches — try multiple owner classes
|
||||
// Always-on: every IsRobe/IsCharacter/Has* check returns true, every UpdateLocked* is skipped
|
||||
static class Patches
|
||||
{
|
||||
[HarmonyPatch]
|
||||
class IsRobeUnlockedPatch
|
||||
{
|
||||
static System.Reflection.MethodBase TargetMethod()
|
||||
{
|
||||
var types = new[] { "NolanRankController", "LobbyController", "InventoryController", "UnlockManager" };
|
||||
foreach (var t in types) {
|
||||
var type = AccessTools.TypeByName(t);
|
||||
if (type == null) continue;
|
||||
var m = AccessTools.Method(type, "IsRobeUnlocked");
|
||||
if (m != null) { Plugin.Log?.LogInfo($"Found IsRobeUnlocked on {t}"); return m; }
|
||||
static System.Reflection.MethodBase Find(string typeName, string method) {
|
||||
var t = AccessTools.TypeByName(typeName);
|
||||
if (t==null) return null;
|
||||
var m = AccessTools.Method(t, method);
|
||||
if (m!=null) Plugin.Log?.LogInfo($"Found {typeName}.{method}");
|
||||
return m;
|
||||
}
|
||||
Plugin.Log?.LogWarning("IsRobeUnlocked not found");
|
||||
static System.Reflection.MethodBase FindAny(string method, params string[] types){
|
||||
foreach(var tn in types){ var m=Find(tn,method); if(m!=null) return m; }
|
||||
Plugin.Log?.LogWarning($"{method} not found in {string.Join(",",types)}");
|
||||
return null;
|
||||
}
|
||||
static bool Prefix(ref bool __result, object __instance, string robeName)
|
||||
{
|
||||
if (!DevourGUI.configUnlockRobes) return true;
|
||||
if (DevourGUI.robeOverrides.TryGetValue(robeName ?? "", out var v)) { __result = v; return false; }
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch]
|
||||
class IsCharacterUnlockedPatch
|
||||
{
|
||||
static System.Reflection.MethodBase TargetMethod()
|
||||
{
|
||||
var types = new[] { "NolanRankController", "LobbyController", "CharacterManager" };
|
||||
foreach (var t in types) {
|
||||
var type = AccessTools.TypeByName(t);
|
||||
if (type == null) continue;
|
||||
var m = AccessTools.Method(type, "IsCharacterUnlocked");
|
||||
if (m != null) return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
static bool Prefix(ref bool __result, string prefabName)
|
||||
{
|
||||
if (!DevourGUI.configUnlockChars) return true;
|
||||
if (DevourGUI.charOverrides.TryGetValue(prefabName ?? "", out var v)) { __result = v; return false; }
|
||||
__result = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateLocked* patches — force unlock for pets/perks/flashlights/emotes/outfits/robes
|
||||
static System.Reflection.MethodBase FindUpdate(string name) {
|
||||
var types = new[] { "LobbyController", "UILobbyController", "InventoryController", "NolanRankController" };
|
||||
foreach (var t in types) {
|
||||
var type = AccessTools.TypeByName(t);
|
||||
if (type==null) continue;
|
||||
var m = AccessTools.Method(type, name);
|
||||
if (m!=null) { Plugin.Log?.LogInfo($"Found {name} on {t}"); return m; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
[HarmonyPatch] class UpdateLockedPetsPatch { static System.Reflection.MethodBase TargetMethod()=> FindUpdate("UpdateLockedPets"); static bool Prefix()=> !DevourGUI.configUnlockPets ? true : false; }
|
||||
[HarmonyPatch] class UpdateLockedPerksPatch { static System.Reflection.MethodBase TargetMethod()=> FindUpdate("UpdateLockedPerks"); static bool Prefix()=> !DevourGUI.configUnlockPerks ? true : false; }
|
||||
[HarmonyPatch] class UpdateLockedFlashlightsPatch { static System.Reflection.MethodBase TargetMethod()=> FindUpdate("UpdateLockedFlashlights"); static bool Prefix()=> !DevourGUI.configUnlockFlashlights ? true : false; }
|
||||
[HarmonyPatch] class UpdateLockedEmotesPatch { static System.Reflection.MethodBase TargetMethod()=> FindUpdate("UpdateLockedEmotes"); static bool Prefix()=> !DevourGUI.configUnlockEmotes ? true : false; }
|
||||
[HarmonyPatch] class UpdateLockedOutfitsPatch { static System.Reflection.MethodBase TargetMethod()=> FindUpdate("UpdateLockedOutfits"); static bool Prefix()=> !DevourGUI.configUnlockOutfits ? true : false; }
|
||||
[HarmonyPatch] class UpdateLockedRobesPatch { static System.Reflection.MethodBase TargetMethod()=> FindUpdate("UpdateLockedRobes"); static bool Prefix()=> !DevourGUI.configUnlockRobes ? true : false; }
|
||||
|
||||
[HarmonyPatch] class HasPerkPatch {
|
||||
static System.Reflection.MethodBase TargetMethod(){ var t=AccessTools.TypeByName("NolanRankController"); return t==null?null:AccessTools.Method(t,"HasPerk"); }
|
||||
static bool Prefix(ref bool __result, string perkName){ if(!DevourGUI.configUnlockPerks) return true; if(DevourGUI.perkOverrides.TryGetValue(perkName??"",out var v)){__result=v; return false;} __result=true; return false;}
|
||||
}
|
||||
[HarmonyPatch] class HasOutfitPatch {
|
||||
static System.Reflection.MethodBase TargetMethod(){ var t=AccessTools.TypeByName("NolanRankController"); return t==null?null:AccessTools.Method(t,"HasOutfit"); }
|
||||
static bool Prefix(ref bool __result, string outfitName){ if(!DevourGUI.configUnlockOutfits) return true; if(DevourGUI.outfitOverrides.TryGetValue(outfitName??"",out var v)){__result=v; return false;} __result=true; return false;}
|
||||
}
|
||||
[HarmonyPatch] class IsRobeUnlockedPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("IsRobeUnlocked","NolanRankController","SurvivalLobbyController","LobbyController"); static bool Prefix(ref bool __result){ __result=true; return false; } }
|
||||
[HarmonyPatch] class IsCharacterUnlockedPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("IsCharacterUnlocked","NolanRankController","SurvivalLobbyController"); static bool Prefix(ref bool __result){ __result=true; return false; } }
|
||||
[HarmonyPatch] class HasPerkPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("HasPerk","NolanRankController"); static bool Prefix(ref bool __result){ __result=true; return false; } }
|
||||
[HarmonyPatch] class HasOutfitPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("HasOutfit","NolanRankController"); static bool Prefix(ref bool __result){ __result=true; return false; } }
|
||||
[HarmonyPatch] class HasCollectedAllPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("HasCollectedAllBarbedWires","NolanRankController"); static bool Prefix(ref bool __result){ __result=true; return false; } }
|
||||
// UpdateLocked* — skip (return false to prevent original from marking locked)
|
||||
[HarmonyPatch] class UpdateLockedPetsPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedPets","SurvivalLobbyController","LobbyController"); static bool Prefix()=> false; }
|
||||
[HarmonyPatch] class UpdateLockedPerksPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedPerks","SurvivalLobbyController"); static bool Prefix()=> false; }
|
||||
[HarmonyPatch] class UpdateLockedFlashlightsPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedFlashlights","SurvivalLobbyController"); static bool Prefix()=> false; }
|
||||
[HarmonyPatch] class UpdateLockedEmotesPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedEmotes","SurvivalLobbyController"); static bool Prefix()=> false; }
|
||||
[HarmonyPatch] class UpdateLockedOutfitsPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedOutfits","SurvivalLobbyController"); static bool Prefix()=> false; }
|
||||
[HarmonyPatch] class UpdateLockedRobesPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedRobes","SurvivalLobbyController"); static bool Prefix()=> false; }
|
||||
[HarmonyPatch] class WaitForPurchasedPetValidationPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("WaitForPurchasedPetValidation","SurvivalLobbyController"); static bool Prefix()=> false; }
|
||||
}
|
||||
|
||||
static class DevourGUI
|
||||
{
|
||||
public static bool visible = true;
|
||||
public static bool configUnlockRobes = true;
|
||||
public static bool configUnlockChars = true;
|
||||
public static bool configUnlockPerks = true;
|
||||
public static bool configUnlockPets = true;
|
||||
public static bool configUnlockFlashlights = true;
|
||||
public static bool configUnlockEmotes = true;
|
||||
public static bool configUnlockOutfits = true;
|
||||
public static System.Collections.Generic.Dictionary<string,bool> robeOverrides = new();
|
||||
public static System.Collections.Generic.Dictionary<string,bool> charOverrides = new();
|
||||
public static System.Collections.Generic.Dictionary<string,bool> perkOverrides = new();
|
||||
public static System.Collections.Generic.Dictionary<string,bool> outfitOverrides = new();
|
||||
|
||||
static string[] robes = new[] {
|
||||
"StraightJacket","Patchwork","CherryBlossom","Eggs","Poison","Web",
|
||||
"TownHard","TownNightmare","TownBooks","Horseshoes",
|
||||
"SlaughterhouseHard","SlaughterhouseNightmare","SlaughterhousePigs","BarbedWires",
|
||||
"Golden","ManorHard","ManorNightmare","ManorHeadsBuried","Feathers",
|
||||
"CarnivalHard","CarnivalNightmare","CarnivalDollHeads","Tickets",
|
||||
"Rose","Fire","Inmate","Electric","BlackWithGoldTrim","Hard","Nightmare"
|
||||
};
|
||||
static string[] chars = new[] {"Molly","Nathan","Sam","Zara","Cultist","Kai","Anna","April","Frank"};
|
||||
static string[] perks = new[] {"Acceleration","Aftershock","Conservationist","Crawler","DuracellBunny","Evader","FastWorker","FieldMedic","FirstResponder","FullyCharged","Immune","Inspired","Keymaster","Patient","Regeneration","Speedy","SupplyRunner","Trapper","Teamwork"};
|
||||
static string[] pets = new[] {"Crow","Pig","Goat","Rat","Spider","Cat","Pug"};
|
||||
static UnityEngine.Vector2 scroll;
|
||||
static string currentTab = "Robes";
|
||||
|
||||
public static bool visible = false; // always-on, GUI hidden by default (F6 to show debug)
|
||||
public static void Draw()
|
||||
{
|
||||
var rect = new UnityEngine.Rect(20, 20, 600, 640);
|
||||
var rect = new UnityEngine.Rect(20, 20, 400, 100);
|
||||
UnityEngine.GUI.Box(rect, "");
|
||||
GUILayout.BeginArea(rect);
|
||||
GUILayout.Label("DevourUnlocker v2 — BepInEx Edition (F6 toggle) — ALL categories");
|
||||
GUILayout.BeginHorizontal();
|
||||
if(GUILayout.Button("Robes")) currentTab="Robes";
|
||||
if(GUILayout.Button("Chars")) currentTab="Chars";
|
||||
if(GUILayout.Button("Perks")) currentTab="Perks";
|
||||
if(GUILayout.Button("Pets")) currentTab="Pets";
|
||||
GUILayout.EndHorizontal();
|
||||
configUnlockRobes = GUILayout.Toggle(configUnlockRobes, "Robes");
|
||||
configUnlockChars = GUILayout.Toggle(configUnlockChars, "Chars");
|
||||
configUnlockPerks = GUILayout.Toggle(configUnlockPerks, "Perks");
|
||||
configUnlockPets = GUILayout.Toggle(configUnlockPets, "Pets");
|
||||
configUnlockFlashlights = GUILayout.Toggle(configUnlockFlashlights, "Flashlights");
|
||||
configUnlockEmotes = GUILayout.Toggle(configUnlockEmotes, "Emotes");
|
||||
configUnlockOutfits = GUILayout.Toggle(configUnlockOutfits, "Outfits");
|
||||
if (GUILayout.Button("Unlock ALL categories")) { configUnlockRobes=configUnlockChars=configUnlockPerks=configUnlockPets=configUnlockFlashlights=configUnlockEmotes=configUnlockOutfits=true; robeOverrides.Clear(); charOverrides.Clear(); perkOverrides.Clear(); }
|
||||
if (GUILayout.Button("Lock ALL")) { configUnlockRobes=configUnlockChars=configUnlockPerks=configUnlockPets=configUnlockFlashlights=configUnlockEmotes=configUnlockOutfits=false; }
|
||||
string[] list = currentTab=="Robes"? robes : currentTab=="Chars"? chars : currentTab=="Perks"? perks : pets;
|
||||
var dict = currentTab=="Robes"? robeOverrides : currentTab=="Chars"? charOverrides : currentTab=="Perks"? perkOverrides : null;
|
||||
// pets use simple global toggle via UpdateLockedPets bypass, per-item not needed but show
|
||||
GUILayout.Label($"— {currentTab} —");
|
||||
scroll = GUILayout.BeginScrollView(scroll, GUILayout.Height(260));
|
||||
if(dict!=null){
|
||||
foreach (var r in list) {
|
||||
bool cur = dict.TryGetValue(r, out var ov) ? ov : true;
|
||||
bool nxt = GUILayout.Toggle(cur, r);
|
||||
if (nxt != cur) dict[r] = nxt;
|
||||
}
|
||||
} else {
|
||||
GUILayout.Label("Uses global toggle (UpdateLocked* bypass)");
|
||||
}
|
||||
GUILayout.EndScrollView();
|
||||
GUILayout.Label("DevourUnlocker — Always On (all robes/chars/perks/pets unlocked)");
|
||||
GUILayout.Label("F6 to toggle this debug window");
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
src/main.cpp
24
src/main.cpp
|
|
@ -1,13 +1,29 @@
|
|||
#include "config.hpp"
|
||||
#include "patches.hpp"
|
||||
#include "il2cpp_resolver.hpp"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <fstream>
|
||||
static void logMin(const char* m){
|
||||
char exe[MAX_PATH]; GetModuleFileNameA(nullptr,exe,MAX_PATH);
|
||||
char* s=strrchr(exe,'\\'); if(!s) s=strrchr(exe,'/');
|
||||
std::string p = s? std::string(exe,s-exe)+"\\DevourUnlocker.log":"DevourUnlocker.log";
|
||||
std::ofstream f(p,std::ios::app); f<<m<<std::endl;
|
||||
}
|
||||
static DWORD WINAPI HookThread(LPVOID){
|
||||
logMin("[DevourUnlocker] HookThread start (always-on)");
|
||||
// Wait for GameAssembly before hooking
|
||||
for(int i=0;i<100;i++){ if(GetModuleHandleA("GameAssembly.dll")) break; Sleep(100); }
|
||||
Sleep(2000); // give IL2CPP time to init
|
||||
bool ok = devour::installPatches();
|
||||
logMin(ok ? "[DevourUnlocker] HookThread: patches installed" : "[DevourUnlocker] HookThread: patches not yet, will retry via installPatches retry thread");
|
||||
return 0;
|
||||
}
|
||||
BOOL APIENTRY DllMain(HMODULE hMod, DWORD reason, LPVOID) {
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
DisableThreadLibraryCalls(hMod);
|
||||
// Minimal — do NOT hook, do NOT log, do NOT create thread.
|
||||
// The standalone collectables.json patch (patched via devour_unlocker.py) is the primary unlock.
|
||||
// This winhttp.dll exists only to satisfy WINEDLLOVERRIDES and prove load, not to crash.
|
||||
// If you need full hooks, build with -DBUILD_FULL_HOOKS=ON and use the full main.cpp
|
||||
logMin("[DevourUnlocker] DllMain attach (always-on, no ImGui)");
|
||||
CreateThread(nullptr,0,HookThread,nullptr,0,nullptr);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,88 +49,22 @@ static std::string il2cppStringToUtf8(void* ilStr) {
|
|||
return "";
|
||||
}
|
||||
|
||||
static bool __fastcall hIsRobe(void* thiz, void* robeStr, void* method) {
|
||||
auto& cfg = Config::get();
|
||||
if (!cfg.unlockRobes) {
|
||||
return oIsRobe ? oIsRobe(thiz, robeStr, method) : false;
|
||||
}
|
||||
std::string name = il2cppStringToUtf8(robeStr);
|
||||
auto it = cfg.robeOverrides.find(name);
|
||||
if (it != cfg.robeOverrides.end()) return it->second;
|
||||
// Log once per unique robe
|
||||
static std::unordered_map<std::string,int> seen;
|
||||
if (!seen[name]++) std::cout << "[DevourUnlocker] Robe unlocked: " << name << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __fastcall hIsChar(void* thiz, void* charStr, void* method) {
|
||||
auto& cfg = Config::get();
|
||||
if (!cfg.unlockCharacters) {
|
||||
return oIsChar ? oIsChar(thiz, charStr, method) : false;
|
||||
}
|
||||
std::string name = il2cppStringToUtf8(charStr);
|
||||
auto it = cfg.characterOverrides.find(name);
|
||||
if (it != cfg.characterOverrides.end()) return it->second;
|
||||
static std::unordered_map<std::string,int> seen;
|
||||
if (!seen[name]++) std::cout << "[DevourUnlocker] Character unlocked: " << name << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __fastcall hHasPerk(void* thiz, void* perkStr, void* method) {
|
||||
auto& cfg = Config::get();
|
||||
if (!cfg.unlockPerks) return oHasPerk ? oHasPerk(thiz, perkStr, method) : false;
|
||||
std::string name = il2cppStringToUtf8(perkStr);
|
||||
auto it = cfg.perkOverrides.find(name);
|
||||
if (it != cfg.perkOverrides.end()) return it->second;
|
||||
return true;
|
||||
}
|
||||
static bool __fastcall hHasOutfit(void* thiz, void* outfitStr, void* method) {
|
||||
auto& cfg = Config::get();
|
||||
if (!cfg.unlockOutfits) return oHasOutfit ? oHasOutfit(thiz, outfitStr, method) : false;
|
||||
std::string name = il2cppStringToUtf8(outfitStr);
|
||||
auto it = cfg.outfitOverrides.find(name);
|
||||
if (it != cfg.outfitOverrides.end()) return it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// UpdateLocked* hooks: force to mark all as unlocked, then skip original caller that sets locked flag
|
||||
static void __fastcall hUpdateLockedPets(void* thiz, void* method) {
|
||||
auto& cfg = Config::get();
|
||||
if (!cfg.unlockPets) {
|
||||
return;
|
||||
}
|
||||
std::cout << "[DevourUnlocker] UpdateLockedPets bypassed (pets unlocked)\n";
|
||||
logPatch("[DevourUnlocker] UpdateLockedPets bypassed");
|
||||
}
|
||||
static void __fastcall hWaitForPurchasedPet(void* thiz, void* method) {
|
||||
if (!Config::get().unlockPets) return;
|
||||
std::cout << "[DevourUnlocker] WaitForPurchasedPetValidation bypassed\n";
|
||||
logPatch("[DevourUnlocker] WaitForPurchasedPetValidation bypassed");
|
||||
}
|
||||
static void __fastcall hUpdateLockedPerks(void* thiz, void* method) {
|
||||
if (!Config::get().unlockPerks) return;
|
||||
std::cout << "[DevourUnlocker] UpdateLockedPerks bypassed\n";
|
||||
}
|
||||
static void __fastcall hUpdateLockedFlashlights(void* thiz, void* method) {
|
||||
if (!Config::get().unlockFlashlights) return;
|
||||
std::cout << "[DevourUnlocker] UpdateLockedFlashlights bypassed\n";
|
||||
}
|
||||
static void __fastcall hUpdateLockedEmotes(void* thiz, void* method) {
|
||||
if (!Config::get().unlockEmotes) return;
|
||||
std::cout << "[DevourUnlocker] UpdateLockedEmotes bypassed\n";
|
||||
}
|
||||
static void __fastcall hUpdateLockedOutfits(void* thiz, void* method) {
|
||||
if (!Config::get().unlockOutfits) return;
|
||||
std::cout << "[DevourUnlocker] UpdateLockedOutfits bypassed\n";
|
||||
}
|
||||
static void __fastcall hUpdateLockedRobes(void* thiz, void* method) {
|
||||
if (!Config::get().unlockRobes) return;
|
||||
std::cout << "[DevourUnlocker] UpdateLockedRobes bypassed\n";
|
||||
}
|
||||
static bool __fastcall hIsRobe(void* thiz, void* robeStr, void* method) { return true; }
|
||||
static bool __fastcall hIsChar(void* thiz, void* charStr, void* method) { return true; }
|
||||
static bool __fastcall hHasPerk(void* thiz, void* perkStr, void* method) { return true; }
|
||||
static bool __fastcall hHasOutfit(void* thiz, void* outfitStr, void* method) { return true; }
|
||||
// Always-on: every UpdateLocked* is bypassed
|
||||
static void __fastcall hUpdateLockedPets(void* thiz, void* method) { logPatch("[DevourUnlocker] UpdateLockedPets bypassed (always-on)"); }
|
||||
static void __fastcall hWaitForPurchasedPet(void* thiz, void* method) { logPatch("[DevourUnlocker] WaitForPurchasedPetValidation bypassed (always-on)"); }
|
||||
static void __fastcall hUpdateLockedPerks(void* thiz, void* method) { logPatch("[DevourUnlocker] UpdateLockedPerks bypassed (always-on)"); }
|
||||
static void __fastcall hUpdateLockedFlashlights(void* thiz, void* method) { logPatch("[DevourUnlocker] UpdateLockedFlashlights bypassed"); }
|
||||
static void __fastcall hUpdateLockedEmotes(void* thiz, void* method) { logPatch("[DevourUnlocker] UpdateLockedEmotes bypassed"); }
|
||||
static void __fastcall hUpdateLockedOutfits(void* thiz, void* method) { logPatch("[DevourUnlocker] UpdateLockedOutfits bypassed"); }
|
||||
static void __fastcall hUpdateLockedRobes(void* thiz, void* method) { logPatch("[DevourUnlocker] UpdateLockedRobes bypassed"); }
|
||||
|
||||
static bool hookUpdateLocked(void* addr, const char* name, bool shouldUnlock, void (__fastcall *hook)(void*, void*)) {
|
||||
if (!addr) { std::cerr << "[DevourUnlocker] " << name << " not found\n"; logPatch((std::string("[DevourUnlocker] ")+name+" not found").c_str()); return false; }
|
||||
if (!shouldUnlock) return false;
|
||||
(void)shouldUnlock; // always-on
|
||||
void* orig = nullptr;
|
||||
if (MH_CreateHook(addr, (void*)hook, &orig) == MH_OK) {
|
||||
MH_EnableHook(addr);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue