mirror of
https://github.com/esuo1198/TaikoArcadeLoader.git
synced 2026-09-28 01:38:10 +03:00
Merge pull request #25 from ryumiyax/experimental
Several fix & optimize
This commit is contained in:
@@ -138,6 +138,8 @@ set(SOURCES
|
||||
src/poll.cpp
|
||||
src/pollasync.cpp
|
||||
src/bnusio.cpp
|
||||
src/Windows/WindowsError.cpp
|
||||
src/Windows/MinimumLatencyAudioClient.cpp
|
||||
src/patches/amauth.cpp
|
||||
# src/patches/dxgi.cpp
|
||||
# src/patches/fpslimiter.cpp
|
||||
|
||||
@@ -34,8 +34,12 @@ version = "auto" # Patch version
|
||||
# | - JPN08: For use with Taiko JPN 08.18
|
||||
# | - JPN39: For use with Taiko JPN 39.06
|
||||
# | - CHN00: For use with Taiko CHN 00.32
|
||||
<<<<<<< HEAD
|
||||
unlock_songs = true # Self-explanatory
|
||||
local_files = true # Only set this to false if you're using this on a Nijiiro Cabinet, running on BNA1
|
||||
=======
|
||||
unlock_songs = true
|
||||
>>>>>>> 684ee61 (Several fix & optimize)
|
||||
|
||||
[patches.chn00] # These patches are only available for version CHN00
|
||||
fix_language = false # Sync test mode language to attract etc
|
||||
@@ -63,13 +67,15 @@ model_res_rate = 1.0 # Don-Model resolution rate (currently JPN39 only)
|
||||
|
||||
|
||||
[audio]
|
||||
wasapi_shared = false # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency.
|
||||
real = true # Reduce audio latency when you are using "High Definition Audio" driver
|
||||
wasapi_shared = true # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency.
|
||||
asio = false # Use asio audio mode
|
||||
asio_driver = "ASIO4ALL v2" # Asio driver name
|
||||
# | If you're not using asio4all, open up regedit then navigate to HKEY_LOCAL_MACHINE\SOFTWARE\ASIO for your driver's name.
|
||||
# | It is case-sensitive.
|
||||
|
||||
|
||||
|
||||
[qr]
|
||||
image_path = "" # Path to the image of the QR Code you want to use
|
||||
|
||||
@@ -85,6 +91,8 @@ song_no = [] # Song noes used for custom folder
|
||||
[controller]
|
||||
wait_period = 0 # Input interval (if using taiko drum controller, should be set to 0)
|
||||
analog_input = false # Use analog input (you need a compatible controller, this allows playing small and big notes like on arcade cabinets)
|
||||
global_keyboard = false # Accept keyboard input even if Taiko.exe is not foreground
|
||||
|
||||
|
||||
|
||||
[keyboard]
|
||||
@@ -151,7 +159,7 @@ Clone this repository, open *cmd* and run the following commands:
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||
|
||||
# Configure the build folder (this is only needed the first time)
|
||||
cmake -B build -S . -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release
|
||||
cmake -B build -S . -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION="10.0.26100.0"
|
||||
|
||||
# Build TaikoArcadeLoader
|
||||
cmake --build build --config Release --target bnusio
|
||||
|
||||
Vendored
+3
-1
@@ -43,7 +43,8 @@ model_res_rate = 1.0 # Don-Model resolution rate (currently JPN39 only)
|
||||
|
||||
|
||||
[audio]
|
||||
wasapi_shared = false # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency.
|
||||
real = true # Reduce audio latency when you are using "High Definition Audio" driver
|
||||
wasapi_shared = true # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency.
|
||||
asio = false # Use asio audio mode
|
||||
asio_driver = "ASIO4ALL v2" # Asio driver name
|
||||
# | If you're not using asio4all, open up regedit then navigate to HKEY_LOCAL_MACHINE\SOFTWARE\ASIO for your driver's name.
|
||||
@@ -65,6 +66,7 @@ song_no = [] # Song noes used for custom folder
|
||||
[controller]
|
||||
wait_period = 0 # Input interval (if using taiko drum controller, should be set to 0)
|
||||
analog_input = false # Use analog input (you need a compatible controller, this allows playing small and big notes like on arcade cabinets)
|
||||
global_keyboard = false # Accept keyboard input even if Taiko.exe is not foreground
|
||||
|
||||
|
||||
[keyboard]
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
namespace miniant {
|
||||
|
||||
class ExpectedError {
|
||||
public:
|
||||
explicit ExpectedError(std::string message) noexcept:
|
||||
m_message(std::move(message)) {}
|
||||
|
||||
explicit ExpectedError(const char* message):
|
||||
m_message(message) {}
|
||||
|
||||
ExpectedError(const ExpectedError&) = default;
|
||||
ExpectedError(ExpectedError&&) noexcept = default;
|
||||
|
||||
ExpectedError& operator= (const ExpectedError&) = default;
|
||||
ExpectedError& operator= (ExpectedError&&) noexcept = default;
|
||||
|
||||
virtual ~ExpectedError() = default;
|
||||
|
||||
virtual std::string GetMessage() const {
|
||||
return m_message;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#include "MinimumLatencyAudioClient.h"
|
||||
|
||||
#include <Audioclient.h>
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace miniant::Windows;
|
||||
using namespace miniant::Windows::WasapiLatency;
|
||||
|
||||
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
|
||||
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
|
||||
const IID IID_IAudioClient3 = __uuidof(IAudioClient3);
|
||||
|
||||
MinimumLatencyAudioClient::MinimumLatencyAudioClient(MinimumLatencyAudioClient&& other) noexcept {
|
||||
assert(other.m_pAudioClient != nullptr);
|
||||
assert(other.m_pFormat != nullptr);
|
||||
|
||||
m_pAudioClient = other.m_pAudioClient;
|
||||
m_pFormat = other.m_pFormat;
|
||||
|
||||
other.m_pAudioClient = nullptr;
|
||||
other.m_pFormat = nullptr;
|
||||
}
|
||||
MinimumLatencyAudioClient::MinimumLatencyAudioClient(void* pAudioClient, void* pFormat) :
|
||||
m_pAudioClient(pAudioClient), m_pFormat(pFormat) {}
|
||||
|
||||
MinimumLatencyAudioClient::~MinimumLatencyAudioClient() {
|
||||
Uninitialise();
|
||||
}
|
||||
|
||||
MinimumLatencyAudioClient& MinimumLatencyAudioClient::operator= (MinimumLatencyAudioClient&& rhs) noexcept {
|
||||
assert(rhs.m_pAudioClient != nullptr);
|
||||
assert(rhs.m_pFormat != nullptr);
|
||||
|
||||
Uninitialise();
|
||||
m_pAudioClient = rhs.m_pAudioClient;
|
||||
m_pFormat = rhs.m_pFormat;
|
||||
|
||||
rhs.m_pAudioClient = nullptr;
|
||||
rhs.m_pFormat = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MinimumLatencyAudioClient::Uninitialise() {
|
||||
if (m_pAudioClient == nullptr) {
|
||||
assert(m_pFormat == nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_pFormat != nullptr);
|
||||
|
||||
static_cast<IAudioClient3*>(m_pAudioClient)->Release();
|
||||
m_pAudioClient = nullptr;
|
||||
|
||||
CoTaskMemFree(m_pFormat);
|
||||
m_pFormat = nullptr;
|
||||
}
|
||||
|
||||
std::expected<MinimumLatencyAudioClient::Properties, WindowsError> MinimumLatencyAudioClient::GetProperties() const {
|
||||
Properties properties;
|
||||
HRESULT hr = static_cast<IAudioClient3*>(m_pAudioClient)->GetSharedModeEnginePeriod(
|
||||
static_cast<WAVEFORMATEX*>(m_pFormat),
|
||||
&properties.defaultBufferSize,
|
||||
&properties.fundamentalBufferSize,
|
||||
&properties.minimumBufferSize,
|
||||
&properties.maximumBufferSize);
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
properties.sampleRate = static_cast<WAVEFORMATEX*>(m_pFormat)->nSamplesPerSec;
|
||||
properties.bitsPerSample = static_cast<WAVEFORMATEX*>(m_pFormat)->wBitsPerSample;
|
||||
properties.numChannels = static_cast<WAVEFORMATEX*>(m_pFormat)->nChannels;
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::expected<MinimumLatencyAudioClient, WindowsError> MinimumLatencyAudioClient::Start() {
|
||||
|
||||
HRESULT hr = CoInitialize (nullptr);
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
IMMDeviceEnumerator* pEnumerator;
|
||||
hr = CoCreateInstance(
|
||||
CLSID_MMDeviceEnumerator, nullptr,
|
||||
CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator,
|
||||
reinterpret_cast<void**>(&pEnumerator));
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
IMMDevice* pDevice;
|
||||
hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
IAudioClient3* pAudioClient;
|
||||
hr = pDevice->Activate(IID_IAudioClient3, CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&pAudioClient));
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
WAVEFORMATEX* pFormat;
|
||||
hr = pAudioClient->GetMixFormat(&pFormat);
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
UINT32 defaultPeriodInFrames;
|
||||
UINT32 fundamentalPeriodInFrames;
|
||||
UINT32 minPeriodInFrames;
|
||||
UINT32 maxPeriodInFrames;
|
||||
hr = pAudioClient->GetSharedModeEnginePeriod(
|
||||
pFormat,
|
||||
&defaultPeriodInFrames,
|
||||
&fundamentalPeriodInFrames,
|
||||
&minPeriodInFrames,
|
||||
&maxPeriodInFrames);
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
hr = pAudioClient->InitializeSharedAudioStream(
|
||||
0,
|
||||
minPeriodInFrames,
|
||||
pFormat, nullptr);
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
hr = pAudioClient->Start();
|
||||
if (hr != S_OK) {
|
||||
return std::unexpected(WindowsError());
|
||||
}
|
||||
|
||||
return MinimumLatencyAudioClient(pAudioClient, pFormat);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "WindowsError.h"
|
||||
|
||||
#include <expected>
|
||||
|
||||
namespace miniant::Windows::WasapiLatency {
|
||||
|
||||
class MinimumLatencyAudioClient {
|
||||
public:
|
||||
struct Properties {
|
||||
uint32_t defaultBufferSize;
|
||||
uint32_t fundamentalBufferSize;
|
||||
uint32_t minimumBufferSize;
|
||||
uint32_t maximumBufferSize;
|
||||
uint32_t sampleRate;
|
||||
uint16_t bitsPerSample;
|
||||
uint16_t numChannels;
|
||||
};
|
||||
|
||||
MinimumLatencyAudioClient(MinimumLatencyAudioClient&& other) noexcept;
|
||||
~MinimumLatencyAudioClient();
|
||||
|
||||
MinimumLatencyAudioClient &operator= (MinimumLatencyAudioClient &&rhs) noexcept;
|
||||
|
||||
std::expected<Properties, WindowsError> GetProperties() const;
|
||||
|
||||
static std::expected<MinimumLatencyAudioClient, WindowsError> Start();
|
||||
|
||||
private:
|
||||
void* m_pAudioClient;
|
||||
void* m_pFormat;
|
||||
|
||||
MinimumLatencyAudioClient(void* pAudioClient, void* pFormat);
|
||||
|
||||
void Uninitialise();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "WindowsError.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
using namespace miniant::Windows;
|
||||
|
||||
std::string GetErrorMessage() {
|
||||
DWORD lastError = ::GetLastError();
|
||||
return "Last error: " + std::to_string(lastError);
|
||||
}
|
||||
|
||||
WindowsError::WindowsError():
|
||||
ExpectedError(GetErrorMessage()) {}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "ExpectedError.h"
|
||||
|
||||
namespace miniant::Windows {
|
||||
|
||||
class WindowsError : public ExpectedError {
|
||||
public:
|
||||
WindowsError();
|
||||
|
||||
WindowsError(std::string message) noexcept:
|
||||
ExpectedError(std::move(message)) {}
|
||||
|
||||
WindowsError(const char* message):
|
||||
ExpectedError(message) {}
|
||||
};
|
||||
|
||||
}
|
||||
+11
-13
@@ -141,7 +141,10 @@ GetGameVersion () {
|
||||
case GameVersion::JPN08:
|
||||
case GameVersion::JPN39:
|
||||
case GameVersion::CHN00: break;
|
||||
default: MessageBoxA (nullptr, "Unknown game version", nullptr, MB_OK); ExitProcess (0);
|
||||
default: {
|
||||
LogMessage (LogLevel::ERROR, "Detected GameVersion is Unsupported!");
|
||||
MessageBoxA (nullptr, "Unsupported game version", nullptr, MB_OK); ExitProcess (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,18 +278,13 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
|
||||
InitializeLogger (GetLogLevel (logLevelStr), logToFile, logPath);
|
||||
LogMessage (LogLevel::INFO, "Application started.");
|
||||
|
||||
if (version == "auto") {
|
||||
GetGameVersion ();
|
||||
} else if (version == "JPN00") {
|
||||
gameVersion = GameVersion::JPN00;
|
||||
} else if (version == "JPN08") {
|
||||
gameVersion = GameVersion::JPN08;
|
||||
} else if (version == "JPN39") {
|
||||
gameVersion = GameVersion::JPN39;
|
||||
} else if (version == "CHN00") {
|
||||
gameVersion = GameVersion::CHN00;
|
||||
} else {
|
||||
LogMessage (LogLevel::ERROR, "GameVersion is UNKNOWN!");
|
||||
if (version == "auto") GetGameVersion ();
|
||||
else if (version == "JPN00") gameVersion = GameVersion::JPN00;
|
||||
else if (version == "JPN08") gameVersion = GameVersion::JPN08;
|
||||
else if (version == "JPN39") gameVersion = GameVersion::JPN39;
|
||||
else if (version == "CHN00") gameVersion = GameVersion::CHN00;
|
||||
else {
|
||||
LogMessage (LogLevel::ERROR, "Input GameVersion is UNKNOWN!");
|
||||
MessageBoxA (nullptr, "Unknown patch version", nullptr, MB_OK);
|
||||
ExitProcess (0);
|
||||
}
|
||||
|
||||
+1
-4
@@ -3,10 +3,7 @@
|
||||
|
||||
static void
|
||||
toml_myfree (void *p) {
|
||||
if (p) {
|
||||
const char *pp = static_cast<char *> (p);
|
||||
delete[] pp;
|
||||
}
|
||||
if (p) free (p);
|
||||
}
|
||||
|
||||
toml_table_t *
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "patches.h"
|
||||
#include "../Windows/MinimumLatencyAudioClient.h"
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
|
||||
@@ -18,6 +19,7 @@ typedef struct nusc_init_config {
|
||||
void *wasapi_audioSes;
|
||||
} nusc_init_config_t;
|
||||
|
||||
bool real = true;
|
||||
bool wasapiShared = true;
|
||||
bool asio = false;
|
||||
std::string asioDriver;
|
||||
@@ -56,6 +58,22 @@ SetVolumeRate (float rate) {
|
||||
volumeRate = rate;
|
||||
}
|
||||
|
||||
int
|
||||
ReduceAudioLatency () {
|
||||
// Start the low-latency audio client
|
||||
if (const auto audioClient = miniant::Windows::WasapiLatency::MinimumLatencyAudioClient::Start (); !audioClient) {
|
||||
LogMessage (LogLevel::INFO, "Unable to Reduce Audio Latency");
|
||||
return 1; // Exit with error
|
||||
} else {
|
||||
auto properties = audioClient->GetProperties ();
|
||||
auto prop = properties.value();
|
||||
double currentDelay = prop.minimumBufferSize * 1000.0 / prop.sampleRate;
|
||||
double defaultDelay = prop.defaultBufferSize * 1000.0 / prop.sampleRate;
|
||||
LogMessage (LogLevel::INFO, "Audio latency: {:.2f}ms -> {:.2f}ms", defaultDelay, currentDelay);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Init () {
|
||||
LogMessage (LogLevel::INFO, "Init Audio patches");
|
||||
@@ -64,12 +82,16 @@ Init () {
|
||||
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
|
||||
if (config_ptr) {
|
||||
if (const auto audio = openConfigSection (config_ptr.get (), "audio")) {
|
||||
real = readConfigBool (audio, "real", real);
|
||||
wasapiShared = readConfigBool (audio, "wasapi_shared", wasapiShared);
|
||||
asio = readConfigBool (audio, "asio", asio);
|
||||
asioDriver = readConfigString (audio, "asio_driver", asioDriver);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (real) ReduceAudioLatency ();
|
||||
|
||||
switch (gameVersion) {
|
||||
case GameVersion::JPN00: {
|
||||
INSTALL_FAST_HOOK_DYNAMIC (NUSCDeviceInit, ASLR (0x140552160));
|
||||
|
||||
+22
-13
@@ -114,7 +114,9 @@ Init () {
|
||||
languageData = calloc (languages.size () * languages.size () * 0x70 * 0x5, sizeof (u8));
|
||||
|
||||
switch (gameVersion) {
|
||||
default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break;
|
||||
default: break;
|
||||
case GameVersion::JPN00: break;
|
||||
case GameVersion::JPN08: break;
|
||||
case GameVersion::JPN39: {
|
||||
taiko_mapping = (Taiko_mapping)ASLR (0x140369B60);
|
||||
TestMode::RegisterModify (
|
||||
@@ -167,6 +169,7 @@ Init () {
|
||||
}
|
||||
);
|
||||
} break;
|
||||
case GameVersion::CHN00: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,11 +373,13 @@ bool titleExistSeason = true, titleExistMaid = true, titleExistMaidCn = true;
|
||||
std::string seasonNulm = "title_season.nulm", seasonNutexb = "title_" + season () + ".nutexb";
|
||||
std::string maidNulmCn = "title_maid.nulm", maidNutexbCn = "title_maid.nutexb";
|
||||
std::string maidNulm = "title_maid.nulm", maidNutexb = "title_maid.nutexb";
|
||||
TestMode::Value *titleScreen = TestMode::CreateValue (L"ModTitleScreen");
|
||||
TestMode::Value *theme = TestMode::CreateValue (L"ModTheme");
|
||||
void
|
||||
Init () {
|
||||
switch (gameVersion) {
|
||||
default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break;
|
||||
default: break;
|
||||
case GameVersion::JPN00: break;
|
||||
case GameVersion::JPN08: break;
|
||||
case GameVersion::JPN39: {
|
||||
bool demoMovieExistAll = true;
|
||||
const char *movieToCheck[]{"movie\\attractdemo_cn_cn.wmv", "sound\\attractdemo_cn_cn.nus3bank"};
|
||||
@@ -439,25 +444,25 @@ Init () {
|
||||
|
||||
if (titleExistSeason || (titleExistMaid && titleExistMaidCn)) {
|
||||
TestMode::RegisterItem (
|
||||
L"<select-item label=\"TITLE SCREEN(NEED FILES)\" param-offset-x=\"35\" replace-text=\"0:DEFAULT, 1:SEASON(CHN), "
|
||||
L"2:MAID\" group=\"Setting\" id=\"ModTitleScreen\" max=\"2\" min=\"0\" default=\"0\"/>",
|
||||
L"<select-item label=\"THEME\" param-offset-x=\"35\" replace-text=\"0:DEFAULT, 1:SEASON(CHN), "
|
||||
L"2:MAID\" group=\"Setting\" id=\"ModTheme\" max=\"2\" min=\"0\" default=\"0\"/>",
|
||||
[&](){
|
||||
LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string {
|
||||
if (currentFileName.starts_with ("F:\\lumen\\") || currentFileName.find ("title") == std::string::npos) return "";
|
||||
if (currentFileName.ends_with ("\\title.nulm")) {
|
||||
if (language == 4 && titleScreen->Read () == 1 && titleExistSeason) return seasonNulm;
|
||||
if (language == 4 && titleScreen->Read () == 2 && titleExistMaidCn) return maidNulmCn;
|
||||
if (titleScreen->Read () == 2 && titleExistMaid) return maidNulm;
|
||||
if (language == 4 && theme->Read () == 1 && titleExistSeason) return seasonNulm;
|
||||
if (language == 4 && theme->Read () == 2 && titleExistMaidCn) return maidNulmCn;
|
||||
if (theme->Read () == 2 && titleExistMaid) return maidNulm;
|
||||
} else if (currentFileName.ends_with ("\\title.nutexb")) {
|
||||
LogMessage (LogLevel::DEBUG, "nutexb");
|
||||
if (language == 4 && titleScreen->Read () == 1 && titleExistSeason) return seasonNutexb;
|
||||
if (language == 4 && titleScreen->Read () == 2 && titleExistMaidCn) return maidNutexbCn;
|
||||
if (titleScreen->Read () == 2 && titleExistMaid) return maidNutexb;
|
||||
if (language == 4 && theme->Read () == 1 && titleExistSeason) return seasonNutexb;
|
||||
if (language == 4 && theme->Read () == 2 && titleExistMaidCn) return maidNutexbCn;
|
||||
if (theme->Read () == 2 && titleExistMaid) return maidNutexb;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string {
|
||||
if (titleScreen->Read () != 2 || currentFileName.starts_with ("F:\\lumen\\") || currentFileName.find ("\\lumen\\") == std::string::npos) return "";
|
||||
if (theme->Read () != 2 || currentFileName.starts_with ("F:\\lumen\\") || currentFileName.find ("\\lumen\\") == std::string::npos) return "";
|
||||
std::string fileName = std::string (currentFileName);
|
||||
fileName = replace (fileName, "\\lumen\\", "\\lumen_maid\\");
|
||||
if (std::filesystem::exists (fileName)) return fileName;
|
||||
@@ -466,6 +471,7 @@ Init () {
|
||||
});
|
||||
}
|
||||
} break;
|
||||
case GameVersion::CHN00: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -657,7 +663,9 @@ CnFontPatches () {
|
||||
void
|
||||
Init () {
|
||||
switch (gameVersion) {
|
||||
default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break;
|
||||
default: break;
|
||||
case GameVersion::JPN00: break;
|
||||
case GameVersion::JPN08: break;
|
||||
case GameVersion::JPN39: {
|
||||
languageFix = [](int lang){ return lang == 4 ? 2 : lang; };
|
||||
taiko_string = (Taiko_string)ASLR (0x1400203B0);
|
||||
@@ -670,6 +678,7 @@ Init () {
|
||||
Language::Lumen::Init ();
|
||||
Language::Voice::Init ();
|
||||
} break;
|
||||
case GameVersion::CHN00: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,4 +133,16 @@ void Init ();
|
||||
namespace UnlimitSong {
|
||||
void Init ();
|
||||
} // namespace UnlimitSong
|
||||
namespace Wordlist {
|
||||
typedef u64 (*RefDataTableManager) (u64);
|
||||
typedef struct {
|
||||
std::string key;
|
||||
std::string text;
|
||||
int fontType;
|
||||
} WordInfo;
|
||||
void Init ();
|
||||
void SetupAccessor (u64 appAccessor, RefDataTableManager refDataTableManager);
|
||||
WordInfo *GetWordInfo (std::string &key);
|
||||
void SetWordInfo (WordInfo *wordInfo);
|
||||
}
|
||||
} // namespace patches
|
||||
|
||||
+86
-111
@@ -242,10 +242,8 @@ std::vector<RegisteredModify *> registeredModifies = {};
|
||||
std::wstring moddedInitial = L"";
|
||||
std::wstring modded = L"";
|
||||
|
||||
std::wstring originalDeviceInitialize = L"";
|
||||
std::wstring usingDeviceInitialize = L"";
|
||||
std::wstring moddedDeviceInitialize = L"DeviceInitialize_mod.xml";
|
||||
std::wstring originalTestMode = L"";
|
||||
std::wstring usingTestMode = L"";
|
||||
std::wstring moddedTestMode = L"TestMode_mod.xml";
|
||||
|
||||
@@ -268,20 +266,30 @@ FAST_HOOK_DYNAMIC (void, SceneFirstInitialize, u64 a1, u64 a2, u64 a3) {
|
||||
originalSceneFirstInitialize.fastcall<char *> (a1, a2, a3);
|
||||
}
|
||||
|
||||
std::wstring
|
||||
replaceFileName (std::wstring fullFileName, std::wstring usingLastFileName) {
|
||||
size_t lastPosition = fullFileName.find_last_of (L"/");
|
||||
if (lastPosition == -1) return usingLastFileName;
|
||||
else return fullFileName.substr(0, lastPosition) + usingLastFileName;
|
||||
}
|
||||
|
||||
FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFileName) {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
const auto originalFileName = std::wstring (lFileName);
|
||||
LogMessage (LogLevel::DEBUG, L"Begin Loading {}", originalFileName);
|
||||
std::wstring fileName = originalFileName;
|
||||
if (fileName.ends_with (originalDeviceInitialize)) {
|
||||
if (fileName.find (L"/DeviceInitialize") != -1) {
|
||||
if (moddedInitial == L"") {
|
||||
fileName = replace (originalFileName, originalDeviceInitialize, usingDeviceInitialize);
|
||||
if (usingDeviceInitialize != L"") {
|
||||
fileName = replaceFileName (originalFileName, usingDeviceInitialize);
|
||||
} else fileName = originalFileName;
|
||||
LogMessage (LogLevel::DEBUG, L"final path: {}", fileName);
|
||||
if (pugi::xml_document doc; !doc.load_file (fileName.c_str ())) {
|
||||
LogMessage (LogLevel::ERROR, L"Loading DeviceInitialize structure failed! path: " + fileName);
|
||||
moddedInitial = originalFileName;
|
||||
fileName = originalFileName;
|
||||
} else {
|
||||
const std::wstring modFileName = replace (originalFileName, originalDeviceInitialize, moddedDeviceInitialize);
|
||||
const std::wstring modFileName = replaceFileName (originalFileName, moddedDeviceInitialize);
|
||||
const pugi::xpath_query dongleQuery = pugi::xpath_query (L"/root/menu[@id='TopMenu']/layout[@type='Center']/select-item[@id='DongleItem']");
|
||||
const pugi::xml_node dongleItem = doc.select_node (dongleQuery).node ();
|
||||
pugi::xml_node talItem = dongleItem.parent ().append_copy (dongleItem);
|
||||
@@ -295,16 +303,19 @@ FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t
|
||||
fileName = modFileName;
|
||||
}
|
||||
} else fileName = moddedInitial;
|
||||
} else if (fileName.ends_with (originalTestMode)) {
|
||||
} else if (fileName.find (L"/TestMode") != -1) {
|
||||
if (modded == L"") {
|
||||
if (!((RegisteredMenu*)modManager)->items.empty () || registeredSingleItems.empty () || !registeredModifies.empty ()) {
|
||||
fileName = replace (originalFileName, originalTestMode, usingTestMode);
|
||||
if (usingTestMode != L"") {
|
||||
fileName = replaceFileName (originalFileName, usingTestMode);
|
||||
} else fileName = originalFileName;
|
||||
LogMessage (LogLevel::DEBUG, L"final path: {}", fileName);
|
||||
if (pugi::xml_document doc; !doc.load_file (fileName.c_str ())) {
|
||||
LogMessage (LogLevel::ERROR, L"Loading TestMode structure failed! path: " + fileName);
|
||||
modded = originalFileName;
|
||||
fileName = originalFileName;
|
||||
} else {
|
||||
const std::wstring modFileName = replace (originalFileName, originalTestMode, moddedTestMode);
|
||||
const std::wstring modFileName = replaceFileName (originalFileName, moddedTestMode);
|
||||
if (!((RegisteredMenu*)modManager)->items.empty ()) {
|
||||
LogMessage (LogLevel::DEBUG, "Begin generate Mod Manager menu");
|
||||
pugi::xpath_query menuQuery
|
||||
@@ -347,124 +358,90 @@ CommonModify () {
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"default").set_value (L"0"); }, [&] {});
|
||||
}
|
||||
|
||||
void
|
||||
LocalizationCHT () {
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='TopMenu']/layout[@type='Center']/menu-item[@menu='ModManagerMenu']",
|
||||
[&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"模組管理"); }, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Header']/text-item",
|
||||
[&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"模組管理"); }, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModFixLanguage']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"修復語言");
|
||||
node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModUnlockSongs']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"解鎖歌曲");
|
||||
node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓, 2:強制");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModFreezeTimer']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"凍結計時");
|
||||
node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo024']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"鬼滅之刃模式");
|
||||
node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo025']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"航海王模式");
|
||||
node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo026']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"AI粗品模式");
|
||||
node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeAprilFool001']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"青春之達人模式");
|
||||
node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModInstantResult']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"即時保存");
|
||||
node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓");
|
||||
}, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/menu-item[@menu='TopMenu']",
|
||||
[&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"離開"); }, [](){}
|
||||
);
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='AttractDemoItem']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"演示遊玩影片");
|
||||
node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓");
|
||||
}, [](){}
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
LocalizationCHS () {
|
||||
RegisterModify (
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='TopMenu']/layout[@type='Center']/menu-item[@menu='ModManagerMenu']",
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"label").set_value (L"模组管理"); }, [] {});
|
||||
RegisterModify (
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"label").set_value (L"模组管理"); }, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Header']/text-item",
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"label").set_value (L"模组管理"); }, [] {});
|
||||
RegisterModify (
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"label").set_value (L"模组管理"); }, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModUnlockSongs']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"解锁歌曲");
|
||||
node.attribute (L"replace-text").set_value (L"0:禁用, 1:启用, 2:强制");
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModFreezeTimer']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"冻结计时");
|
||||
node.attribute (L"label").set_value (L"冻结计时器");
|
||||
node.attribute (L"replace-text").set_value (L"0:禁用, 1:启用");
|
||||
},
|
||||
[] {});
|
||||
RegisterModify (
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo024']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"鬼灭之刃模式");
|
||||
node.attribute (L"replace-text").set_value (L"0:默认, 1:启用, 2:仅刷卡");
|
||||
},
|
||||
[] {});
|
||||
RegisterModify (
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo025']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"航海王模式");
|
||||
node.attribute (L"replace-text").set_value (L"0:默认, 1:启用, 2:仅刷卡");
|
||||
},
|
||||
[] {});
|
||||
RegisterModify (
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo026']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"AI粗品模式");
|
||||
node.attribute (L"replace-text").set_value (L"0:默认, 1:启用, 2:仅刷卡");
|
||||
},
|
||||
[] {});
|
||||
RegisterModify (
|
||||
}, [](){});
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeAprilFool001']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"青春之达人模式");
|
||||
node.attribute(L"replace-text").set_value(L"0:默认, 1:启用, 2:仅刷卡");
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModInstantResult']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"即时上传成绩");
|
||||
node.attribute (L"replace-text").set_value (L"0:禁用, 1:启用");
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModTheme']",
|
||||
[&] (const pugi::xml_node &node) {
|
||||
node.attribute (L"label").set_value (L"界面主题");
|
||||
node.attribute (L"replace-text").set_value (L"0:默认, 1:四季(仅中文), 2:秋叶原女仆");
|
||||
}, [](){});
|
||||
TestMode::RegisterModify (
|
||||
L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/menu-item[@menu='TopMenu']",
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"label").set_value (L"离开"); }, [] {});
|
||||
[&] (const pugi::xml_node &node) { node.attribute (L"label").set_value (L"离开"); }, [](){});
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='AttractDemoItem']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"演示游玩影片");
|
||||
node.attribute(L"replace-text").set_value(L"0:关闭, 1:开启");
|
||||
}, [](){});
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"文本语言");
|
||||
const wchar_t *vals = node.attribute(L"replace-text").value ();
|
||||
std::wstring langaugeReplace = std::wstring (vals);
|
||||
langaugeReplace = replace (langaugeReplace, L"JPN", L"日语");
|
||||
langaugeReplace = replace (langaugeReplace, L"ENG", L"英语");
|
||||
langaugeReplace = replace (langaugeReplace, L"zh-tw", L"繁体中文");
|
||||
langaugeReplace = replace (langaugeReplace, L"KOR", L"韩语");
|
||||
langaugeReplace = replace (langaugeReplace, L"zh-cn", L"简体中文");
|
||||
node.attribute(L"replace-text").set_value(langaugeReplace.c_str ());
|
||||
}, [](){});
|
||||
TestMode::RegisterModify(
|
||||
L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='VoiceLanguageItem']",
|
||||
[&](pugi::xml_node &node) {
|
||||
node.attribute(L"label").set_value(L"语音语言");
|
||||
node.attribute(L"replace-text").set_value(L"0:日语, 1:中文");
|
||||
}, [](){});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -478,14 +455,12 @@ Init () {
|
||||
for (auto method : hooks) method ();
|
||||
|
||||
switch (gameVersion) {
|
||||
case GameVersion::UNKNOWN: break;
|
||||
case GameVersion::JPN00: break;
|
||||
case GameVersion::JPN08: break;
|
||||
case GameVersion::JPN39: {
|
||||
INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeLoading, ASLR (0x1404793D0));
|
||||
INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600));
|
||||
INSTALL_FAST_HOOK_DYNAMIC (SceneFirstInitialize, ASLR (0x1404574B0));
|
||||
originalDeviceInitialize = L"DeviceInitialize.xml";
|
||||
if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_china.xml")) {
|
||||
usingDeviceInitialize = L"DeviceInitialize_china.xml";
|
||||
patches.push_back (safetyhook::create_mid (ASLR (0x140465549), [](SafetyHookContext &ctx)
|
||||
@@ -496,13 +471,13 @@ Init () {
|
||||
WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加载中.\0");
|
||||
WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加载中..\0");
|
||||
WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加载中...\0");
|
||||
} else usingDeviceInitialize = originalDeviceInitialize;
|
||||
originalTestMode = L"TestMode.xml";
|
||||
}
|
||||
if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_china.xml")) {
|
||||
usingTestMode = L"TestMode_china.xml";
|
||||
patches.push_back (safetyhook::create_mid (ASLR (0x14047C603), [](SafetyHookContext &ctx)
|
||||
{ ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x14047C610); })); // TestMode = DeviceInitialize
|
||||
} else usingTestMode = originalTestMode;
|
||||
LocalizationCHS ();
|
||||
}
|
||||
} break;
|
||||
case GameVersion::CHN00: break;
|
||||
}
|
||||
|
||||
@@ -301,9 +301,10 @@ MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) {
|
||||
|
||||
FAST_HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) {
|
||||
LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]);
|
||||
a3[2] = (DWORD)(float)120.0;
|
||||
// a3[0] = xRes;
|
||||
// a3[1] = yRes;
|
||||
// LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]);
|
||||
LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]);
|
||||
return originalAcquireMostCompatibleDisplayMode.fastcall<DWORD *> (a1, a2, a3);
|
||||
}
|
||||
|
||||
@@ -363,23 +364,6 @@ Init () {
|
||||
WRITE_MEMORY (ASLR (0x1404F3D5B), i32, donModelX);
|
||||
WRITE_MEMORY (ASLR (0x1404F3D62), i32, donModelY);
|
||||
}
|
||||
// // DonSystem::Renderer::Renderer
|
||||
// WRITE_MEMORY (ASLR (0x1404FBF33), i32, xRes);
|
||||
// WRITE_MEMORY (ASLR (0x1404FBF3A), i32, yRes);
|
||||
// // DonSystem::Renderer::CreateOnpuPass
|
||||
// WRITE_MEMORY (ASLR (0x1404FCF77), i32, xRes);
|
||||
// WRITE_MEMORY (ASLR (0x1404FCF81), i32, yRes / 2);
|
||||
// // nu::LightManager::LightManager
|
||||
// WRITE_MEMORY (ASLR (0x1406BED7A), i32, xRes);
|
||||
// WRITE_MEMORY (ASLR (0x1406BED82), i32, yRes);
|
||||
// WRITE_MEMORY (ASLR (0x1406BEF26), i32, xRes);
|
||||
// WRITE_MEMORY (ASLR (0x1406BEF33), i32, yRes);
|
||||
// // google::protobuf::TextFormat::Parser::ParserImpl::ConsumeField
|
||||
// WRITE_MEMORY (ASLR (0x1406F7E47), i32, xRes);
|
||||
// // google::protobuf::DescriptorBuilder::AddSymbol
|
||||
// WRITE_MEMORY (ASLR (0x140719191), i32, xRes);
|
||||
// nuscDecoderCalcObjectSize
|
||||
// WRITE_MEMORY (ASLR (0x140719191), i32, xRes);
|
||||
|
||||
if (!vsync) WRITE_MEMORY (ASLR (0x14064C7E9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90);
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "constants.h"
|
||||
#include "helpers.h"
|
||||
#include "patches.h"
|
||||
|
||||
extern GameVersion gameVersion;
|
||||
|
||||
namespace patches::Wordlist {
|
||||
u64 GetWordInfoAddress;
|
||||
u64 AddWordInfoAddress;
|
||||
|
||||
u64 appAccessor;
|
||||
RefDataTableManager refDataTableManager;
|
||||
|
||||
void
|
||||
Init () {
|
||||
switch (gameVersion) {
|
||||
case GameVersion::JPN00: break;
|
||||
case GameVersion::JPN08: break;
|
||||
case GameVersion::JPN39: {
|
||||
GetWordInfoAddress = ASLR (0x1400AA640);
|
||||
AddWordInfoAddress = ASLR (0x1400AAA20);
|
||||
} break;
|
||||
case GameVersion::CHN00: break;
|
||||
}
|
||||
}
|
||||
void
|
||||
SetupAccessor (u64 appAccessor, RefDataTableManager refDataTableManager) {
|
||||
patches::Wordlist::refDataTableManager = refDataTableManager;
|
||||
patches::Wordlist::appAccessor = appAccessor;
|
||||
}
|
||||
WordInfo *
|
||||
GetWordInfo (std::string &key) {
|
||||
WordInfo *wordInfo = (WordInfo *)malloc (sizeof(WordInfo));
|
||||
wordInfo->key = "";
|
||||
wordInfo->text = "";
|
||||
wordInfo->fontType = 0;
|
||||
if (refDataTableManager != nullptr && appAccessor != 0) {
|
||||
u64 dataTableManager = refDataTableManager (appAccessor);
|
||||
if (dataTableManager) {
|
||||
u64 wordInfoAccessor = *(u64*)(dataTableManager + 32);
|
||||
if (wordInfoAccessor) {
|
||||
((char (__fastcall *)(u64, std::string *, WordInfo *))(GetWordInfoAddress))(wordInfoAccessor, &key, wordInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return wordInfo;
|
||||
}
|
||||
void
|
||||
SetWordInfo (WordInfo *wordInfo) {
|
||||
if (wordInfo != nullptr && refDataTableManager != nullptr && appAccessor != 0) {
|
||||
u64 dataTableManager = refDataTableManager (appAccessor);
|
||||
if (dataTableManager) {
|
||||
u64 wordInfoAccessor = *(u64*)(dataTableManager + 32);
|
||||
if (wordInfoAccessor) {
|
||||
((u64 (__fastcall *)(u64, WordInfo *))(AddWordInfoAddress))(wordInfoAccessor, wordInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -13,6 +13,7 @@ extern bool globalKeyboardInput;
|
||||
extern bool autoIme;
|
||||
extern HKL currentLayout;
|
||||
extern bool emulateUsio;
|
||||
extern bool globalKeyboard;
|
||||
|
||||
bool wndForeground = false;
|
||||
bool usingKeyboard = false;
|
||||
@@ -126,7 +127,7 @@ HHOOK mouseHook;
|
||||
LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
||||
if (nCode == HC_ACTION) {
|
||||
switch (wParam) {
|
||||
case WM_KEYDOWN: if (wndForeground) {
|
||||
case WM_KEYDOWN: if (globalKeyboard || wndForeground) {
|
||||
auto* pKeyboard = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
DWORD keyCode = pKeyboard->vkCode;
|
||||
if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] = std::min (keyboardCount[keyCode] + 1, maxCount);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
#include "poll.h"
|
||||
|
||||
struct KeyCodePair {
|
||||
|
||||
Reference in New Issue
Block a user