diff --git a/MK11Hook/MK11Hook.rc b/MK11Hook/MK11Hook.rc
index 0d32fcd..21081ca 100644
Binary files a/MK11Hook/MK11Hook.rc and b/MK11Hook/MK11Hook.rc differ
diff --git a/MK11Hook/MK11Hook.vcxproj b/MK11Hook/MK11Hook.vcxproj
index 1e4f9e2..f8c7729 100644
--- a/MK11Hook/MK11Hook.vcxproj
+++ b/MK11Hook/MK11Hook.vcxproj
@@ -215,6 +215,7 @@
+
diff --git a/MK11Hook/MK11Hook.vcxproj.filters b/MK11Hook/MK11Hook.vcxproj.filters
index 8cd5c40..b20ccc7 100644
--- a/MK11Hook/MK11Hook.vcxproj.filters
+++ b/MK11Hook/MK11Hook.vcxproj.filters
@@ -407,6 +407,9 @@
Header Files\mk
+
+ Header Files\plugin
+
diff --git a/MK11Hook/dllmain.cpp b/MK11Hook/dllmain.cpp
index 70f1956..31b43d3 100644
--- a/MK11Hook/dllmain.cpp
+++ b/MK11Hook/dllmain.cpp
@@ -49,7 +49,7 @@ void OnInitializeHook()
freopen("CONOUT$", "w", stderr);
}
- eLog::Message(__FUNCTION__, "INFO: MK11Hook Begin!");
+ eLog::Message(__FUNCTION__, "INFO: MK11Hook (%s | %s) Begin!", MK11HOOK_VERSION, __DATE__);
eLog::Message(__FUNCTION__, "INFO: Is DirectX12 - %s", IsDX12() ? "Yes" : "No");
Notifications->Init();
@@ -71,17 +71,17 @@ void OnInitializeHook()
InjectHook(_pattern(PATID_CameraPositionHook), tramp->Jump(&MKCamera::HookedSetPosition));
InjectHook(_pattern(PATID_CameraRotationHook), tramp->Jump(&MKCamera::HookedSetRotation));
- InjectHook(_pattern(PATID_SetSelectScreen_Hook), tramp->Jump(SetSelectScreen_Hook), PATCH_JUMP);
+ InjectHook(_pattern(PATID_SetSelectScreen_Hook), tramp->Jump(SetSelectScreen_Hook), HookType::Jump);
InjectHook(_pattern(PATID_SetCharacterLadder_Hook), tramp->Jump(SetCharacterLadder_Hook));
- InjectHook(_pattern(PATID_ReadPropertyValue_Hook), tramp->Jump(ReadPropertyValue_Hook), PATCH_JUMP);
+ InjectHook(_pattern(PATID_ReadPropertyValue_Hook), tramp->Jump(ReadPropertyValue_Hook), HookType::Jump);
InjectHook(_pattern(PATID_SetProperty_Hook), tramp->Jump(SetProperty));
InjectHook(_pattern(PATID_Dispatch_Hook), tramp->Jump(Dispatch_Hook));
if (SettingsMgr->bMakeAllAbilities1Slot)
- InjectHook(_pattern(PATID_1SlotAbilitiesHook), tramp->Jump(GenericTrueReturn), PATCH_JUMP);
+ InjectHook(_pattern(PATID_1SlotAbilitiesHook), tramp->Jump(GenericTrueReturn), HookType::Jump);
InjectHook(_pattern(PATID_SetKryptCharacter_Hook), tramp->Jump(SetKryptCharacter));
InjectHook(_pattern(PATID_SetKryptCharacterL_Hook), tramp->Jump(SetKryptCharacterL));
@@ -89,7 +89,13 @@ void OnInitializeHook()
ReadCall(_pattern(PATID_ProcessDOFSettings), pProcessDOFSettings);
- InjectHook(_pattern(PATID_ProcessDOFSettings), tramp->Jump(ProcessDOFSettings), PATCH_CALL);
+ InjectHook(_pattern(PATID_ProcessDOFSettings), tramp->Jump(ProcessDOFSettings));
+
+ ReadCall(_pattern(PATID_FightStartupAddModifiers), pPluginFightStartupAddModifiers);
+ InjectHook(_pattern(PATID_FightStartupAddModifiers), tramp->Jump(PluginFightStartupAddModifiers));
+
+ MH_CreateHook((void*)_pattern(PATID_FightStartupQueueModifiers), &PluginFightStartupQueueModifiers, (void**)&pPluginFightStartupQueueModifiers);
+ MH_EnableHook((void*)_pattern(PATID_FightStartupQueueModifiers));
//gamepad
if (SettingsMgr->bEnableGamepadSupport)
@@ -100,7 +106,7 @@ void OnInitializeHook()
uintptr_t xinput_addr = _pattern(PATID_XInputGetState_Hook);
xinput_addr += *(unsigned int*)(xinput_addr)+4;
- InjectHook(xinput_addr, tramp->Jump(XInputGetState_Hook), PATCH_JUMP);
+ InjectHook(xinput_addr, tramp->Jump(XInputGetState_Hook), HookType::Jump);
}
}
@@ -169,6 +175,7 @@ extern "C"
{
__declspec(dllexport) void InitializeASI()
{
+ MH_Initialize();
eLog::Initialize();
if (ValidateGameVersion())
diff --git a/MK11Hook/helper/eAbilityNames.cpp b/MK11Hook/helper/eAbilityNames.cpp
index f5c1f83..123c601 100644
--- a/MK11Hook/helper/eAbilityNames.cpp
+++ b/MK11Hook/helper/eAbilityNames.cpp
@@ -620,16 +620,21 @@ void eAbiltityNames::Init()
}
-eAbilityNameEntry eAbiltityNames::Get(const char * chrName)
+eAbilityNameEntry* eAbiltityNames::Get(const char * chrName)
{
- std::string input = chrName;
- eAbilityNameEntry result;
+ std::string inName(chrName);
+ std::transform(inName.begin(), inName.end(), inName.begin(), std::tolower);
+
+ eAbilityNameEntry* result = nullptr;
for (unsigned int i = 0; i < m_aAbilityNames.size(); i++)
{
- if (m_aAbilityNames[i].chr == input)
+ std::string abilityName(m_aAbilityNames[i].chr);
+ std::transform(abilityName.begin(), abilityName.end(), abilityName.begin(), std::tolower);
+
+ if (abilityName == inName)
{
- result = m_aAbilityNames[i];
+ result = &m_aAbilityNames[i];
break;
}
}
@@ -637,13 +642,23 @@ eAbilityNameEntry eAbiltityNames::Get(const char * chrName)
return result;
}
+int eAbiltityNames::GetAmount(eAbilityNameEntry* ability)
+{
+ int amount = 0;
+ for (int i = 0; i < TOTAL_ABILITIES; i++)
+ if (ability->abNames[i])
+ amount++;
+
+ return amount;
+}
+
eAbilityNameEntry::eAbilityNameEntry()
{
chr = "char_null";
for (int i = 0; i < TOTAL_ABILITIES; i++)
{
- abNames[i] = "";
+ abNames[i] = nullptr;
}
}
diff --git a/MK11Hook/helper/eAbilityNames.h b/MK11Hook/helper/eAbilityNames.h
index d55784a..266aa54 100644
--- a/MK11Hook/helper/eAbilityNames.h
+++ b/MK11Hook/helper/eAbilityNames.h
@@ -15,6 +15,7 @@ class eAbiltityNames {
public:
static std::vector m_aAbilityNames;
static void Init();
- static eAbilityNameEntry Get(const char* chrName);
+ static eAbilityNameEntry* Get(const char* chrName);
+ static int GetAmount(eAbilityNameEntry* ability);
};
\ No newline at end of file
diff --git a/MK11Hook/mk/Engine.cpp b/MK11Hook/mk/Engine.cpp
index 132ff75..7e2a95f 100644
--- a/MK11Hook/mk/Engine.cpp
+++ b/MK11Hook/mk/Engine.cpp
@@ -104,3 +104,22 @@ void SetCharacterMKX(PLAYER_NUM plr, char* name)
CharacterDefinition* chr = (CharacterDefinition*)(ptr + 216);
chr->Set(name, 0, 0);
}
+
+void SetCharacterAI(PLAYER_NUM plr, char* script, int level)
+{
+ PlayerInfo* info = GetInfo(plr);
+
+ if (!info)
+ return;
+
+ info->MakeDrone();
+
+ AIDrone* drone = info->GetDrone();
+
+ if (!drone)
+ return;
+
+ drone->Set(script, 0);
+ float difficultyLevel = level;
+ drone->SetLevel(difficultyLevel);
+}
diff --git a/MK11Hook/mk/Engine.h b/MK11Hook/mk/Engine.h
index f84a134..dbff22c 100644
--- a/MK11Hook/mk/Engine.h
+++ b/MK11Hook/mk/Engine.h
@@ -24,4 +24,5 @@ unsigned int _hash(const char* input);
void GetCharacterPosition(FVector* vec, PLAYER_NUM plr);
char* GetCharacterName(PLAYER_NUM plr);
-void SetCharacterMKX(PLAYER_NUM plr, char* name);
\ No newline at end of file
+void SetCharacterMKX(PLAYER_NUM plr, char* name);
+void SetCharacterAI(PLAYER_NUM plr, char* script, int level);
\ No newline at end of file
diff --git a/MK11Hook/mk/MKCamera.cpp b/MK11Hook/mk/MKCamera.cpp
index 85cc113..6d683f8 100644
--- a/MK11Hook/mk/MKCamera.cpp
+++ b/MK11Hook/mk/MKCamera.cpp
@@ -263,6 +263,10 @@ void MKCamera::HookedSetRotation(FRotator * rot)
rot->Pitch += 1228;
TheMenu->camRot = *rot;
break;
+ case CAMERA_9_16:
+ rot->Roll += (int)(float)((float)(90.0 * 32767.0) / 180.0);
+ TheMenu->camRot = *rot;
+ break;
}
}
SetRotation(rot);
diff --git a/MK11Hook/mk/MKModifier.cpp b/MK11Hook/mk/MKModifier.cpp
index 9310497..4823856 100644
--- a/MK11Hook/mk/MKModifier.cpp
+++ b/MK11Hook/mk/MKModifier.cpp
@@ -1,4 +1,5 @@
#include "MKModifier.h"
+#include "Engine.h"
TagAssistModifier::TagAssistModifier(const char * character)
@@ -15,26 +16,26 @@ void TagAssistModifier::Activate(PlayerInfo* info)
((void(__fastcall*)(BaseModifier*, PlayerInfo*))pat)(this, info);
}
-TagAssistModifierObject * TagAssistModifier::CreateObject()
+Modifier* MKModifier::CreateModifier(const char* name)
{
- static uintptr_t pat = _pattern(PATID_TagAssistModifier_CreateObject);
- if (pat)
- return ((TagAssistModifierObject*(__fastcall*)(BaseModifier*))pat)(this);
- return nullptr;
+ return new Modifier(name);
}
-void MKModifier::ActivateModifier(BaseModifier * modifier, MKCharacter * obj)
+void MKModifier::ActivateModifier(Modifier* mod, int playerFlags)
{
- static uintptr_t pat = _pattern(PATID_MKModifier_ActivateModifier);
- if (pat)
- ((void(__fastcall*)(MKModifier*, BaseModifier*, MKCharacter*))pat)(this, modifier, obj);
-}
+ ModifierObject obj(mod, playerFlags);
-void TagAssistModifierObject::Activate(MKCharacter* obj)
-{
- static uintptr_t pat = _pattern(PATID_TagAssistModifierObject_Activate);
- if (pat)
- ((void(__fastcall*)(TagAssistModifierObject*, MKCharacter*))pat)(this, obj);
+ MKCharacter* p1 = GetObj(PLAYER1);
+
+ if (!p1)
+ return;
+
+ MKCharacter* p2 = GetObj(PLAYER2);
+
+ if (!p2)
+ return;
+
+ obj.Activate(p1, p2);
}
MKModifier* GetModifierManager()
@@ -58,4 +59,32 @@ void LoadModifierAssets()
static uintptr_t pat = _pattern(PATID_LoadModifierAssets);
if (pat)
((void(__fastcall*)(FGGameInfo*, bool))pat)(GetGameInfo(), 1);
-}
\ No newline at end of file
+}
+
+Modifier::Modifier(const char* name)
+{
+ static uintptr_t pat = _pattern(PATID_MKModifier_Constructor);
+ if (pat)
+ ((void(__fastcall*)(BaseModifier*, const char*, int, int64, int64))pat)(this, name, 1, 0, 0);
+}
+
+void Modifier::GetAssetPath(TArray& path)
+{
+ static uintptr_t pat = _pattern(PATID_MKModifier_GetAssetPath);
+ if (pat)
+ ((void(__fastcall*)(Modifier*, TArray&))pat)(this, path);
+}
+
+ModifierObject::ModifierObject(Modifier* modifier, int flags)
+{
+ static uintptr_t pat = _pattern(PATID_MKModifierObject_Constructor);
+ if (pat)
+ ((void(__fastcall*)(ModifierObject*, BaseModifier*, int))pat)(this, modifier, flags);
+}
+
+void ModifierObject::Activate(MKCharacter* p1, MKCharacter* p2)
+{
+ static uintptr_t pat = _pattern(PATID_MKModifierObject_Activate);
+ if (pat)
+ ((void(__fastcall*)(ModifierObject*, MKCharacter*, MKCharacter*))pat)(this, p1, p2);
+}
diff --git a/MK11Hook/mk/MKModifier.h b/MK11Hook/mk/MKModifier.h
index abb79f1..646a5aa 100644
--- a/MK11Hook/mk/MKModifier.h
+++ b/MK11Hook/mk/MKModifier.h
@@ -1,28 +1,43 @@
#pragma once
#include "../mk/MKCharacter.h"
#include "../mk/PlayerInfo.h"
+#include "../unreal/TArray.h"
#include "../utils.h"
class BaseModifier {
public:
- char data[96] = {};
+ char data[112] = {};
};
-class TagAssistModifierObject {
+class Modifier : public BaseModifier {
public:
- void Activate(MKCharacter* obj);
+ Modifier(const char* name);
+
+ void GetAssetPath(TArray& path);
};
+class ModifierObject {
+public:
+ char data[512] = {};
+
+ ModifierObject(Modifier* modifier, int flags);
+
+ void Activate(MKCharacter* p1, MKCharacter* p2);
+};
+
+
+
+
class TagAssistModifier : public BaseModifier {
public:
TagAssistModifier(const char* character);
void Activate(PlayerInfo* info);
- TagAssistModifierObject* CreateObject();
};
class MKModifier {
public:
- void ActivateModifier(BaseModifier* modifier, MKCharacter* obj);
+ static Modifier* CreateModifier(const char* name);
+ static void ActivateModifier(Modifier* mod, int playerFlags);
};
diff --git a/MK11Hook/mk/PlayerInfo.cpp b/MK11Hook/mk/PlayerInfo.cpp
index 6196f8f..6b84dba 100644
--- a/MK11Hook/mk/PlayerInfo.cpp
+++ b/MK11Hook/mk/PlayerInfo.cpp
@@ -28,6 +28,13 @@ float PlayerInfo::GetMeter(eMeterValues type)
return *(float*)(meter_ptr + 4);
}
+void PlayerInfo::MakeDrone()
+{
+ static uintptr_t pat = _pattern(PATID_PlayerInfo_MakeDrone);
+ if (pat)
+ ((void(__fastcall*)(PlayerInfo*))pat)(this);
+}
+
HitCounter PlayerInfo::GetHits()
{
return *(HitCounter*)((int64)this + 0x430);
@@ -47,3 +54,10 @@ void AIDrone::Set(const char* script, int unk)
if (pat)
((void(__fastcall*)(AIDrone*, const char*, int))pat)(this, script, unk);
}
+
+void AIDrone::SetLevel(float level)
+{
+ static uintptr_t pat = _pattern(PATID_AIDrone_SetLevel);
+ if (pat)
+ ((void(__fastcall*)(AIDrone*, float))pat)(this, level);
+}
diff --git a/MK11Hook/mk/PlayerInfo.h b/MK11Hook/mk/PlayerInfo.h
index 1191dc3..95944df 100644
--- a/MK11Hook/mk/PlayerInfo.h
+++ b/MK11Hook/mk/PlayerInfo.h
@@ -46,6 +46,7 @@ struct Gamepad {
class AIDrone {
public:
void Set(const char* script, int unk);
+ void SetLevel(float level);
};
class PlayerInfo {
@@ -58,6 +59,8 @@ class PlayerInfo {
void RefreshMeter(bool value);
float GetMeter(eMeterValues type);
+ void MakeDrone();
+
HitCounter GetHits();
AIDrone* GetDrone();
diff --git a/MK11Hook/plugin/Hooks.cpp b/MK11Hook/plugin/Hooks.cpp
index ffd297c..2b08df2 100644
--- a/MK11Hook/plugin/Hooks.cpp
+++ b/MK11Hook/plugin/Hooks.cpp
@@ -2,8 +2,9 @@
int64 hud_property = 0;
-void(__fastcall* pProcessDOFSettings)(int64, int64, int64, int64) = 0;
-
+void(__fastcall* pProcessDOFSettings)(int64, int64, int64, int64) = nullptr;
+void(*pPluginFightStartupAddModifiers)() = nullptr;
+void(*pPluginFightStartupQueueModifiers)(int64, int64) = nullptr;
void ProcessDOFSettings(int64 settings, int64 a2, int64 newSettings, int64 a4)
{
@@ -169,7 +170,10 @@ void PluginDispatch()
if (TheMenu->m_bAIDroneModifierP1)
{
if (AIDrone* drone = p1_info->GetDrone())
+ {
drone->Set(TheMenu->szPlayer1AI, 0);
+ drone->SetLevel(TheMenu->m_nAIDroneLevelP1);
+ }
}
if (TheMenu->m_bEasyKBsP1)
@@ -251,7 +255,10 @@ void PluginDispatch()
if (TheMenu->m_bAIDroneModifierP2)
{
if (AIDrone* drone = p2_info->GetDrone())
+ {
drone->Set(TheMenu->szPlayer2AI, 0);
+ drone->SetLevel(TheMenu->m_nAIDroneLevelP2);
+ }
}
@@ -328,13 +335,11 @@ void PluginDispatch()
void PluginFightStartup()
{
- printf("MK11Hook::Info() | Starting a new fight!\n");
+ eLog::Message("MK11Hook::Info()", "Starting a new fight!");
TheMenu->m_bCustomCameraPos = false;
TheMenu->m_bCustomCameraRot = false;
TheMenu->m_bYObtained = false;
-
-
if (TheMenu->m_bStageModifier)
GetGameInfo()->SetStage(TheMenu->szStageModifierStage);
@@ -354,34 +359,94 @@ void PluginFightStartup()
TagAssistModifier tag(TheMenu->szPlayer1TagAssistCharacter);
tag.Activate(GetInfo(PLAYER1));
- TagAssistModifierObject* obj = tag.CreateObject();
-
- if (obj)
- obj->Activate(GetObj(PLAYER1));
-
- GetModifierManager()->ActivateModifier(&tag, GetObj(PLAYER1));
LoadModifierAssets();
- printf("MK11Hook::Info() | P1 Tag Assist: %s\n", TheMenu->szPlayer1TagAssistCharacter);
+ eLog::Message("MK11Hook::Info()", "P1 Tag Assist: %s", TheMenu->szPlayer1TagAssistCharacter);
}
if (TheMenu->m_bTagAssistP2)
{
TagAssistModifier tag(TheMenu->szPlayer2TagAssistCharacter);
tag.Activate(GetInfo(PLAYER2));
- TagAssistModifierObject* obj = tag.CreateObject();
-
- if (obj)
- obj->Activate(GetObj(PLAYER2));
-
- GetModifierManager()->ActivateModifier(&tag, GetObj(PLAYER2));
LoadModifierAssets();
- printf("MK11Hook::Info() | P2 Tag Assist: %s\n", TheMenu->szPlayer2TagAssistCharacter);
+ eLog::Message("MK11Hook::Info()", "P2 Tag Assist: %s", TheMenu->szPlayer2TagAssistCharacter);
}
+
}
-
printf("MK11Hook::Info() | %s VS %s\n", GetCharacterName(PLAYER1), GetCharacterName(PLAYER2));
PluginInterface::OnFightStartup();
}
+
+void PluginFightStartupAddModifiers()
+{
+ if (TheMenu->m_bAIDroneModifierP1)
+ SetCharacterAI(PLAYER1, TheMenu->szPlayer1AI, TheMenu->m_nAIDroneLevelP1);
+ if (TheMenu->m_bAIDroneModifierP2)
+ SetCharacterAI(PLAYER2, TheMenu->szPlayer2AI, TheMenu->m_nAIDroneLevelP2);
+
+ if (!TheMenu->m_bAddGlobalModifiers)
+ return;
+
+ unsigned int numModifiers = TheMenu->m_ModifiersList.size();
+
+ std::string modifiersNames = "";
+ for (int i = 0; i < numModifiers; i++)
+ {
+ ModifierEntry& modifier = TheMenu->m_ModifiersList[i];
+
+ modifiersNames += modifier.name.c_str();
+ modifiersNames += "(";
+ if (modifier.flag & ModifierEntryFlag_P1)
+ modifiersNames += "P1";
+ if (modifier.flag & ModifierEntryFlag_P2)
+ modifiersNames += "P2";
+ modifiersNames += ")";
+ if (!(i == numModifiers - 1))
+ modifiersNames += ",";
+ }
+
+ eLog::Message("MK11Hook::Info()", "Used modifiers: %s", modifiersNames.c_str());
+
+ for (int i = 0; i < numModifiers; i++)
+ {
+ ModifierEntry& modifier = TheMenu->m_ModifiersList[i];
+
+ if (!modifier.modifierDefinition)
+ continue;
+
+ MKModifier::ActivateModifier(modifier.modifierDefinition, modifier.flag);
+ }
+
+ pPluginFightStartupAddModifiers();
+}
+
+void PluginFightStartupQueueModifiers(int64 ptr, int64 pathArray)
+{
+ if (TheMenu->m_bAddGlobalModifiers)
+ {
+ unsigned int numModifiers = TheMenu->m_ModifiersList.size();
+
+ for (int i = 0; i < numModifiers; i++)
+ {
+ ModifierEntry& modifier = TheMenu->m_ModifiersList[i];
+ modifier.modifierDefinition = MKModifier::CreateModifier(modifier.name.c_str());
+
+ if (modifier.modifierDefinition)
+ {
+ TArray path;
+ modifier.modifierDefinition->GetAssetPath(path);
+
+ static uintptr_t pat = _pattern(PATID_TArray_AddString);
+ if (pat)
+ ((void(__fastcall*)(int64, int64))pat)(pathArray, (int64)&path);
+ }
+ }
+ }
+
+
+
+ if (pPluginFightStartupQueueModifiers)
+ pPluginFightStartupQueueModifiers(ptr, pathArray);
+}
diff --git a/MK11Hook/plugin/Hooks.h b/MK11Hook/plugin/Hooks.h
index f5ea257..5f7a03f 100644
--- a/MK11Hook/plugin/Hooks.h
+++ b/MK11Hook/plugin/Hooks.h
@@ -28,4 +28,9 @@ void SetKryptCharacterClass(int64 ptr, char* name, int unk);
void PluginDispatch();
-void PluginFightStartup();
\ No newline at end of file
+void PluginFightStartup();
+void PluginFightStartupAddModifiers();
+void PluginFightStartupQueueModifiers(int64 ptr, int64 pathArray);
+
+extern void(*pPluginFightStartupAddModifiers)();
+extern void(*pPluginFightStartupQueueModifiers)(int64, int64);
diff --git a/MK11Hook/plugin/Menu.cpp b/MK11Hook/plugin/Menu.cpp
index f9aae5b..050b90e 100644
--- a/MK11Hook/plugin/Menu.cpp
+++ b/MK11Hook/plugin/Menu.cpp
@@ -5,11 +5,13 @@
#include "../helper/eKeyboardMan.h"
#include "../helper/eMouse.h"
#include "../mk/Scaleform.h"
+#include "../mk/MKModifier.h"
#include "../gui/notifications.h"
#include "../gui/imgui/imgui.h"
#include "../gui/gui_impl.h"
+#include
#include
#include
#include
@@ -17,10 +19,9 @@
using namespace Memory::VP;
-static int64 timer = GetTickCount64();
-static int64 func_timer = GetTickCount64();
-char textBuffer[260] = {};
+std::random_device rd;
+std::mt19937 mt(rd());
const char* szCharacters[] = {
// place npcs first for easy access
@@ -622,8 +623,10 @@ const char* szCameraModes[TOTAL_CUSTOM_CAMERAS] = {
"First Person",
"First Person Mid",
"Injustice 2",
- "Head Perspective"
+ "Head Perspective",
+ "9:16",
};
+
const char* szCharClasses[TOTAL_CHARACTER_CLASSES] = {
"Base",
"TestCharacters",
@@ -1168,7 +1171,6 @@ void MK11Menu::DrawModifiersTab()
ImGui::Separator();
ImGui::Checkbox("Player 2 Tag Assist Modifier", &m_bTagAssistP2);
-
if (ImGui::BeginCombo("Player 2 Tag Assist Character", szPlayer2TagAssistCharacter))
{
for (int n = 0; n < IM_ARRAYSIZE(szKryptCharacters); n++)
@@ -1190,67 +1192,7 @@ void MK11Menu::DrawModifiersTab()
}
if (ImGui::BeginTabItem("Abilities"))
{
- ImGui::Checkbox("Player 1 Custom Abilities", &m_bP1CustomAbilities);
- ImGui::SameLine(); ShowHelpMarker("Set these on select screen! Changing these in game will make moves locked.");
- ImGui::Separator();
-
-
- for (int i = 0; i < sizeof(m_P1Abilities) / sizeof(m_P1Abilities[0]); i++)
- {
- sprintf(textBuffer, "Ability %d", i + 1);
-
- ImGui::Checkbox(textBuffer, &m_P1Abilities[i]);
-
- if (i % 2 == 0)
- ImGui::SameLine();
- }
-
-
- if (GetObj(PLAYER1))
- {
- if (ImGui::Button("Get##p1"))
- {
- int abilities = GetObj(PLAYER1)->GetAbility();
-
- for (int i = 0; i < sizeof(m_P1Abilities) / sizeof(m_P1Abilities[0]); i++)
- {
- int id = (int)pow(2, i);
- m_P1Abilities[i] = abilities & id;
- }
- }
-
- }
- ImGui::Separator();
- ImGui::Checkbox("Player 2 Custom Abilities", &m_bP2CustomAbilities);
- ImGui::Separator();
-
- for (int i = 0; i < sizeof(m_P2Abilities) / sizeof(m_P2Abilities[0]); i++)
- {
- int val = (int)pow(2, i);
-
- sprintf(textBuffer, "Ability %d##p2", i + 1);
-
- ImGui::Checkbox(textBuffer, &m_P2Abilities[i]);
-
- if (i % 2 == 0)
- ImGui::SameLine();
- }
-
- if (GetObj(PLAYER2))
- {
- if (ImGui::Button("Get##p2"))
- {
- int abilities = GetObj(PLAYER2)->GetAbility();
-
- for (int i = 0; i < sizeof(m_P2Abilities) / sizeof(m_P2Abilities[0]); i++)
- {
- int id = (int)pow(2, i);
- m_P2Abilities[i] = abilities & id;
- }
- }
-
- }
-
+ DrawModifiers_AbilityTab();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Skeleton"))
@@ -1381,7 +1323,7 @@ void MK11Menu::DrawModifiersTab()
}
if (ImGui::BeginTabItem("AI"))
{
- ImGui::TextWrapped("This will only change existing AI's script, it will not make human character be controlled by AI.");
+ ImGui::TextWrapped("Reload match to change if players are AI controlled.");
ImGui::Separator();
ImGui::Checkbox("Change Player 1 AI", &m_bAIDroneModifierP1);
@@ -1399,6 +1341,7 @@ void MK11Menu::DrawModifiersTab()
ImGui::EndCombo();
}
+ ImGui::SliderInt("Player 1 AI Level", &m_nAIDroneLevelP1, 0, 19);
ImGui::Separator();
ImGui::Checkbox("Change Player 2 AI", &m_bAIDroneModifierP2);
@@ -1415,6 +1358,140 @@ void MK11Menu::DrawModifiersTab()
}
ImGui::EndCombo();
}
+ ImGui::SliderInt("Player 2 AI Level", &m_nAIDroneLevelP2, 0, 19);
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Tower Modifiers"))
+ {
+ ImGui::TextWrapped("Add modifiers in game and reload match to prevent potential crashes.");
+ ImGui::Separator();
+ ImGui::Checkbox("Add Tower Modifiers", &m_bAddGlobalModifiers);
+ ImGui::Separator();
+
+ enum EModifierFlagType {
+ ModifierFlagType_Both,
+ ModifierFlagType_P1Only,
+ ModifierFlagType_P2Only,
+ };
+ static int flagType = ModifierFlagType_Both;
+
+
+ ImGui::TextWrapped("Target");
+ ImGui::Separator();
+ ImGui::RadioButton("Both", &flagType, ModifierFlagType_Both); ImGui::SameLine();
+ ImGui::RadioButton("Player 1 Only", &flagType, ModifierFlagType_P1Only); ImGui::SameLine();
+ ImGui::RadioButton("Player 2 Only", &flagType, ModifierFlagType_P2Only);
+ ImGui::Separator();
+
+ static char modifierName[256] = {};
+ static ImGuiTextFilter filter;
+ ImGui::Text("Search Modifiers");
+ ImGui::PushItemWidth(-FLT_MIN);
+ filter.Draw("##modlist");
+ ImGui::PopItemWidth();
+ ImGui::BeginChild("##list", { 0, 125.0f }, true);
+ {
+
+ for (int i = 0; i < NUM_MODIFIERS; i++)
+ {
+ if (filter.PassFilter(szModifiers[i]))
+ {
+ bool is_selected = (modifierName == szModifiers[i]);
+ if (ImGui::Selectable(szModifiers[i], is_selected))
+ {
+ sprintf(modifierName, "%s", szModifiers[i]);
+ }
+ }
+
+
+ }
+ }
+ ImGui::EndChild();
+ if (strlen(modifierName) > 0)
+ ImGui::TextWrapped("Selected: %s", modifierName);
+ if (ImGui::Button("Add", { -FLT_MIN, 0 }))
+ {
+ ModifierEntry entry = {};
+ entry.name = modifierName;
+ switch (flagType)
+ {
+ case ModifierFlagType_Both:
+ entry.flag = ModifierEntryFlag_P1 | ModifierEntryFlag_P2;
+ entry.bothPlayers = true;
+ break;
+ case ModifierFlagType_P1Only:
+ entry.flag = ModifierEntryFlag_P1;
+ entry.bothPlayers = false;
+ break;
+ case ModifierFlagType_P2Only:
+ entry.flag = ModifierEntryFlag_P2;
+ entry.bothPlayers = false;
+ break;
+ default:
+ break;
+ }
+ m_ModifiersList.push_back(entry);
+ }
+ if (ImGui::Button("Add Random", { -FLT_MIN, 0 }))
+ {
+ std::uniform_int_distribution random_dist(0, NUM_MODIFIERS);
+
+ int randomID = random_dist(mt);
+
+ ModifierEntry entry = {};
+ entry.name = szModifiers[randomID];
+ switch (flagType)
+ {
+ case ModifierFlagType_Both:
+ entry.flag = ModifierEntryFlag_P1 | ModifierEntryFlag_P2;
+ entry.bothPlayers = true;
+ break;
+ case ModifierFlagType_P1Only:
+ entry.flag = ModifierEntryFlag_P1;
+ entry.bothPlayers = false;
+ break;
+ case ModifierFlagType_P2Only:
+ entry.flag = ModifierEntryFlag_P2;
+ entry.bothPlayers = false;
+ break;
+ default:
+ break;
+ }
+ m_ModifiersList.push_back(entry);
+ }
+
+ ImGui::Separator();
+ unsigned int numModifiers = m_ModifiersList.size();
+ if (numModifiers > 0)
+ {
+ ImGui::TextWrapped("Modifiers to activate:");
+ ImGui::Separator();
+ for (unsigned int i = 0; i < m_ModifiersList.size(); i++)
+ {
+ char modifierLabel[64] = {};
+ sprintf(modifierLabel, "%d - %s##gm%d", i + 1, m_ModifiersList[i].name.c_str(), i);
+ char* modifierLabelType = "##";
+ if (m_ModifiersList[i].flag & ModifierEntryFlag_P1)
+ modifierLabelType = "P1##";
+ if (m_ModifiersList[i].flag & ModifierEntryFlag_P2)
+ modifierLabelType = "P2##";
+ if (m_ModifiersList[i].flag & ModifierEntryFlag_P1 && m_ModifiersList[i].flag & ModifierEntryFlag_P2)
+ modifierLabelType = "Both##";
+ ImGui::LabelText(modifierLabelType, modifierLabel);
+ }
+ if (ImGui::Button("Delete Last", { -FLT_MIN, 0 }))
+ {
+ m_ModifiersList.erase(m_ModifiersList.end() - 1);
+ }
+ if (ImGui::Button("Clear", { -FLT_MIN, 0 }))
+ {
+ m_ModifiersList.clear();
+ }
+
+ }
+
+
+
ImGui::EndTabItem();
}
ImGui::EndTabBar();
@@ -1513,9 +1590,6 @@ void MK11Menu::DrawCameraTab()
ImGui::Checkbox("Mouse Control", &m_bMouseControl);
}
-
-
-
ImGui::Separator();
ImGui::Checkbox("Disable DOF", &m_bDisableDOF);
ImGui::Checkbox("Force Camera To Move", &m_bForceCameraUpdate);
@@ -2084,22 +2158,27 @@ void MK11Menu::DrawAbilityReference()
ImGui::SameLine();
ImGui::BeginChild("##movelist", { 0, -ImGui::GetFrameHeightWithSpacing() });
- eAbilityNameEntry ab;
- ab = eAbiltityNames::Get(szKryptCharacters[charID]);
-
- ImGui::LabelText("ID", "Name");
- ImGui::Separator();
+
+ eAbilityNameEntry* ab = eAbiltityNames::Get(szKryptCharacters[charID]);
- for (unsigned int i = 0; i < TOTAL_ABILITIES; i++)
+ if (ab)
{
- if (strlen(ab.abNames[i]) > 0)
+ ImGui::LabelText("ID", "Name");
+ ImGui::Separator();
+
+ for (unsigned int i = 0; i < eAbiltityNames::GetAmount(ab); i++)
{
- sprintf(textBuffer, "%d", i + 1);
- ImGui::LabelText(textBuffer, ab.abNames[i]);
- }
+ if (strlen(ab->abNames[i]) > 0)
+ {
+ static char textBuffer[256] = {};
+ sprintf(textBuffer, "%d", i + 1);
+ ImGui::LabelText(textBuffer, ab->abNames[i]);
+ }
+ }
}
+
ImGui::EndChild();
ImGui::End();
}
@@ -2172,6 +2251,74 @@ void MK11Menu::DrawAnimationTool()
AnimationTool::Draw();
}
+void MK11Menu::DrawModifiers_AbilityTab()
+{
+ ImGui::TextWrapped("Set abilities before going into a fight. Changing these in game will make moves locked, restart match if that happens.");
+ ImGui::Separator();
+ ImGui::Checkbox("Player 1 Custom Abilities", &m_bP1CustomAbilities);
+ ImGui::Separator();
+ DrawModifiers_AbilityTab_List(PLAYER1);
+ ImGui::Checkbox("Player 2 Custom Abilities", &m_bP2CustomAbilities);
+ DrawModifiers_AbilityTab_List(PLAYER2);
+}
+
+void MK11Menu::DrawModifiers_AbilityTab_List(PLAYER_NUM player)
+{
+ static char abilityName[256] = {};
+
+ bool* abilities = &m_P1Abilities[0];
+ if (player == PLAYER2)
+ abilities = &m_P2Abilities[0];
+
+ int numAbilities = TOTAL_ABILITIES;
+
+ if (GetObj(player))
+ {
+ eAbilityNameEntry* ability = eAbiltityNames::Get(GetCharacterName(player));
+
+ if (!ability)
+ return;
+
+ numAbilities = eAbiltityNames::GetAmount(ability);
+
+ for (int i = 0; i < numAbilities; i++)
+ {
+ sprintf(abilityName, "%s##a%d%d", ability->abNames[i], player, i + 1);
+
+ ImGui::Checkbox(abilityName, &abilities[i]);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < numAbilities; i++)
+ {
+ sprintf(abilityName, "Ability %d##a%d%d", i + 1,player,i + 1);
+
+ ImGui::Checkbox(abilityName, &abilities[i]);
+
+ if (i % 2 == 0)
+ ImGui::SameLine();
+ }
+ }
+
+
+ if (GetObj(player))
+ {
+ if (ImGui::Button("Get Current##p1"))
+ {
+ int curAbilities = GetObj(player)->GetAbility();
+
+ for (int i = 0; i < TOTAL_ABILITIES; i++)
+ {
+ int id = (int)pow(2, i);
+ abilities[i] = curAbilities & id;
+ }
+ }
+
+ }
+ ImGui::Separator();
+}
+
void MK11Menu::DrawKeyBind(char* name, int* var)
{
ImGui::SameLine();
diff --git a/MK11Hook/plugin/Menu.h b/MK11Hook/plugin/Menu.h
index c797061..77e6cb7 100644
--- a/MK11Hook/plugin/Menu.h
+++ b/MK11Hook/plugin/Menu.h
@@ -3,14 +3,16 @@
#include "../mk/CharacterDefinition.h"
#include "../mk/MKCharacter.h"
#include "../mk/MKCamera.h"
+#include "../mk/MKModifier.h"
#include "../mk/LadderInfo.h"
#include "PluginInterface.h"
#include "../helper/eKeyboardMan.h"
#include "../utils.h"
+#define NUM_MODIFIERS 284
-#define MK11HOOK_VERSION "0.5.8"
+#define MK11HOOK_VERSION "0.5.9"
enum eCustomCameras {
CAMERA_3RDPERSON,
@@ -19,6 +21,7 @@ enum eCustomCameras {
CAMERA_1STPERSON_MID,
CAMERA_INJUSTICE_2,
CAMERA_HEAD_TRACKING,
+ CAMERA_9_16,
TOTAL_CUSTOM_CAMERAS
};
@@ -44,6 +47,11 @@ enum eScriptExecuteType {
SCRIPT_GLOBAL
};
+enum eModifierEntryFlag {
+ ModifierEntryFlag_P1 = 1,
+ ModifierEntryFlag_P2 = 2,
+};
+
struct eScriptKeyBind {
eScriptExecuteType type;
eVKKeyCode key;
@@ -51,6 +59,15 @@ struct eScriptKeyBind {
unsigned int functionHash;
};
+struct ModifierEntry {
+ std::string name;
+ int flag;
+ bool bothPlayers;
+ Modifier* modifierDefinition;
+};
+
+extern const char* szModifiers[NUM_MODIFIERS];
+
class MK11Menu {
public:
bool m_bIsActive = false;
@@ -111,6 +128,7 @@ class MK11Menu {
bool m_bKryptModifier = false;
bool m_bTagAssist = false;
bool m_bTagAssistP2 = false;
+ bool m_bAddGlobalModifiers = false;
bool m_bDisableGearLoadouts = false;
bool m_bDisableComboScaling = false;
bool m_bKryptAirbreak = false;
@@ -141,15 +159,19 @@ class MK11Menu {
int m_nFreeCameraRotationSpeed = 120;
int m_nCurrentCustomCamera = CAMERA_3RDPERSON;
int m_nCurrentCharModifier = MODIFIER_SCREEN;
+
+ int m_nAIDroneLevelP1 = 0;
+ int m_nAIDroneLevelP2 = 0;
+
int m_nP1Abilities = 0;
int m_nP2Abilities = 0;
int* m_pCurrentVarToChange = nullptr;
bool m_bP1CustomAbilities = false;
- bool m_P1Abilities[20] = {};
+ bool m_P1Abilities[TOTAL_ABILITIES] = {};
bool m_bP2CustomAbilities = false ;
- bool m_P2Abilities[20] = {};
+ bool m_P2Abilities[TOTAL_ABILITIES] = {};
int m_nScriptExecuteType = 0;
unsigned int m_nHash = 0;
@@ -181,6 +203,8 @@ class MK11Menu {
char szPlayer1AI[128] = {};
char szPlayer2AI[128] = {};
+ std::vector m_ModifiersList;
+
// camera
FVector camPos = {};
@@ -227,6 +251,9 @@ class MK11Menu {
void DrawScriptReference();
void DrawAnimationTool();
+ void DrawModifiers_AbilityTab();
+ void DrawModifiers_AbilityTab_List(PLAYER_NUM player);
+
void DrawKeyBind(char* name, int* var);
void KeyBind(int* var, char* bindName, char* name);
diff --git a/MK11Hook/plugin/ModifierList.cpp b/MK11Hook/plugin/ModifierList.cpp
new file mode 100644
index 0000000..d349185
--- /dev/null
+++ b/MK11Hook/plugin/ModifierList.cpp
@@ -0,0 +1,288 @@
+#include "Menu.h"
+
+const char* szModifiers[NUM_MODIFIERS] = {
+ "AcidRain",
+ "AirStrike",
+ "Armor",
+ "BadLowGround",
+ "BadSpecial",
+ "Bleeding",
+ "BlockingDisabled",
+ "BrutalityKombat",
+ "BuffedUp",
+ "CoordinatesReceived",
+ "DarkKombat",
+ "DeadHands",
+ "DiveKick",
+ "Earthshaker",
+ "Earthquake",
+ "BloodAura",
+ "ChaosAura",
+ "DarkAura",
+ "ElectricAura",
+ "EnergyAura",
+ "FireAura",
+ "IceAura",
+ "MagicAura",
+ "PoisonAura",
+ "BloodFists",
+ "ChaosFists",
+ "DarkFists",
+ "ElectricFists",
+ "EnergyFists",
+ "FireFists",
+ "IceFists",
+ "MagicFists",
+ "PoisonFists",
+ "BloodFloor",
+ "ChaosFloor",
+ "DarkFloor",
+ "ElectricFloor",
+ "EnergyFloor",
+ "FireFloor",
+ "IceFloor",
+ "MagicFloor",
+ "PoisonFloor",
+ "BloodShield",
+ "HalfResistBlood",
+ "ChaosShield",
+ "HalfResistChaos",
+ "DarkShield",
+ "HalfResistDark",
+ "ElectricShield",
+ "HalfResistElectric",
+ "EnergyShield",
+ "HalfResistEnergy",
+ "FireShield",
+ "HalfResistFire",
+ "IceShield",
+ "HalfResistIce",
+ "MagicShield",
+ "HalfResistMagic",
+ "PoisonShield",
+ "HalfResistPoison",
+ "PhysicalShield",
+ "HalfResistPhysical",
+ "BloodRockets",
+ "BloodRockets_FriendlyFire",
+ "ChaosRockets",
+ "ChaosRockets_FriendlyFire",
+ "DarkRockets",
+ "DarkRockets_FriendlyFire",
+ "ElectricRockets",
+ "ElectricRockets_FriendlyFire",
+ "EnergyRockets",
+ "EnergyRockets_FriendlyFire",
+ "FireRockets",
+ "FireRockets_FriendlyFire",
+ "IceRockets",
+ "IceRockets_FriendlyFire",
+ "MagicRockets",
+ "MagicRockets_FriendlyFire",
+ "PoisonRockets",
+ "PoisonRockets_FriendlyFire",
+ "BloodStorm",
+ "ChaosStorm",
+ "DarkStorm",
+ "ElectricStorm",
+ "EnergyStorm",
+ "FireStorm",
+ "IceStorm",
+ "MagicStorm",
+ "PoisonStorm",
+ "BloodTotem",
+ "ChaosTotem",
+ "DarkTotem",
+ "ElectricTotem",
+ "EnergyTotem",
+ "FireTotem",
+ "IceTotem",
+ "MagicTotem",
+ "PoisonTotem",
+ "FallingBombs",
+ "FallingHeads",
+ "FleetFooted",
+ "GiftOfBlood",
+ "CurseOfBlood",
+ "GiftOfChaos",
+ "CurseOfChaos",
+ "GiftOfDark",
+ "CurseOfDark",
+ "GiftOfElectric",
+ "CurseOfElectric",
+ "GiftOfEnergy",
+ "CurseOfEnergy",
+ "GiftOfFire",
+ "CurseOfFire",
+ "GiftOfIce",
+ "CurseOfIce",
+ "GiftOfMagic",
+ "CurseOfMagic",
+ "GiftOfPoison",
+ "CurseOfPoison",
+ "GiftOfRandom",
+ "CurseOfRandom",
+ "PickupOfRandom",
+ "GiveSupermove",
+ "GroundBlade",
+ "GroundMines",
+ "GroundSpikes",
+ "GunAttacksUp",
+ "JuggleKombat",
+ "BlueLightningStrikes",
+ "RedLightningStrikes",
+ "BlackLightningStrikes",
+ "MeteorKombat",
+ "Overpowered",
+ "DamageBuff",
+ "PanningLasers",
+ "PillarsOfFlame",
+ "Poisoned",
+ "BadDucking",
+ "BadJumping",
+ "PowerOrb",
+ "PowerStruggle",
+ "HypoKombat",
+ "HyperKombat",
+ "SupermoveBuff",
+ "WetSpot",
+ "DamageReflectAll",
+ "HealBlock",
+ "BlackDragonAssist",
+ "BoRaiChoAssist",
+ "ErmacAssist",
+ "HsuHaoAssist",
+ "HydroAssist",
+ "KungJinAssist",
+ "MeatAssist",
+ "MileenaAssist",
+ "NitaraAssist",
+ "OnyxAssist",
+ "QuanChiAssist",
+ "ReikoAssist",
+ "ReptileAssist",
+ "SektorAssist",
+ "SmokeAssist",
+ "SpecialForcesAssist",
+ "StrykerAssist",
+ "TakedaAssist",
+ "TanyaAssist",
+ "TremorAssist",
+ "CyraxAssist",
+ "CyraxBombsAssist",
+ "KenshiAssist",
+ "RainAssist",
+ "ShinnokAssist",
+ "BloodBuff",
+ "ChaosBuff",
+ "DarkBuff",
+ "ElectricBuff",
+ "EnergyBuff",
+ "FireBuff",
+ "IceBuff",
+ "MagicBuff",
+ "PoisonBuff",
+ "PhysicalBuff",
+ "DisableWeather",
+ "DisableRockets",
+ "DisableFloorMods",
+ "DisableTotemMods",
+ "FreezeDuration",
+ "HealthRegen",
+ "M80Assist",
+ "PugglesAssist",
+ "RomanCandleAssist",
+ "BatsAssist",
+ "BigBoom",
+ "BlackCatAssist",
+ "BottleRockets",
+ "CannedCranberry",
+ "DiveBombingTurkey",
+ "FallingPumpkins",
+ "Fireworks",
+ "FlyingWitchAssist",
+ "Gravestones",
+ "GravyBubble",
+ "GroundSpinner",
+ "HornOfPlenty",
+ "JackOLantern",
+ "MashedPotatoes",
+ "Pentagrams",
+ "PieAssist",
+ "SmokeBomb",
+ "Sparklers",
+ "RunningTurkeyAssist",
+ "AIDisabled",
+ "PhysicalOverride",
+ "BloodOverride",
+ "ChaosOverride",
+ "DarkOverride",
+ "ElectricOverride",
+ "EnergyOverride",
+ "FireOverride",
+ "IceOverride",
+ "MagicOverride",
+ "PoisonOverride",
+ "FStyleDisabled",
+ "InvisibleKombat",
+ "MomentOfOpportunity",
+ "ProjectilePassThru",
+ "ReducedDamage",
+ "ReducedPhysicalDamage",
+ "ReducedBloodDamage",
+ "ReducedChaosDamage",
+ "ReducedDarkDamage",
+ "ReducedElectricDamage",
+ "ReducedEnergyDamage",
+ "ReducedFireDamage",
+ "ReducedMagicDamage",
+ "ReducedPoisonDamage",
+ "SpecialBuff",
+ "SpecialsDisabled",
+ "SupermovesDisabled",
+ "TimerAdjustment",
+ "Weakened",
+ "DeflectedGlaive",
+ "DeflectedGlaiveLow",
+ "WaveOfGlaives",
+ "GlaiveBurst",
+ "GlaiveJuggling",
+ "HighLowGlaives",
+ "SavageBleed",
+ "SavageBleedPhase2",
+ "SavageBleedPhase3",
+ "SavageBleedPhase4",
+ "GreenEnergyBuff",
+ "SkarletHealingBlood",
+ "ScytheFall",
+ "BloodBall",
+ "SpearFlurry",
+ "FireResistance",
+ "DvorahPoisonOvipositors",
+ "DvorahSpiderFood",
+ "DvorahOrbspinner",
+ "DvorahInfest",
+ "DvorahSwarmCloud",
+ "RaidenStormhead",
+ "RaidenLightningPillar",
+ "RaidenLightningStorm",
+ "KungLaoRazorHats",
+ "KungLaoKungFuMaster",
+ "KungLaoSpiritMaster",
+ "KungLaoSpiritReinforcement",
+ "KungLaoSpiritsGifts",
+ "GreatKungLaosDecimation",
+ "BouncingHat",
+ "DragonsBreathZones",
+ "DragonsBreathJump",
+ "LiuKangFlowLikeWater",
+ "KabalGasSaturation",
+ "KabalSpeedBoost",
+ "KabalHookBleed",
+ "KabalGroundBladeRush",
+ "FightClub",
+ "BlackDragonSniper",
+ "ChemicalBurns",
+ "ErronBlackChainDetonator",
+ "DoNothing",
+};
diff --git a/MK11Hook/plugin/PatternSolver.cpp b/MK11Hook/plugin/PatternSolver.cpp
index e749205..bce29f9 100644
--- a/MK11Hook/plugin/PatternSolver.cpp
+++ b/MK11Hook/plugin/PatternSolver.cpp
@@ -91,8 +91,13 @@ void PatternSolver::Initialize()
ms_patterns[PATID_TagAssistModifier_TagAssistModifier] = GetPattern("48 89 4C 24 08 55 56 57 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 60 48 C7 45 C0 FE FF FF FF 48 89 9C 24 A8 00 00 00 49 8B D8", 0);
ms_patterns[PATID_TagAssistModifier_Activate] = GetPattern("48 85 D2 0F 84 A7 01 00 00 48 8B C4 57 41 56 41 57 48 83 EC 70 48 C7 40 A8 FE FF FF FF", 0);
ms_patterns[PATID_TagAssistModifier_CreateObject] = GetPattern("40 57 48 83 EC 30 48 C7 44 24 20 FE FF FF FF 48 89 5C 24 40 48 8B F9 BA 01 00 00 00 B9 20 01 00 00", 0);
- ms_patterns[PATID_MKModifier_ActivateModifier] = GetPattern("48 89 5C 24 18 48 89 6C 24 20 56 48 83 EC 20 48 8B 02 48 8B E9 48 8B CA", 0);
- ms_patterns[PATID_TagAssistModifierObject_Activate] = GetPattern("48 89 5C 24 08 57 48 83 EC 20 48 8B DA 48 8B F9 48 85 D2 0F 84 89 00 00 00", 0);
+ ms_patterns[PATID_MKModifier_Constructor] = GetPattern("4C 8B DC 49 89 4B 08 56 57 41 56 48 83 EC 50 49 C7 43 ? ? ? ? ? 49 89 5B 10 49 89 6B 18 48 8B EA 4C 8B F1 48 8B 84 24 ? ? ? ? 49 89 43 B8 E8 ? ? ? ? 90 48 8D 05 ? ? ? ? 49 89 06 4C 8B C5 48 8D 15 ? ? ? ? 48 8D 4C 24 ? E8", 0);
+ ms_patterns[PATID_MKModifier_Activate] = GetPattern("48 8B C4 41 54 41 56 41 57 48 81 EC ? ? ? ? 48 C7 40 ? ? ? ? ? 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 48 8B F2 48 8B F9 80 B9 ? ? ? ? ? 74 07 32 C0 E9 ? ? ? ? 48 8B 15 ? ? ? ? 4C 8D 25 ? ? ? ? 48 83 BA ? ? ? ? ? 74 1C 8B 82", 0);
+ ms_patterns[PATID_MKModifier_GetAssetPath] = GetPattern("40 57 48 83 EC 50 48 C7 44 24 ? ? ? ? ? 48 89 5C 24 ? 48 89 74 24 ? 48 8B DA 83 79 10 00 74 06 4C 8B 41 08 EB 07 4C 8D 05 ? ? ? ? 48 8D 15 ? ? ? ? 48 8D 4C 24 ? E8", 0);
+ ms_patterns[PATID_MKModifierObject_Constructor] = GetPattern("48 89 5C 24 ? 57 48 83 EC 20 48 8B 02 48 8B D9 48 8B CA 41 8B F8 FF 50 08 48 89 03 48 8B C3 89 7B 08 48 8B 5C 24 ? 48 83 C4 20 5F C3", 0);
+ ms_patterns[PATID_MKModifierObject_Activate] = GetPattern("48 89 5C 24 ? 48 89 6C 24 ? 56 48 83 EC 20 49 8B F0 48 8B EA 48 8B D9 E8 ? ? ? ? 48 85 C0 74 56 48 8B C8 48 89 7C 24 ? E8 ? ? ? ? 48 8B F8 48 85 C0 74 3C 8B 53 08 85 D2 74 27 83 EA 01 74 1D", 0);
+
+
ms_patterns[PATID_GetModifierManager] = GetPattern("B9 03 00 00 00 E8 ? ? ? ? E8 ? ? ? ? 48 85 C0 74 11 BA 40 00 00 00", 11);
ms_patterns[PATID_LoadModifierAssets] = GetPattern("48 89 5C 24 10 55 48 83 EC 30 48 8D 2D ? ? ? ?", 0);
@@ -107,7 +112,10 @@ void PatternSolver::Initialize()
ms_patterns[PATID_PlayerInfo_SetMeter] = GetPattern("40 53 48 83 EC 30 0F 29 74 24 20 0F 57 F6 8B DA", 0);
ms_patterns[PATID_PlayerInfo_RefreshMeter] = GetPattern("48 89 5C 24 10 56 48 81 EC 80 00 00 00 48 8B D9", 0);
ms_patterns[PATID_PlayerInfo_GetDrone] = GetPattern("48 8B 81 50 04 00 00 48 85 C0 74 21", 0);
+ ms_patterns[PATID_PlayerInfo_MakeDrone] = GetPattern("40 56 57 41 56 48 83 EC 30 48 C7 44 24 ? ? ? ? ? 48 89 5C 24 ? 48 89 6C 24 ? 48 8B D9 48 85 C9 75 07 33 C0 E9 ? ? ? ? 48 8B 79 30 48 85 FF 74 F0 48 8B CF E8 ? ? ? ? 33 F6 85 C0 75 3E 44 8B F6 48 8B CF E8 ? ? ? ? 85 C0", 0);
ms_patterns[PATID_AIDrone_Set] = GetPattern("48 89 5C 24 10 48 89 6C 24 18 56 57 41 56 48 83 EC 20 48 8B F9 48 8B F2 48 8B 0D ? ? ? ? BA 00 00 00 10", 0);
+ ms_patterns[PATID_AIDrone_SetLevel] = GetPattern("40 53 48 83 EC 30 0F 29 74 24 ? 48 8B D9 0F 28 F1 0F 2F 35 ? ? ? ? 77 45 48 8B 89 ? ? ? ? 48 85 C9 74 27 8B 83 ? ? ? ? 3D ? ? ? ? 73 1A 8B D0 4C 8D 05 ? ? ? ? 8B 83", 0);
+
ms_patterns[PATID_SetKryptCharacter] = GetPattern("40 57 48 83 EC 40 48 C7 44 24 20 FE FF FF FF 48 89 5C 24 50 48 89 74 24 60 48 8B DA 48 8B F9 33 F6", 0);
ms_patterns[PATID_SetKryptCharacterL] = GetPattern("40 53 48 83 EC 40 48 8B D9 48 85 D2 74 48 80 3A 00", 0);
@@ -123,6 +131,9 @@ void PatternSolver::Initialize()
ms_patterns[PATID_ProcessDOFSettings] = GetPattern("48 8D 4B 44 E8 ? ? ? ? 48 8D 44 24", 4);
+ ms_patterns[PATID_FightStartupAddModifiers] = GetPattern("E8 ? ? ? ? E8 ? ? ? ? 85 C0 74 16 0F 1F 44 00 ? 41 8B CC E8", 0);
+ ms_patterns[PATID_TArray_AddString] = GetPattern("48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 48 63 59 08 48 8B F2 48 8B F9 8D 43 01 89 41 08 3B 41 0C 7E 47 44 8B C0 41 C1 E8 03 42 8D 04 40 83 C0 20 41 03 C0 48 05 ? ? ? ? 48 8B C8 48 C1 F9 3F 23 C1 48 8B 0F 05 ? ? ? ? 89 47 0C 48 85 C9 75 04 85 C0 74 13 C1 E0 04", 0);
+ ms_patterns[PATID_FightStartupQueueModifiers] = GetPattern("48 8B C4 55 41 54 41 55 41 56 41 57 48 8B EC 48 81 EC ? ? ? ? 48 C7 45 ? ? ? ? ? 48 89 58 10 48 89 70 18 48 89 78 20 48 8B FA 4C 8B F9 48 8D 4D C8 E8 ? ? ? ? 48 8B D8 45 33 F6 48 3B F8 0F 84 ? ? ? ? 8B 40 08", 0);
auto end = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast(end - begin);
@@ -215,8 +226,11 @@ const char* PatternSolver::GetPatternName(int id)
"TagAssistModifier_TagAssistModifier",
"TagAssistModifier_Activate",
"TagAssistModifier_CreateObject",
- "MKModifier_ActivateModifier",
- "TagAssistModifierObject_Activate",
+ "MKModifier_Constructor",
+ "MKModifier_Activate",
+ "MKModifier_GetAssetPath",
+ "MKModifierObject_Constructor",
+ "MKModifierObject_Activate",
"GetModifierManager",
"LoadModifierAssets",
"MKObject_SetPos",
@@ -228,7 +242,9 @@ const char* PatternSolver::GetPatternName(int id)
"PlayerInfo_SetMeter",
"PlayerInfo_RefreshMeter",
"PlayerInfo_GetDrone",
+ "PlayerInfo_MakeDrone",
"AIDrone_Set",
+ "AIDrone_SetLevel",
"SetKryptCharacter",
"SetKryptCharacterL",
"AnimationToolCode",
@@ -237,7 +253,10 @@ const char* PatternSolver::GetPatternName(int id)
"USkeletalMeshComponent_GetBoneName",
"XInputGetState_Hook",
"GetScaleform",
- "ProcessDOFSettings"
+ "ProcessDOFSettings",
+ "FightStartupAddModifiers",
+ "TArray_AddString",
+ "FightStartupQueueModifiers",
};
return szPatternNames[id];
diff --git a/MK11Hook/plugin/PatternSolver.h b/MK11Hook/plugin/PatternSolver.h
index ce084dc..d374abb 100644
--- a/MK11Hook/plugin/PatternSolver.h
+++ b/MK11Hook/plugin/PatternSolver.h
@@ -67,8 +67,12 @@ enum EPatternID {
PATID_TagAssistModifier_TagAssistModifier,
PATID_TagAssistModifier_Activate,
PATID_TagAssistModifier_CreateObject,
- PATID_MKModifier_ActivateModifier,
- PATID_TagAssistModifierObject_Activate,
+ PATID_MKModifier_Constructor,
+ PATID_MKModifier_Activate,
+ PATID_MKModifier_GetAssetPath,
+ PATID_MKModifierObject_Constructor,
+ PATID_MKModifierObject_Activate,
+
PATID_GetModifierManager,
PATID_LoadModifierAssets,
@@ -83,7 +87,9 @@ enum EPatternID {
PATID_PlayerInfo_SetMeter,
PATID_PlayerInfo_RefreshMeter,
PATID_PlayerInfo_GetDrone,
+ PATID_PlayerInfo_MakeDrone,
PATID_AIDrone_Set,
+ PATID_AIDrone_SetLevel,
PATID_SetKryptCharacter,
PATID_SetKryptCharacterL,
@@ -96,6 +102,10 @@ enum EPatternID {
PATID_XInputGetState_Hook,
PATID_GetScaleform,
PATID_ProcessDOFSettings,
+ PATID_FightStartupAddModifiers,
+ PATID_TArray_AddString,
+ PATID_FightStartupQueueModifiers,
+
PATID_Total_Patterns
};
diff --git a/MK11Hook/utils/MemoryMgr.h b/MK11Hook/utils/MemoryMgr.h
index b53cf48..d52cfda 100644
--- a/MK11Hook/utils/MemoryMgr.h
+++ b/MK11Hook/utils/MemoryMgr.h
@@ -1,5 +1,4 @@
-#ifndef __MEMORYMGR
-#define __MEMORYMGR
+#pragma once
// Switches:
// _MEMORY_NO_CRT - don't include anything "complex" like ScopedUnprotect or memset
@@ -7,61 +6,81 @@
#define WRAPPER __declspec(naked)
#define DEPRECATED __declspec(deprecated)
+#define WRAPARG(a) ((int)a)
+
+#ifdef _MSC_VER
#define EAXJMP(a) { _asm mov eax, a _asm jmp eax }
#define VARJMP(a) { _asm jmp a }
-#define WRAPARG(a) ((int)a)
+#elif defined(__GNUC__) || defined(__clang__)
+#define EAXJMP(a) { __asm__ volatile("mov eax, %0\n" "jmp eax" :: "i" (a)); }
+#define VARJMP(a) { __asm__ volatile("jmp %0" :: "m" (a)); }
+#endif
+#ifdef _MSC_VER
#define NOVMT __declspec(novtable)
+#else
+#define NOVMT
+#endif
+
#define SETVMT(a) *((uintptr_t*)this) = (uintptr_t)a
#ifndef _MEMORY_DECLS_ONLY
#define WIN32_LEAN_AND_MEAN
-#include
+#include
#include
#include
#ifndef _MEMORY_NO_CRT
+#include
#include
-#include
+#include
#endif
-enum
+namespace Memory
{
- PATCH_CALL,
- PATCH_JUMP
-};
+ enum class HookType
+ {
+ Call,
+ Jump,
+ };
-template
-inline AT DynBaseAddress(AT address)
-{
-#ifdef _WIN64
- return (ptrdiff_t)GetModuleHandle(nullptr) - 0x140000000 + address;
-#else
- return (ptrdiff_t)GetModuleHandle(nullptr) - 0x400000 + address;
-#endif
-}
+ template
+ inline AT DynBaseAddress(AT address)
+ {
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
+ #ifdef _WIN64
+ return (ptrdiff_t)GetModuleHandle(nullptr) - 0x140000000 + address;
+ #else
+ return (ptrdiff_t)GetModuleHandle(nullptr) - 0x400000 + address;
+ #endif
+ }
-namespace Memory
-{
template
inline void Patch(AT address, T value)
- {*(T*)address = value; }
+ {
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
+ *(T*)address = value;
+ }
#ifndef _MEMORY_NO_CRT
template
inline void Patch(AT address, std::initializer_list list )
{
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
uint8_t* addr = reinterpret_cast(address);
- std::copy( list.begin(), list.end(), stdext::make_checked_array_iterator(addr, list.size()) );
+ std::copy( list.begin(), list.end(), addr );
}
#endif
template
inline void Nop(AT address, size_t count)
#ifndef _MEMORY_NO_CRT
- { memset((void*)address, 0x90, count); }
+ {
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
+ memset((void*)address, 0x90, count);
+ }
#else
{ do {
*(uint8_t*)address++ = 0x90;
@@ -71,6 +90,7 @@ namespace Memory
template
inline void WriteOffsetValue(AT address, Var var)
{
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
intptr_t dstAddr = (intptr_t)address;
intptr_t srcAddr;
memcpy( &srcAddr, std::addressof(var), sizeof(srcAddr) );
@@ -80,6 +100,7 @@ namespace Memory
template
inline void ReadOffsetValue(AT address, Var& var)
{
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
intptr_t srcAddr = (intptr_t)address;
intptr_t dstAddr = srcAddr + (4 + extraBytesAfterOffset) + *(int32_t*)srcAddr;
var = {};
@@ -93,9 +114,9 @@ namespace Memory
}
template
- inline void InjectHook(AT address, Func hook, unsigned int nType)
+ inline void InjectHook(AT address, Func hook, HookType type)
{
- *(uint8_t*)address = nType == PATCH_JUMP ? 0xE9 : 0xE8;
+ *(uint8_t*)address = type == HookType::Jump ? 0xE9 : 0xE8;
InjectHook(address, hook);
}
@@ -113,23 +134,38 @@ namespace Memory
return reinterpret_cast( addr + offset );
}
+ constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook)
+ {
+ ReadCall(address, func);
+ InjectHook(address, hook);
+ };
+
#ifndef _MEMORY_NO_CRT
inline bool MemEquals(uintptr_t address, std::initializer_list val)
{
const uint8_t* mem = reinterpret_cast(address);
- return std::equal( val.begin(), val.end(), stdext::make_checked_array_iterator(mem, val.size()) );
+ return std::equal( val.begin(), val.end(), mem );
}
#endif
template
inline AT Verify(AT address, uintptr_t expected)
{
+ static_assert(sizeof(AT) == sizeof(uintptr_t), "AT must be pointer sized");
assert( uintptr_t(address) == expected );
return address;
}
namespace DynBase
{
+ enum class HookType
+ {
+ Call,
+ Jump,
+ };
+
+ using Memory::DynBaseAddress;
+
template
inline void Patch(AT address, T value)
{
@@ -162,16 +198,16 @@ namespace Memory
Memory::ReadOffsetValue(DynBaseAddress(address), var);
}
- template
- inline void InjectHook(AT address, HT hook)
+ template
+ inline void InjectHook(AT address, Func hook)
{
Memory::InjectHook(DynBaseAddress(address), hook);
}
- template
- inline void InjectHook(AT address, HT hook, unsigned int nType)
+ template
+ inline void InjectHook(AT address, Func hook, HookType type)
{
- Memory::InjectHook(DynBaseAddress(address), hook, nType);
+ Memory::InjectHook(DynBaseAddress(address), hook, static_cast(type));
}
template
@@ -186,6 +222,11 @@ namespace Memory
return Memory::ReadCallFrom(DynBaseAddress(address), offset);
}
+ constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook)
+ {
+ Memory::InterceptCall(DynBaseAddress(address), func, hook);
+ };
+
#ifndef _MEMORY_NO_CRT
inline bool MemEquals(uintptr_t address, std::initializer_list val)
{
@@ -202,6 +243,14 @@ namespace Memory
namespace VP
{
+ enum class HookType
+ {
+ Call,
+ Jump,
+ };
+
+ using Memory::DynBaseAddress;
+
template
inline void Patch(AT address, T value)
{
@@ -247,8 +296,8 @@ namespace Memory
Memory::ReadOffsetValue(address, var);
}
- template
- inline void InjectHook(AT address, HT hook)
+ template
+ inline void InjectHook(AT address, Func hook)
{
DWORD dwProtect;
@@ -257,13 +306,13 @@ namespace Memory
VirtualProtect((void*)((DWORD_PTR)address + 1), 4, dwProtect, &dwProtect);
}
- template
- inline void InjectHook(AT address, HT hook, unsigned int nType)
+ template
+ inline void InjectHook(AT address, Func hook, HookType type)
{
DWORD dwProtect;
VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
- Memory::InjectHook( address, hook, nType );
+ Memory::InjectHook( address, hook, static_cast(type) );
VirtualProtect((void*)address, 5, dwProtect, &dwProtect);
}
@@ -279,6 +328,15 @@ namespace Memory
return Memory::ReadCallFrom(address, offset);
}
+ constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook)
+ {
+ DWORD dwProtect;
+
+ VirtualProtect((void*)address, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
+ Memory::InterceptCall(address, func, hook);
+ VirtualProtect((void*)address, 5, dwProtect, &dwProtect);
+ };
+
#ifndef _MEMORY_NO_CRT
inline bool MemEquals(uintptr_t address, std::initializer_list val)
{
@@ -294,6 +352,14 @@ namespace Memory
namespace DynBase
{
+ enum class HookType
+ {
+ Call,
+ Jump,
+ };
+
+ using Memory::DynBaseAddress;
+
template
inline void Patch(AT address, T value)
{
@@ -326,16 +392,16 @@ namespace Memory
VP::ReadOffsetValue(DynBaseAddress(address), var);
}
- template
- inline void InjectHook(AT address, HT hook)
+ template
+ inline void InjectHook(AT address, Func hook)
{
VP::InjectHook(DynBaseAddress(address), hook);
}
- template
- inline void InjectHook(AT address, HT hook, unsigned int nType)
+ template
+ inline void InjectHook(AT address, Func hook, HookType type)
{
- VP::InjectHook(DynBaseAddress(address), hook, nType);
+ VP::InjectHook(DynBaseAddress(address), hook, static_cast(type));
}
template
@@ -347,9 +413,14 @@ namespace Memory
template
inline void* ReadCallFrom(AT address, ptrdiff_t offset = 0)
{
- Memory::ReadCallFrom(DynBaseAddress(address), offset);
+ return Memory::ReadCallFrom(DynBaseAddress(address), offset);
}
+ constexpr auto InterceptCall = [](auto address, auto&& func, auto&& hook)
+ {
+ VP::InterceptCall(DynBaseAddress(address), func, hook);
+ };
+
#ifndef _MEMORY_NO_CRT
inline bool MemEquals(uintptr_t address, std::initializer_list val)
{
@@ -367,104 +438,4 @@ namespace Memory
};
};
-#ifndef _MEMORY_NO_CRT
-
-#include
-#include
-#include
-
-namespace ScopedUnprotect
-{
- class Unprotect
- {
- public:
- ~Unprotect()
- {
- for ( auto& it : m_queriedProtects )
- {
- DWORD dwOldProtect;
- VirtualProtect( std::get<0>(it), std::get<1>(it), std::get<2>(it), &dwOldProtect );
- }
- }
-
- protected:
- Unprotect() = default;
-
- void UnprotectRange( DWORD_PTR BaseAddress, SIZE_T Size )
- {
- SIZE_T QueriedSize = 0;
- while ( QueriedSize < Size )
- {
- MEMORY_BASIC_INFORMATION MemoryInf;
- DWORD dwOldProtect;
-
- VirtualQuery( (LPCVOID)(BaseAddress + QueriedSize), &MemoryInf, sizeof(MemoryInf) );
- if ( MemoryInf.State == MEM_COMMIT && (MemoryInf.Type & MEM_IMAGE) != 0 &&
- (MemoryInf.Protect & (PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_READWRITE|PAGE_WRITECOPY)) == 0 )
- {
- const bool wasExecutable = (MemoryInf.Protect & (PAGE_EXECUTE|PAGE_EXECUTE_READ)) != 0;
- VirtualProtect( MemoryInf.BaseAddress, MemoryInf.RegionSize, wasExecutable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &dwOldProtect );
- m_queriedProtects.emplace_front( MemoryInf.BaseAddress, MemoryInf.RegionSize, MemoryInf.Protect );
- }
- QueriedSize += MemoryInf.RegionSize;
- }
- }
-
- private:
- std::forward_list< std::tuple< LPVOID, SIZE_T, DWORD > > m_queriedProtects;
- };
-
- class Section : public Unprotect
- {
- public:
- Section( HINSTANCE hInstance, const char* name )
- {
- PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew);
- PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(ntHeader);
-
- for ( SIZE_T i = 0, j = ntHeader->FileHeader.NumberOfSections; i < j; ++i, ++pSection )
- {
- if ( strncmp( (const char*)pSection->Name, name, IMAGE_SIZEOF_SHORT_NAME ) == 0 )
- {
- const DWORD_PTR VirtualAddress = (DWORD_PTR)hInstance + pSection->VirtualAddress;
- const SIZE_T VirtualSize = pSection->Misc.VirtualSize;
- UnprotectRange( VirtualAddress, VirtualSize );
-
- m_locatedSection = true;
- break;
- }
- }
- };
-
- bool SectionLocated() const { return m_locatedSection; }
-
- private:
- bool m_locatedSection = false;
- };
-
- class FullModule : public Unprotect
- {
- public:
- FullModule( HINSTANCE hInstance )
- {
- PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hInstance + ((PIMAGE_DOS_HEADER)hInstance)->e_lfanew);
- UnprotectRange( (DWORD_PTR)hInstance, ntHeader->OptionalHeader.SizeOfImage );
- }
- };
-
- inline std::unique_ptr UnprotectSectionOrFullModule( HINSTANCE hInstance, const char* name )
- {
- std::unique_ptr section = std::make_unique( hInstance, name );
- if ( !section->SectionLocated() )
- {
- return std::make_unique( hInstance );
- }
- return section;
- }
-};
-
#endif
-
-#endif
-
-#endif
\ No newline at end of file
diff --git a/MK11Hook/utils/Patterns.cpp b/MK11Hook/utils/Patterns.cpp
index e8c36bd..13bceda 100644
--- a/MK11Hook/utils/Patterns.cpp
+++ b/MK11Hook/utils/Patterns.cpp
@@ -8,7 +8,11 @@
#include "Patterns.h"
#define WIN32_LEAN_AND_MEAN
+
+#ifndef NOMINMAX
#define NOMINMAX
+#endif
+
#include
#include
@@ -19,7 +23,7 @@
#if PATTERNS_USE_HINTS
- // from boost someplace
+// from boost someplace
template
struct basic_fnv_1
{
@@ -46,235 +50,243 @@ typedef basic_fnv_1 fnv_1;
namespace hook
{
- ptrdiff_t details::get_process_base()
- {
- return ptrdiff_t(GetModuleHandle(nullptr));
- }
+ptrdiff_t details::get_process_base()
+{
+ return ptrdiff_t(GetModuleHandle(nullptr));
+}
#if PATTERNS_USE_HINTS
- static auto& getHints()
- {
- static std::multimap hints;
- return hints;
- }
+static auto& getHints()
+{
+ static std::multimap hints;
+ return hints;
+}
#endif
- static void TransformPattern(std::string_view pattern, std::basic_string& data, std::basic_string& mask)
+static void TransformPattern(std::string_view pattern, std::basic_string& data, std::basic_string& mask)
+{
+ uint8_t tempDigit = 0;
+ bool tempFlag = false;
+
+ auto tol = [] (char ch) -> uint8_t
{
- uint8_t tempDigit = 0;
- bool tempFlag = false;
+ if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10);
+ if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10);
+ return uint8_t(ch - '0');
+ };
- auto tol = [](char ch) -> uint8_t
+ for (auto ch : pattern)
+ {
+ if (ch == ' ')
{
- if (ch >= 'A' && ch <= 'F') return uint8_t(ch - 'A' + 10);
- if (ch >= 'a' && ch <= 'f') return uint8_t(ch - 'a' + 10);
- return uint8_t(ch - '0');
- };
-
- for (auto ch : pattern)
+ continue;
+ }
+ else if (ch == '?')
{
- if (ch == ' ')
- {
- continue;
- }
- else if (ch == '?')
+ data.push_back(0);
+ mask.push_back(0);
+ }
+ else if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
+ {
+ uint8_t thisDigit = tol(ch);
+
+ if (!tempFlag)
{
- data.push_back(0);
- mask.push_back(0);
+ tempDigit = thisDigit << 4;
+ tempFlag = true;
}
- else if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
+ else
{
- uint8_t thisDigit = tol(ch);
-
- if (!tempFlag)
- {
- tempDigit = thisDigit << 4;
- tempFlag = true;
- }
- else
- {
- tempDigit |= thisDigit;
- tempFlag = false;
-
- data.push_back(tempDigit);
- mask.push_back(0xFF);
- }
+ tempDigit |= thisDigit;
+ tempFlag = false;
+
+ data.push_back(tempDigit);
+ mask.push_back(0xFF);
}
}
}
+}
- class executable_meta
- {
- private:
- uintptr_t m_begin;
- uintptr_t m_end;
-
- template
- TReturn* getRVA(TOffset rva)
- {
- return (TReturn*)(m_begin + rva);
- }
+class executable_meta
+{
+private:
+ uintptr_t m_begin;
+ uintptr_t m_end;
- public:
- explicit executable_meta(uintptr_t module)
- : m_begin(module)
- {
- PIMAGE_DOS_HEADER dosHeader = getRVA(0);
- PIMAGE_NT_HEADERS ntHeader = getRVA(dosHeader->e_lfanew);
+public:
+ explicit executable_meta(uintptr_t module)
+ {
+ PIMAGE_DOS_HEADER dosHeader = reinterpret_cast(module);
+ PIMAGE_NT_HEADERS ntHeader = reinterpret_cast(module + dosHeader->e_lfanew);
- m_end = m_begin + ntHeader->OptionalHeader.SizeOfImage;
- }
+ m_begin = module + ntHeader->OptionalHeader.BaseOfCode;
+ m_end = m_begin + ntHeader->OptionalHeader.SizeOfCode;
- executable_meta(uintptr_t begin, uintptr_t end)
- : m_begin(begin), m_end(end)
+ // Executables with DRM bypassed may lie in their SizeOfCode and underreport severely
+ // We can somewhat detect this by checking if the code entry point is past
+ // these boundaries. It's not perfect, but it's safe.
+ const uintptr_t entryPoint = module + ntHeader->OptionalHeader.AddressOfEntryPoint;
+ if (entryPoint >= m_begin && entryPoint < m_end)
{
+ return;
}
- inline uintptr_t begin() const { return m_begin; }
- inline uintptr_t end() const { return m_end; }
- };
+ // Alternate heuristics - scan the entire executable, minus headers
+ const uintptr_t sizeOfHeaders = ntHeader->OptionalHeader.SizeOfHeaders;
+ m_begin = module + sizeOfHeaders;
+ m_end = module + (ntHeader->OptionalHeader.SizeOfImage - sizeOfHeaders);
+ }
- namespace details
+ executable_meta(uintptr_t begin, uintptr_t end)
+ : m_begin(begin), m_end(end)
{
+ }
- void basic_pattern_impl::Initialize(std::string_view pattern)
- {
- // get the hash for the base pattern
+ inline uintptr_t begin() const { return m_begin; }
+ inline uintptr_t end() const { return m_end; }
+};
+
+namespace details
+{
+
+void basic_pattern_impl::Initialize(std::string_view pattern)
+{
+ // get the hash for the base pattern
#if PATTERNS_USE_HINTS
- m_hash = fnv_1()(pattern);
+ m_hash = fnv_1()(pattern);
#endif
- // transform the base pattern from IDA format to canonical format
- TransformPattern(pattern, m_bytes, m_mask);
+ // transform the base pattern from IDA format to canonical format
+ TransformPattern(pattern, m_bytes, m_mask);
#if PATTERNS_USE_HINTS
- // if there's hints, try those first
+ // if there's hints, try those first
#if PATTERNS_CAN_SERIALIZE_HINTS
- if (m_rangeStart == reinterpret_cast(GetModuleHandle(nullptr)))
+ if (m_rangeStart == reinterpret_cast(GetModuleHandle(nullptr)))
#endif
- {
- auto range = getHints().equal_range(m_hash);
-
- if (range.first != range.second)
- {
- std::for_each(range.first, range.second, [&](const auto& hint)
- {
- ConsiderHint(hint.second);
- });
-
- // if the hints succeeded, we don't need to do anything more
- if (!m_matches.empty())
- {
- m_matched = true;
- return;
- }
- }
- }
-#endif
- }
+ {
+ auto range = getHints().equal_range(m_hash);
- void basic_pattern_impl::EnsureMatches(uint32_t maxCount)
+ if (range.first != range.second)
{
- if (m_matched)
+ std::for_each(range.first, range.second, [&] (const auto& hint)
+ {
+ ConsiderHint(hint.second);
+ });
+
+ // if the hints succeeded, we don't need to do anything more
+ if (!m_matches.empty())
{
+ m_matched = true;
return;
}
+ }
+ }
+#endif
+}
+
+void basic_pattern_impl::EnsureMatches(uint32_t maxCount)
+{
+ if (m_matched)
+ {
+ return;
+ }
- // scan the executable for code
- executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_rangeStart);
+ // scan the executable for code
+ executable_meta executable = m_rangeStart != 0 && m_rangeEnd != 0 ? executable_meta(m_rangeStart, m_rangeEnd) : executable_meta(m_rangeStart);
- auto matchSuccess = [&](uintptr_t address)
- {
+ auto matchSuccess = [&] (uintptr_t address)
+ {
#if PATTERNS_USE_HINTS
- getHints().emplace(m_hash, address);
+ getHints().emplace(m_hash, address);
#else
- (void)address;
+ (void)address;
#endif
- return (m_matches.size() == maxCount);
- };
+ return (m_matches.size() == maxCount);
+ };
- const uint8_t* pattern = m_bytes.data();
- const uint8_t* mask = m_mask.data();
- const size_t maskSize = m_mask.size();
- const size_t lastWild = m_mask.find_last_not_of(uint8_t(0xFF));
+ const uint8_t* pattern = m_bytes.data();
+ const uint8_t* mask = m_mask.data();
+ const size_t maskSize = m_mask.size();
+ const size_t lastWild = m_mask.find_last_not_of(uint8_t(0xFF));
- ptrdiff_t Last[256];
+ ptrdiff_t Last[256];
- std::fill(std::begin(Last), std::end(Last), lastWild == std::string::npos ? -1 : static_cast(lastWild));
+ std::fill(std::begin(Last), std::end(Last), lastWild == std::string::npos ? -1 : static_cast(lastWild) );
- for (ptrdiff_t i = 0; i < static_cast(maskSize); ++i)
- {
- if (Last[pattern[i]] < i)
- {
- Last[pattern[i]] = i;
- }
- }
+ for ( ptrdiff_t i = 0; i < static_cast(maskSize); ++i )
+ {
+ if ( Last[ pattern[i] ] < i )
+ {
+ Last[ pattern[i] ] = i;
+ }
+ }
+
+ for (uintptr_t i = executable.begin(), end = executable.end() - maskSize; i <= end;)
+ {
+ uint8_t* ptr = reinterpret_cast(i);
+ ptrdiff_t j = maskSize - 1;
- for (uintptr_t i = executable.begin(), end = executable.end() - maskSize; i <= end;)
+ while((j >= 0) && pattern[j] == (ptr[j] & mask[j])) j--;
+
+ if(j < 0)
+ {
+ m_matches.emplace_back(ptr);
+
+ if (matchSuccess(i))
{
- uint8_t* ptr = reinterpret_cast(i);
- ptrdiff_t j = maskSize - 1;
-
- while ((j >= 0) && pattern[j] == (ptr[j] & mask[j])) j--;
-
- if (j < 0)
- {
- m_matches.emplace_back(ptr);
-
- if (matchSuccess(i))
- {
- break;
- }
- i++;
- }
- else i += std::max(ptrdiff_t(1), j - Last[ptr[j]]);
+ break;
}
-
- m_matched = true;
+ i++;
}
+ else i += std::max(ptrdiff_t(1), j - Last[ ptr[j] ]);
+ }
- bool basic_pattern_impl::ConsiderHint(uintptr_t offset)
- {
- uint8_t* ptr = reinterpret_cast(offset);
+ m_matched = true;
+}
+
+bool basic_pattern_impl::ConsiderHint(uintptr_t offset)
+{
+ uint8_t* ptr = reinterpret_cast(offset);
#if PATTERNS_CAN_SERIALIZE_HINTS
- const uint8_t* pattern = m_bytes.data();
- const uint8_t* mask = m_mask.data();
+ const uint8_t* pattern = m_bytes.data();
+ const uint8_t* mask = m_mask.data();
- for (size_t i = 0, j = m_mask.size(); i < j; i++)
- {
- if (pattern[i] != (ptr[i] & mask[i]))
- {
- return false;
- }
- }
+ for (size_t i = 0, j = m_mask.size(); i < j; i++)
+ {
+ if (pattern[i] != (ptr[i] & mask[i]))
+ {
+ return false;
+ }
+ }
#endif
- m_matches.emplace_back(ptr);
+ m_matches.emplace_back(ptr);
- return true;
- }
+ return true;
+}
#if PATTERNS_USE_HINTS && PATTERNS_CAN_SERIALIZE_HINTS
- void basic_pattern_impl::hint(uint64_t hash, uintptr_t address)
- {
- auto& hints = getHints();
-
- auto range = hints.equal_range(hash);
+void basic_pattern_impl::hint(uint64_t hash, uintptr_t address)
+{
+ auto& hints = getHints();
- for (auto it = range.first; it != range.second; ++it)
- {
- if (it->second == address)
- {
- return;
- }
- }
+ auto range = hints.equal_range(hash);
- hints.emplace(hash, address);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ if (it->second == address)
+ {
+ return;
}
+ }
+
+ hints.emplace(hash, address);
+}
#endif
- }
-}
\ No newline at end of file
+}
+}
diff --git a/MK11Hook/utils/Patterns.h b/MK11Hook/utils/Patterns.h
index 8c115d6..fe5d6c6 100644
--- a/MK11Hook/utils/Patterns.h
+++ b/MK11Hook/utils/Patterns.h
@@ -8,10 +8,12 @@
#pragma once
#include
+#include
#include
+#include
#include
-#if defined(_CPPUNWIND) && !defined(PATTERNS_SUPPRESS_EXCEPTIONS)
+#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(PATTERNS_SUPPRESS_EXCEPTIONS)
#define PATTERNS_ENABLE_EXCEPTIONS
#endif
@@ -35,7 +37,7 @@ namespace hook
static void count(bool countMatches) { if (!countMatches) { throw txn_exception{}; } }
};
#else
- struct exception_err_policy
+ struct exception_err_policy : public assert_err_policy
{
};
#endif
@@ -57,6 +59,11 @@ namespace hook
char* ptr = reinterpret_cast(m_pointer);
return reinterpret_cast(ptr + offset);
}
+
+ uintptr_t get_uintptr(ptrdiff_t offset = 0) const
+ {
+ return reinterpret_cast(get(offset));
+ }
};
namespace details
@@ -121,7 +128,23 @@ namespace hook
inline basic_pattern_impl(std::basic_string_view bytes, std::basic_string_view mask)
: basic_pattern_impl(get_process_base())
{
- assert(bytes.length() == mask.length());
+ assert( bytes.length() == mask.length() );
+ m_bytes = std::move(bytes);
+ m_mask = std::move(mask);
+ }
+
+ inline basic_pattern_impl(void* module, std::basic_string_view bytes, std::basic_string_view mask)
+ : basic_pattern_impl(reinterpret_cast(module))
+ {
+ assert( bytes.length() == mask.length() );
+ m_bytes = std::move(bytes);
+ m_mask = std::move(mask);
+ }
+
+ inline basic_pattern_impl(uintptr_t begin, uintptr_t end, std::basic_string_view bytes, std::basic_string_view mask)
+ : basic_pattern_impl(begin, end)
+ {
+ assert( bytes.length() == mask.length() );
m_bytes = std::move(bytes);
m_mask = std::move(mask);
}
@@ -185,18 +208,18 @@ namespace hook
template
inline auto get_first(ptrdiff_t offset = 0)
{
- return get_one().get(offset);
+ return get_one().template get(offset);
}
template
- inline Pred for_each_result(Pred&& pred)
+ inline Pred for_each_result(Pred pred)
{
EnsureMatches(UINT32_MAX);
- for (auto it : m_matches)
+ for (auto match : m_matches)
{
- std::forward(pred)(it);
+ pred(match);
}
- return std::forward(pred);
+ return pred;
}
public:
@@ -227,6 +250,11 @@ namespace hook
return pattern(std::move(pattern_string)).get_first(offset);
}
+ inline auto get_pattern_uintptr(std::string_view pattern_string, ptrdiff_t offset = 0)
+ {
+ return pattern(std::move(pattern_string)).get_one().get_uintptr(offset);
+ }
+
namespace txn
{
using pattern = hook::basic_pattern;
@@ -247,5 +275,10 @@ namespace hook
{
return pattern(std::move(pattern_string)).get_first(offset);
}
+
+ inline auto get_pattern_uintptr(std::string_view pattern_string, ptrdiff_t offset = 0)
+ {
+ return pattern(std::move(pattern_string)).get_one().get_uintptr(offset);
+ }
}
-}
\ No newline at end of file
+}