1
0
mirror of synced 2024-11-27 17:00:53 +01:00

Merge pull request #9 from ryumiyax/Refactor

Add freeze_timer / nus3bank id patch / chs_patch (voice part) for JPN39
This commit is contained in:
esuo1198 2024-11-01 18:05:14 +09:00 committed by GitHub
commit a6c6efc2a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 251 additions and 13 deletions

View File

@ -47,6 +47,8 @@ unlock_songs = true
[patches.jpn39]
# sync test mode language to attract etc
fix_language = false
# stop timer count down
freeze_timer = false
# use cn font and chineseS wordlist value
chs_patch = false
# enable one piece collab mode

1
dist/config.toml vendored
View File

@ -18,6 +18,7 @@ unlock_songs = true
[patches.jpn39]
fix_language = false
freeze_timer = false
chs_patch = false
mode_collabo025 = false
mode_collabo026 = false

View File

@ -108,4 +108,4 @@ printColour (int colour, const char *format, ...) {
SetConsoleTextAttribute (consoleHandle, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
va_end (args);
}
}

View File

@ -8,6 +8,10 @@
#include <stdlib.h>
#include <toml.h>
#include <windows.h>
#include <map>
#include <mutex>
#include <atomic>
#include <safetyhook.hpp>
typedef int8_t i8;
typedef int16_t i16;
@ -24,6 +28,7 @@ typedef double f64;
#define FUNCTION_PTR_H(returnType, function, ...) extern returnType (*function) (__VA_ARGS__)
#define PROC_ADDRESS(libraryName, procName) GetProcAddress (LoadLibrary (TEXT (libraryName)), procName)
#define PROC_ADDRESS_OFFSET(libraryName, offset) (u64)((u64)GetModuleHandle (TEXT (libraryName)) + offset)
#define BASE_ADDRESS 0x140000000
#ifdef BASE_ADDRESS
@ -49,6 +54,16 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr);
void *where##className##functionName = NULL; \
returnType implOf##className##functionName (className *This, __VA_ARGS__)
#define HOOK_MID(functionName, location, ...) \
SafetyHookMid midHook##functionName{}; \
u64 where##functionName = (location); \
void implOf##functionName (SafetyHookContext &ctx)
#define HOOK_MID_DYNAMIC(functionName, location, ...) \
SafetyHookMid midHook##functionName{}; \
u64 where##functionName = (location); \
void implOf##functionName (SafetyHookContext &ctx)
#define INSTALL_HOOK(functionName) \
{ \
MH_Initialize (); \
@ -75,6 +90,21 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr);
INSTALL_HOOK (className##functionName); \
}
#define INSTALL_HOOK_MID(functionName) \
{ \
midHook##functionName = safetyhook::create_mid(where##functionName, implOf##functionName); \
}
#define INSTALL_HOOK_MID_DYNAMIC(functionName, address) \
{ \
midHook##functionName = safetyhook::create_mid(address, implOf##functionName); \
}
#define UNINSTALL_HOOK_MID(functionName) \
{ \
midHook##functionName = {}; \
}
#define READ_MEMORY(location, type) *(type *)location
#define WRITE_MEMORY(location, type, ...) \
@ -120,6 +150,7 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr);
#define printInfo(format, ...) printColour (INFO_COLOUR, format, __VA_ARGS__)
#define printWarning(format, ...) printColour (WARNING_COLOUR, format, __VA_ARGS__)
#define printError(format, ...) printColour (ERROR_COLOUR, format, __VA_ARGS__)
#define round(num) ((num > 0) ? (int)(num + 0.5) : (int)(num - 0.5))
toml_table_t *openConfig (std::filesystem::path path);
toml_table_t *openConfigSection (toml_table_t *config, const std::string &sectionName);
@ -127,4 +158,4 @@ bool readConfigBool (toml_table_t *table, const std::string &key, bool notFoundV
int64_t readConfigInt (toml_table_t *table, const std::string &key, int64_t notFoundValue);
const std::string readConfigString (toml_table_t *table, const std::string &key, const std::string &notFoundValue);
std::vector<int64_t> readConfigIntArray (toml_table_t *table, const std::string &key, std::vector<int64_t> notFoundValue);
void printColour (int colour, const char *format, ...);
void printColour (int colour, const char *format, ...);

View File

@ -1,7 +1,7 @@
#include "../patches.h"
#include "helpers.h"
#include <safetyhook.hpp>
#include <stdio.h>
#include <iostream>
namespace patches::JPN39 {
@ -15,8 +15,13 @@ HOOK_DYNAMIC (i64, __fastcall, curl_easy_setopt, i64 a1, i64 a2, i64 a3, i64 a4,
}
FUNCTION_PTR (i64, lua_settop, PROC_ADDRESS ("lua51.dll", "lua_settop"), u64, u64);
FUNCTION_PTR (i64, lua_replace, PROC_ADDRESS ("lua51.dll", "lua_replace"), u64, u64);
FUNCTION_PTR (i64, lua_pushboolean, PROC_ADDRESS ("lua51.dll", "lua_pushboolean"), u64, u64);
FUNCTION_PTR (i64, lua_pushstring, PROC_ADDRESS ("lua51.dll", "lua_pushstring"), u64, u64);
FUNCTION_PTR (i64, lua_pushcclosure, PROC_ADDRESS ("lua51.dll", "lua_pushcclosure"), u64, u64, u64);
FUNCTION_PTR (i64, lua_toboolean, PROC_ADDRESS ("lua51.dll", "lua_toboolean"), u64, u64);
FUNCTION_PTR (i64, lua_tolstring, PROC_ADDRESS ("lua51.dll", "lua_tolstring"), u64, u64, u64);
i64
lua_pushtrue (i64 a1) {
@ -57,14 +62,96 @@ ReplaceLeaBufferAddress (const std::vector<uintptr_t> &bufferAddresses, void *ne
}
}
SafetyHookMid changeLanguageTypeHook{};
// -------------- MidHook Area --------------
void
ChangeLanguageType (SafetyHookContext &ctx) {
HOOK_MID (ChangeLanguageType, ASLR (0x1400B2016), SafetyHookContext &ctx) {
int *pFontType = (int *)ctx.rax;
if (*pFontType == 4) *pFontType = 2;
}
i64 __fastcall
lua_freeze_timer (i64 a1) {
return lua_pushtrue (a1);
}
HOOK_MID (FreezeTimer, ASLR (0x14019FF51), SafetyHookContext &ctx) {
auto a1 = ctx.rdi;
int v9 = (int)(ctx.rax + 1);
lua_pushcclosure(a1, reinterpret_cast<i64>(&lua_freeze_timer), v9);
ctx.rip = ASLR (0x14019FF65);
}
std::map<std::string, int> nus3bankMap;
int nus3bankIdCounter = 0;
std::map<std::string, bool> voiceCnExist;
bool enableSwitchVoice = false;
std::mutex nus3bankMtx;
int
get_bank_id(std::string bankName) {
if (nus3bankMap.find(bankName) == nus3bankMap.end()) {
nus3bankMap[bankName] = nus3bankIdCounter;
nus3bankIdCounter++;
}
return nus3bankMap[bankName];
}
void
check_voice_tail(std::string bankName, uint8_t* pBinfBlock, std::map<std::string, bool> &voiceExist, std::string tail) {
// check if any voice_xxx.nus3bank has xxx_cn audio inside while loading
if (enableSwitchVoice && bankName.starts_with("voice_")) {
int binfLength = *((int*)(pBinfBlock + 4));
uint8_t* pGrpBlock = pBinfBlock + 8 + binfLength;
int grpLength = *((int*)(pGrpBlock + 4));
uint8_t* pDtonBlock = pGrpBlock + 8 + grpLength;
int dtonLength = *((int*)(pDtonBlock + 4));
uint8_t* pToneBlock = pDtonBlock + 8 + dtonLength;
int toneSize = *((int*)(pToneBlock + 8));
uint8_t* pToneBase = pToneBlock + 12;
for (int i = 0; i < toneSize; i++) {
if (*((int*)(pToneBase + i * 8 + 4)) <= 0x0C) continue; // skip empty space
uint8_t* currToneBase = pToneBase + *((int*)(pToneBase + i * 8));
int titleOffset = -1;
switch (*currToneBase) {
case 0xFF: titleOffset = 9; break; // audio mark
case 0x7F: titleOffset = 5; break; // randomizer mark
default: continue; // unknown mark skip
}
if (titleOffset > 0) {
std::string title((char*)(currToneBase + titleOffset));
if (title.ends_with(tail)) {
if (voiceExist.find(bankName) == voiceExist.end() || !voiceExist[bankName]) {
voiceExist[bankName] = true;
}
return;
}
}
}
if (voiceExist.find(bankName) == voiceExist.end() || voiceExist[bankName]) {
voiceExist[bankName] = false;
}
}
}
HOOK_MID (GenNus3bankId, ASLR (0x1407B97BD), SafetyHookContext &ctx) {
std::lock_guard<std::mutex> lock(nus3bankMtx);
if ((uint8_t**)(ctx.rcx + 8) != nullptr) {
uint8_t* pNus3bankFile = *((uint8_t **)(ctx.rcx + 8));
if (pNus3bankFile[0] == 'N' && pNus3bankFile[1] == 'U' && pNus3bankFile[2] == 'S' && pNus3bankFile[3] == '3') {
int tocLength = *((int*)(pNus3bankFile + 16));
uint8_t* pPropBlock = pNus3bankFile + 20 + tocLength;
int propLength = *((int*)(pPropBlock + 4));
uint8_t* pBinfBlock = pPropBlock + 8 + propLength;
std::string bankName((char*)(pBinfBlock + 0x11));
check_voice_tail(bankName, pBinfBlock, voiceCnExist, "_cn");
ctx.rax = get_bank_id(bankName);
}
}
}
// -------------- MidHook Area End --------------
int language = 0;
const char *
languageStr () {
@ -92,17 +179,99 @@ HOOK (i64, GetCabinetLanguage, ASLR (0x1401D1A60), i64, i64 a2) {
return 1;
}
std::string
FixToneName (std::string bankName, std::string toneName) {
if (language == 2 || language == 4) {
if (voiceCnExist.find(bankName) != voiceCnExist.end() && voiceCnExist[bankName]) {
return toneName + "_cn";
}
}
return toneName;
}
int commonSize = 0;
HOOK (i64, PlaySound, ASLR (0x1404C6DC0), i64 a1) {
if (enableSwitchVoice && language != 0) {
std::string bankName((char*)lua_tolstring (a1, -3, (u64)&commonSize));
if (bankName[0] == 'v') {
lua_pushstring(a1, (u64)(FixToneName(bankName, (char*)lua_tolstring (a1, -2, (u64)&commonSize)).c_str()));
lua_replace(a1, -3);
}
}
return originalPlaySound(a1);
}
HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) {
if (enableSwitchVoice && language != 0) {
std::string bankName((char*)lua_tolstring (a1, -3, (u64)&commonSize));
if (bankName[0] == 'v') {
lua_pushstring(a1, (u64)(FixToneName(bankName, (char*)lua_tolstring (a1, -2, (u64)&commonSize)).c_str()));
lua_replace(a1, -3);
}
}
return originalPlaySoundMulti(a1);
}
FUNCTION_PTR (u64*, append_chars_to_basic_string, ASLR (0x140028DA0), u64*, char*, size_t);
u64*
FixToneNameEnso(u64* Src, std::string &bankName) {
if (language == 2 || language == 4) {
if (voiceCnExist.find(bankName) != voiceCnExist.end() && voiceCnExist[bankName]) {
Src = append_chars_to_basic_string (Src, (const char*)"_cn", 3);
}
}
return Src;
}
HOOK (bool, PlaySoundEnso, ASLR (0x1404ED590), u64* a1, u64* a2, i64 a3) {
if (enableSwitchVoice && language != 0) {
std::string bankName = a1[3] > 0x10 ? std::string(*((char**)a1)) : std::string((char*)a1);
if (bankName[0] == 'v') a2 = FixToneNameEnso(a2, bankName);
}
return originalPlaySoundEnso(a1, a2, a3);
}
HOOK (bool, PlaySoundSpecial, ASLR (0x1404ED230), u64* a1, u64* a2) {
if (enableSwitchVoice && language != 0) {
std::string bankName = a1[3] > 0x10 ? std::string(*((char**)a1)) : std::string((char*)a1);
if (bankName[0] == 'v') a2 = FixToneNameEnso(a2, bankName);
}
return originalPlaySoundSpecial(a1, a2);
}
int loaded_fail_count = 0;
HOOK (i64, LoadedBankAll, ASLR (0x1404C69F0), i64 a1) {
originalLoadedBankAll (a1);
auto result = lua_toboolean(a1, -1);
lua_settop(a1, 0);
if (result) {
loaded_fail_count = 0;
lua_pushboolean (a1, 1);
} else if (loaded_fail_count > 100) {
loaded_fail_count = 0;
lua_pushboolean (a1, 1);
} else {
loaded_fail_count += 1;
lua_pushboolean (a1, 0);
}
return 1;
}
void
Init () {
i32 xRes = 1920;
i32 yRes = 1080;
bool unlockSongs = true;
bool fixLanguage = false;
bool freezeTimer = false;
bool chsPatch = false;
bool modeCollabo025 = false;
bool modeCollabo026 = false;
bool modeAprilFool001 = false;
bool useLayeredfs = false;
auto configPath = std::filesystem::current_path () / "config.toml";
std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
if (config_ptr) {
@ -112,6 +281,7 @@ Init () {
auto jpn39 = openConfigSection (patches, "jpn39");
if (jpn39) {
fixLanguage = readConfigBool (jpn39, "fix_language", fixLanguage);
freezeTimer = readConfigBool (jpn39, "freeze_timer", freezeTimer);
chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch);
modeCollabo025 = readConfigBool (jpn39, "mode_collabo025", modeCollabo025);
modeCollabo026 = readConfigBool (jpn39, "mode_collabo026", modeCollabo026);
@ -127,6 +297,11 @@ Init () {
yRes = readConfigInt (res, "y", yRes);
}
}
auto layeredfs = openConfigSection (config_ptr.get (), "layeredfs");
if (layeredfs) {
useLayeredfs = readConfigBool (layeredfs, "enabled", useLayeredfs);
}
}
// Apply common config patch
@ -182,28 +357,57 @@ Init () {
ReplaceLeaBufferAddress (datatableBuffer3Addresses, datatableBuffer3.data ());
}
// Freeze Timer
if (freezeTimer) {
INSTALL_HOOK_MID (FreezeTimer);
}
// Use chs font/wordlist instead of cht
if (chsPatch) {
WRITE_MEMORY (ASLR (0x140CD1AE0), char, "cn_64");
WRITE_MEMORY (ASLR (0x140CD1AF0), char, "cn_32");
WRITE_MEMORY (ASLR (0x140CD1AF8), char, "cn_30");
WRITE_MEMORY (ASLR (0x140C946A0), char, "chineseSText");
WRITE_MEMORY (ASLR (0x140C946B0), char, "chineseSFontType");
bool fontExistAll = true;
const char* fontToCheck[] {"cn_30.nutexb", "cn_30.xml", "cn_32.nutexb", "cn_32.xml", "cn_64.nutexb", "cn_64.xml"};
for (int i = 0; i < 6; i++) {
if (useLayeredfs && std::filesystem::exists(std::string("..\\..\\Data_mods\\x64\\font\\") + fontToCheck[i])) continue;
if (std::filesystem::exists(std::string("..\\..\\Data\\x64\\font\\") + fontToCheck[i])) continue;
fontExistAll = false;
}
changeLanguageTypeHook = safetyhook::create_mid (ASLR (0x1400B2016), ChangeLanguageType);
if (fontExistAll) {
WRITE_MEMORY (ASLR (0x140CD1AE0), char, "cn_64");
WRITE_MEMORY (ASLR (0x140CD1AF0), char, "cn_32");
WRITE_MEMORY (ASLR (0x140CD1AF8), char, "cn_30");
WRITE_MEMORY (ASLR (0x140C946A0), char, "chineseSText");
WRITE_MEMORY (ASLR (0x140C946B0), char, "chineseSFontType");
INSTALL_HOOK_MID (ChangeLanguageType);
}
}
// Fix language
if (fixLanguage) {
INSTALL_HOOK (GetLanguage);
INSTALL_HOOK (GetLanguage); // Language will use in other place
INSTALL_HOOK (GetRegionLanguage);
INSTALL_HOOK (GetCabinetLanguage);
}
// if both chsPatch & fixLanguage enabled, try use cn voice from nus3bank
// don't worry, we will check if cn voice existed
if (chsPatch && fixLanguage) {
enableSwitchVoice = true;
INSTALL_HOOK (PlaySound);
INSTALL_HOOK (PlaySoundMulti);
INSTALL_HOOK (PlaySoundEnso);
INSTALL_HOOK (PlaySoundSpecial);
}
// Mode unlock
if (modeCollabo025) INSTALL_HOOK (AvailableMode_Collabo025);
if (modeCollabo026) INSTALL_HOOK (AvailableMode_Collabo026);
if (modeAprilFool001) INSTALL_HOOK (AvailableMode_AprilFool001);
// Fix normal song play after passing through silent song
INSTALL_HOOK_MID (GenNus3bankId);
INSTALL_HOOK (LoadedBankAll);
// Disable live check
auto amHandle = (u64)GetModuleHandle ("AMFrameWork.dll");
INSTALL_HOOK_DYNAMIC (AMFWTerminate, (void *)(amHandle + 0x42DE0));