Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions mio-modding-api/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
namespace ModAPI {
// Constant addresses
namespace Addresses {
uintptr_t g_BaseAddr;
void* g_PlayerStaminaAddr = nullptr;
void* g_PlayerVelocityXAddr = nullptr;
void* g_PlayerVelocityYAddr = nullptr;
void* g_MenuStateAddr = nullptr;
void* g_MoveByMethodAddr = nullptr;
void* g_PlayerObjAddr = nullptr;
void* g_HitEnemyAddress = nullptr;
void* g_GiveFlagAddress = nullptr;
}

// Base address for pointer chain
Expand Down Expand Up @@ -71,8 +73,11 @@ void LoadMemoryAddresses() {
uintptr_t saveArraySizeAddr = baseAddr + 0x1116bf0;

uintptr_t hitEnemyFunctionAddress = baseAddr + 0x75ed70;
uintptr_t giveFlagFunctionAddress = baseAddr + 0x060ee40;

// Store the address
ModAPI::Addresses::g_BaseAddr = baseAddr;

ModAPI::Pointers::g_PlayerLocationBasePtr = (void**)playerLocationBasePtrAddr;
ModAPI::Pointers::g_PlayerHealthBasePtr = (void**)playerHealthBasePtrAddr;
ModAPI::Pointers::g_PlayerNacreBasePtr = (void**)playerNacreBasePtrAddr;
Expand All @@ -90,6 +95,7 @@ void LoadMemoryAddresses() {
ModAPI::Addresses::g_PlayerVelocityYAddr = (void*)(plrObjAddr + 0x47C);

ModAPI::Addresses::g_HitEnemyAddress = (void*)hitEnemyFunctionAddress;
ModAPI::Addresses::g_GiveFlagAddress = (void*)giveFlagFunctionAddress;
}

extern "C" __declspec(dllexport) void ModInit(char* id) {
Expand Down
28 changes: 27 additions & 1 deletion mio-modding-api/hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace ModAPI {

NOINLINE void __cdecl ResolveOnHitEnemyHook(uintptr_t enemy_info_address, uintptr_t hit_info_address) {
// Run all functions connected to this event
for (int i = 0; i < hitenemy_hooks.size(); i++) {
for(int i = 0; i < hitenemy_hooks.size(); i++) {
hitenemy_hooks[i](enemy_info_address, hit_info_address);
}
// Run the original Enemy Hit function (at the address provided in enemyhit_trampoline)
Expand All @@ -28,6 +28,30 @@ namespace ModAPI {
hitenemy_hooks.push_back(callback);
}
}
namespace Flags {
// Functions hooked to OnHitEnemy
std::vector<std::function<void(uintptr_t, ModAPI::SaveData::GameString*, int32_t*)>> giveflag_hooks;

uintptr_t giveflag_trampoline = NULL;

NOINLINE void __cdecl ResolveOnGiveFlag(uintptr_t unknown, ModAPI::SaveData::GameString flag, int32_t amount) {
// Run all functions connected to this event
ModAPI::SaveData::GameString modifiableFlag = flag;
int32_t modifiableAmount = amount;
for(int i = 0; i < giveflag_hooks.size(); i++) {
giveflag_hooks[i](unknown, &modifiableFlag, &modifiableAmount);
}
// Run the original Enemy Hit function (at the address provided in enemyhit_trampoline)
typedef int func(uintptr_t, ModAPI::SaveData::GameString, int32_t);
func* trampoline = (func*)(giveflag_trampoline);
int i = trampoline(unknown, modifiableFlag, modifiableAmount);
}

// Enter a function to call it when an enemy is hit. Parameters are the addresses of enemy data and hit data.
MODDING_API void RunOnGiveFlag(std::function<void(uintptr_t, ModAPI::SaveData::GameString*, int32_t*)> callback) {
giveflag_hooks.push_back(callback);
}
}

namespace Time {
float g_timeScale = 1.0f;
Expand Down Expand Up @@ -81,6 +105,8 @@ namespace ModAPI {
MODDING_API void InitializeHooks() {
static PLH::NatDetour enemyhit_hook_detour = PLH::NatDetour((uintptr_t)ModAPI::Addresses::g_HitEnemyAddress, (uintptr_t)Combat::ResolveOnHitEnemyHook, &Combat::hitenemy_trampoline);
enemyhit_hook_detour.hook();
static PLH::NatDetour giveflag_hook_detour = PLH::NatDetour((uintptr_t)ModAPI::Addresses::g_GiveFlagAddress, (uintptr_t)Flags::ResolveOnGiveFlag, &Flags::giveflag_trampoline);
giveflag_hook_detour.hook();

static PLH::NatDetour rtlqpc_detour = PLH::NatDetour(
(uintptr_t)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlQueryPerformanceCounter"),
Expand Down
31 changes: 31 additions & 0 deletions mio-modding-api/mio-modding-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,16 @@ namespace ModAPI {
* instead of accessing these directly.
*/
namespace Addresses {
extern uintptr_t g_BaseAddr; ///< Base Address for the mio.exe.

extern void* g_PlayerStaminaAddr; ///< Direct address of the player's stamina value.
extern void* g_PlayerVelocityXAddr; ///< Direct address of the player's X velocity value, offset from the player object.
extern void* g_PlayerVelocityYAddr; ///< Direct address of the player's Y velocity value, offset from the player object.
extern void* g_MoveByMethodAddr; ///< Address of the game's internal move by method function.
extern void* g_PlayerObjAddr; ///< Direct address of the player object.
extern void* g_HitEnemyAddress; ///< Address of the game's internal hit enemy function.
extern void* g_MenuStateAddr; ///< Direct address of the current menu state value.
extern void* g_GiveFlagAddress; ///< Address of the game's internal give flag function.
} // namespace Addresses

/**
Expand Down Expand Up @@ -268,6 +271,10 @@ namespace ModAPI {
char* data; ///< Pointer to the string data.
uint32_t size; ///< Length of the string in bytes.
uint32_t unused; ///< Padding - do not use.
GameString(char* data) {
this->data = data;
size = strlen(data);
}
} GameString;
static_assert(sizeof(GameString) == 16, "GameString size mismatch — struct layout may be wrong");

Expand Down Expand Up @@ -362,6 +369,13 @@ namespace ModAPI {
* @return True on success, false if the entry was not found.
*/
MODDING_API bool SetSaveEntryValueFlags(const char* name, uint32_t flags);
/**
* @brief Increases the amount for a flag
* @param flag The flag to increase.
* @param amount The amount to increase the flag by.
* @return The game's internal return value from the give flag method.
*/
MODDING_API char* GiveFlag(const char* flag, int32_t amount);
}
} // namespace SaveData

Expand Down Expand Up @@ -538,6 +552,23 @@ namespace ModAPI {
MODDING_API void RunOnHitEnemy(std::function<void(uintptr_t, uintptr_t)> callback);
} // namespace Combat

/**
* @brief Hooks related to flags.
*/
namespace Flags {
/**
* @brief Registers a callback to be invoked whenever the player is given a flag.
*
* Multiple callbacks can be registered and all will fire on each hit.
*
* @param callback Function to call on enemy hit. Receives two arguments:
* - An unknown pointer to an object (uintptr_t)
* - A pointer to the GameString for the flag type, You may modify this pointer (GameString*)
* - A pointer to the amount of the flag, You may modify this pointer (int32_t*)
*/
MODDING_API void RunOnGiveFlag(std::function<void(uintptr_t, ModAPI::SaveData::GameString*, int32_t*)> callback);
} // namespace Flags

/**
* @brief Hooks related to game time.
*/
Expand Down
12 changes: 11 additions & 1 deletion mio-modding-api/save-data.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Windows.h"
#include "mio-modding-api.h"
#include <string>

using SaveEntry = ModAPI::SaveData::SaveEntry;

Expand Down Expand Up @@ -100,7 +101,16 @@ namespace ModAPI {
}
entry->value.flags = flags;
return true;
}
}
MODDING_API char* GiveFlag(const char* flag, int32_t amount) {
uintptr_t globalAddr = ModAPI::Addresses::g_BaseAddr + 0x10efbf0;
GameString flagStr = GameString((char*)flag);
return ModAPI::Util::CallAssembly<char*, uintptr_t, GameString, int32_t>(
ModAPI::Addresses::g_GiveFlagAddress,
globalAddr,
flagStr,
amount);
}
}
}
}
Loading