Files
esuo1198_TaikoArcadeLoader/src/patches/scanner.cpp
T

508 lines
23 KiB
C++

#include "constants.h"
#include "helpers.h"
#include "patches.h"
#include <ReadBarcode.h>
#include <chrono>
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <vector>
#include <queue>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_WINDOWS_UTF8
#include "stb_image.h"
extern GameVersion gameVersion;
extern std::vector<HMODULE> plugins;
extern bool acceptInvalidCards;
extern bool emulateCardReader;
extern bool emulateQr;
extern char accessCode1[21];
extern char accessCode2[21];
extern char chipId1[33];
extern char chipId2[33];
namespace patches::Scanner {
namespace Card {
State state = State::Disable;
i32 *attachData;
u64 touchData;
CallbackAttach callbackAttach;
CallbackTouch callbackTouch;
std::string accessCodeTemplate = "00000000000000000000";
std::string chipIdTemplate = "00000000000000000000000000000000";
u8 cardData[168] = {
0x01, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x2E, 0x58, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x5C, 0x97, 0x44, 0xF0, 0x88, 0x04, 0x00, 0x43, 0x26, 0x2C, 0x33, 0x00, 0x04,
0x06, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x43, 0x36,
0x00, 0x00, 0xFA, 0xE9, 0x69, 0x00, 0xF6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
namespace Internal {
enum CardErrorCode { ReadError = -201, NotSupport = -400 };
void
InsertCard (uint8_t cardData[168], bool internalInvoke) {
if (callbackTouch) {
state = internalInvoke ? State::Disable : State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
if (!internalInvoke) {
LogMessage (LogLevel::DEBUG, "[Card] Call CallbackTouch!");
for (int i = 0; i < 8; i++) {
std::ostringstream cardDataOut;
cardDataOut << std::hex << std::uppercase;
for (int j = 0; j < 21; j++) {
cardDataOut << std::setw (2) << std::setfill ('0') << (int)cardData[i * 21 + j] << " ";
}
LogMessage (LogLevel::DEBUG, cardDataOut.str ());
}
}
callbackTouch (0, 0, cardData, touchData);
}
}
void
InsertError (CardErrorCode errorCode) {
if (callbackTouch) {
state = State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
callbackTouch (0, errorCode, cardData, touchData);
}
}
void
AgentCallbackTouch (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) {
if (callbackTouch) {
state = State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
callbackTouch (a1, a2, a3, a4);
}
}
void
AgentCallbackTouchOfficial (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) {
if (callbackTouch) {
state = State::CopyWait;
patches::Plugins::UpdateStatus (1, false);
LogMessage (LogLevel::DEBUG, "Official CallbackTouch a1={} a2={}", a1, a2);
if (acceptInvalidCards && !a3[0]) {
char AccessId[21] = "00000000000000000001";
uint8_t UID[8] = {a3[12], a3[14], a3[15], a3[16], 0x90, 0x00, 0x00, 0x00};
uint64_t ReversedAccessID;
for (int i = 0; i < 8; i++)
ReversedAccessID = (ReversedAccessID << 8) | UID[i];
sprintf(AccessId, "%020llu", ReversedAccessID);
std::string accessCode = std::string (AccessId), chipId = "";
if (chipId.length () == 0) chipId = accessCode;
if (chipId.length () < 32) chipId = accessCodeTemplate.substr (0, 32 - chipId.length ()) + chipId;
for (size_t i = 0; i < 32; i++) *(cardData + 0x2C + i) = i < chipId.length() ? chipId[i] : 0;
for (size_t i = 0; i < 20; i++) *(cardData + 0x50 + i) = i < accessCode.length() ? accessCode[i] : 0;
callbackTouch (0, 0, cardData, a4);
} else callbackTouch (a1, a2, a3, a4);
}
}
bool
Commit0 (std::string accessCode, std::string chipId, bool internalInvoke) {
if (chipId.length () == 0) chipId = accessCode;
if (chipId.length () < 32) chipId = accessCodeTemplate.substr (0, 32 - chipId.length ()) + chipId;
for (size_t i = 0; i < 32; i++) *(cardData + 0x2C + i) = i < chipId.length() ? chipId[i] : 0;
for (size_t i = 0; i < 20; i++) *(cardData + 0x50 + i) = i < accessCode.length() ? accessCode[i] : 0;
if (!internalInvoke) LogMessage (LogLevel::INFO, "[Card] Insert Card accessCode: \"{}\" chipId: \"{}\"", accessCode, chipId);
patches::Scanner::Card::Internal::InsertCard (cardData, internalInvoke);
return true;
}
}
FAST_HOOK (u64, bngrw_Init, PROC_ADDRESS ("bngrw.dll", "BngRwInit")) { return 0; }
FAST_HOOK (void, bngrw_Fin, PROC_ADDRESS ("bngrw.dll", "BngRwFin")) { return; }
FAST_HOOK (u64, bngrw_IsCmdExec, PROC_ADDRESS ("bngrw.dll", "BngRwIsCmdExec")) { return 0xFFFFFFFF; }
FAST_HOOK (i32, bngrw_ReqSendUrl, PROC_ADDRESS ("bngrw.dll", "BngRwReqSendUrlTo")) { return 1; }
FAST_HOOK (u64, bngrw_ReqLed, PROC_ADDRESS ("bngrw.dll", "BngRwReqLed")) { return 1; }
FAST_HOOK (u64, bngrw_ReqBeep, PROC_ADDRESS ("bngrw.dll", "BngRwReqBeep")) { return 1; }
FAST_HOOK (u64, bngrw_ReqAction, PROC_ADDRESS ("bngrw.dll", "BngRwReqAction")) { return 1; }
FAST_HOOK (u64, bngrw_ReqSetLedPower, PROC_ADDRESS ("bngrw.dll", "BngRwReqSetLedPower")) { return 0; }
FAST_HOOK (u64, bngrw_GetRetryCount, PROC_ADDRESS ("bngrw.dll", "BngRwGetTotalRetryCount")) { return 0; }
FAST_HOOK (u64, bngrw_GetFwVersion, PROC_ADDRESS ("bngrw.dll", "BngRwGetFwVersion")) { return 0; }
FAST_HOOK (u64, bngrw_ReqFwVersionUp, PROC_ADDRESS ("bngrw.dll", "BngRwReqFwVersionUp")) { return 1; }
FAST_HOOK (u64, bngrw_ReqFwCleanup, PROC_ADDRESS ("bngrw.dll", "BngRwReqFwCleanup")) { return 1; }
FAST_HOOK (u64, bngrw_ReadMifare, PROC_ADDRESS ("bngrw.dll", "BngRwExReadMifareAllBlock")) { return 0xFFFFFF9C; }
FAST_HOOK (u64, bngrw_GetStationID, PROC_ADDRESS ("bngrw.dll", "BngRwGetStationID")) { return 0; }
FAST_HOOK (i32, bngrw_ReqSendMail, PROC_ADDRESS ("bngrw.dll", "BngRwReqSendMailTo")) { return 1; }
FAST_HOOK (i32, bngrw_ReqLatchID, PROC_ADDRESS ("bngrw.dll", "BngRwReqLatchID")) { return 1; }
FAST_HOOK (u64, bngrw_ReqAiccAuth, PROC_ADDRESS ("bngrw.dll", "BngRwReqAiccAuth")) { return 1; }
FAST_HOOK (u64, bngrw_DevReset, PROC_ADDRESS ("bngrw.dll", "BngRwDevReset")) { return 1; } // Invoke when enter testmode
FAST_HOOK (i32, bngrw_ReqCancel, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel")) {
if (state != State::Disable) {
state = State::Disable;
patches::Scanner::Card::Internal::Commit0 (accessCodeTemplate, chipIdTemplate, true);
}
return 1;
}
FAST_HOOK (u64, bngrw_Attach, PROC_ADDRESS ("bngrw.dll", "BngRwAttach"), i32 a1, char *a2, i32 a3, i32 a4, CallbackAttach callback, i32 *a6) {
callbackAttach = callback;
attachData = a6;
return 1;
}
FAST_HOOK (u64, bngrw_ReqWaitTouch, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) {
state = State::Ready;
patches::Plugins::UpdateStatus (1, true);
patches::Plugins::WaitTouch (Internal::AgentCallbackTouch, a5);
callbackTouch = callback;
touchData = a5;
return 1;
}
HOOK (i64, bngrw_ReqCancelOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel"), u32 a1) {
if (state != State::Disable) {
state = State::Disable;
patches::Plugins::UpdateStatus (1, false);
}
return originalbngrw_ReqCancelOfficial (a1);
}
HOOK (u64, bngrw_ReqWaitTouchOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) {
state = State::Ready;
patches::Plugins::UpdateStatus (1, true);
callbackTouch = callback;
touchData = a5;
return originalbngrw_ReqWaitTouchOfficial (a1, a2, a3, Internal::AgentCallbackTouchOfficial, a5);
}
bool
Commit(std::string accessCode, std::string chipId) {
if (!emulateCardReader) {
LogMessage (LogLevel::DEBUG, "[Card] Not emulate CardReader!");
return false;
}
if (state != State::Ready) {
LogMessage (LogLevel::DEBUG, "[Card] Not Waiting for Touch, please wait!");
return false;
}
if (accessCode.length() == 0 || accessCode.length() > 20) {
LogMessage (LogLevel::ERROR, "[Card] Not an effective accessCode: \"{}\"", accessCode);
patches::Scanner::Card::Internal::InsertError (Internal::CardErrorCode::NotSupport);
return false;
}
if (chipId.length() > 32) {
LogMessage (LogLevel::ERROR, "[Card] Not an effective chipId: \"{}\"", chipId);
patches::Scanner::Card::Internal::InsertError (Internal::CardErrorCode::NotSupport);
return false;
}
return patches::Scanner::Card::Internal::Commit0 (accessCode, chipId, false);
}
void
Update() {
if (callbackAttach) callbackAttach (0, 0, attachData);
}
void
Init() {
LogMessage (LogLevel::INFO, "Init Card patches");
if (!emulateCardReader) {
LogMessage (LogLevel::WARN, "[Card] Card reader emulation disabled!");
INSTALL_HOOK (bngrw_ReqCancelOfficial);
INSTALL_HOOK (bngrw_ReqWaitTouchOfficial);
// patches::Plugins::InitCardReader (patches::Scanner::Card::Commit);
return;
}
INSTALL_FAST_HOOK (bngrw_Init)
INSTALL_FAST_HOOK (bngrw_Fin);
INSTALL_FAST_HOOK (bngrw_IsCmdExec);
INSTALL_FAST_HOOK (bngrw_ReqCancel);
INSTALL_FAST_HOOK (bngrw_ReqWaitTouch);
INSTALL_FAST_HOOK (bngrw_ReqSendUrl);
INSTALL_FAST_HOOK (bngrw_ReqLed);
INSTALL_FAST_HOOK (bngrw_ReqBeep);
INSTALL_FAST_HOOK (bngrw_ReqAction);
INSTALL_FAST_HOOK (bngrw_ReqSetLedPower);
INSTALL_FAST_HOOK (bngrw_GetRetryCount);
INSTALL_FAST_HOOK (bngrw_GetFwVersion);
INSTALL_FAST_HOOK (bngrw_ReqFwVersionUp);
INSTALL_FAST_HOOK (bngrw_ReqFwCleanup);
INSTALL_FAST_HOOK (bngrw_ReadMifare);
INSTALL_FAST_HOOK (bngrw_GetStationID);
INSTALL_FAST_HOOK (bngrw_ReqSendMail);
INSTALL_FAST_HOOK (bngrw_ReqLatchID);
INSTALL_FAST_HOOK (bngrw_ReqAiccAuth);
INSTALL_FAST_HOOK (bngrw_Attach);
INSTALL_FAST_HOOK (bngrw_DevReset);
patches::Plugins::InitCardReader (patches::Scanner::Card::Commit);
}
}
namespace Qr {
std::queue<std::vector<uint8_t> *> scanQueue;
State state = State::Disable;
long long lastScan;
FAST_HOOK_DYNAMIC (char, QrInit, i64) { return 1; }
FAST_HOOK_DYNAMIC (char, QrClose, i64) { return 1; }
FAST_HOOK_DYNAMIC (char, QrRead, i64 a1) {
*(DWORD *)(a1 + 40) = 1;
*(DWORD *)(a1 + 16) = 1;
*(BYTE *)(a1 + 112) = 0;
return 1;
}
FAST_HOOK_DYNAMIC (i64, CallQrUnknown, i64) { return 1; }
FAST_HOOK_DYNAMIC (bool, Send1, i64 a1) {
*(BYTE *)(a1 + 88) = 1;
*(i64 *)(a1 + 32) = *(i64 *)(a1 + 24);
*(WORD *)(a1 + 89) = 0;
return true;
}
FAST_HOOK_DYNAMIC (bool, Send2, i64 a1) {
*(WORD *)(a1 + 88) = 0;
*(BYTE *)(a1 + 90) = 0;
return true;
}
FAST_HOOK_DYNAMIC (bool, Send3, i64, char) { return true; }
FAST_HOOK_DYNAMIC (bool, Send4, i64, const void *, i64) { return true; }
FAST_HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) {
patches::Plugins::UsingQr ();
lastScan = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ();
if (state == State::CopyWait && scanQueue.size () > 0) {
std::vector<uint8_t> *data = scanQueue.front ();
if ((int)data->size () > length) {
LogMessage (LogLevel::ERROR, "[QR] Not an effective code, length: {} require: {}", data->size (), length);
}
std::stringstream hexStream;
hexStream << std::hex << std::uppercase << std::setfill ('0') << std::setw (2);
for (size_t i = 0; i < data->size (); i++) hexStream << static_cast<int> ((*data)[i]) << " ";
LogMessage (LogLevel::INFO, "[QR] Read QRData size: {} data: {}\n", data->size (), hexStream.str ());
size_t finalCopySize = std::min (data->size () + 1, (size_t)length);
memcpy (dest, data->data (), finalCopySize);
scanQueue.pop ();
delete data;
if (scanQueue.size () == 0) state = State::Ready;
return finalCopySize;
} else if (state == State::Disable) {
while (!scanQueue.empty ()) {
std::vector<uint8_t> *data = scanQueue.front ();
delete data;
scanQueue.pop ();
}
state = State::Ready;
patches::Plugins::UpdateStatus (2, true);
}
return 0;
}
bool
Commit (std::vector<uint8_t> &buffer) {
if (!emulateQr) {
LogMessage (LogLevel::DEBUG, "[QR] Not emulate QR Scanner!");
return false;
}
if (state == State::Disable) {
LogMessage (LogLevel::DEBUG, "[QR] Not Ready to accept QRData!");
return false;
}
if (buffer.size () == 0) {
LogMessage (LogLevel::ERROR, "[QR] Not an effective code, length: 0");
return false;
}
if (scanQueue.empty() || *scanQueue.back() != buffer) {
std::vector<uint8_t> *scanData = new std::vector<uint8_t> ();
for (uint8_t byte_data : buffer)
scanData->push_back (byte_data);
scanQueue.push (scanData);
}
if (state == State::Ready) state = State::CopyWait;
return true;
}
bool
CommitLogin (std::string accessCode) {
if (!emulateQr) {
LogMessage (LogLevel::DEBUG, "[QR] Not emulate QR Scanner!");
return false;
}
std::vector<uint8_t> buffer = {};
std::string accessQRDataBase = "BNTTCNID";
if (!accessCode.starts_with (accessQRDataBase))
for (char word : accessQRDataBase) buffer.push_back (word);
for (char word : accessCode) buffer.push_back (word);
return patches::Scanner::Qr::Commit (buffer);
}
void
Update () {
if (state != State::Disable) {
if ((lastScan + 200) < std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now ().time_since_epoch ()).count ()) {
state = State::Disable;
patches::Plugins::UpdateStatus (2, false);
} else {
void *plugin = patches::Plugins::CheckQr ();
if (plugin) {
uint8_t *space = (uint8_t *)calloc (600, sizeof (uint8_t));
size_t size = patches::Plugins::GetQr (plugin, 600, space);
if (size > 0) {
std::vector<uint8_t> data = {};
for (size_t i = 0; i < size; i ++) data.push_back (space[i]);
patches::Scanner::Qr::Commit (data);
}
}
}
}
}
std::vector<uint8_t> &
ReadQRData (std::vector<uint8_t> &buffer) {
std::string serial = "";
u16 type = 0;
std::vector<i64> songNoes;
buffer.clear ();
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) {
auto qr = openConfigSection (config_ptr.get (), "qr");
if (qr) {
auto data = openConfigSection (qr, "data");
if (data) {
serial = readConfigString (data, "serial", "");
type = (u16) readConfigInt (data, "type", 0);
songNoes = readConfigIntArray (data, "song_no", songNoes);
}
}
}
std::vector<uint8_t> header = { 0x53, 0x31, 0x32, 0x00, 0x00, 0xFF, 0xFF, (uint8_t)serial.size (), 0x01, 0x00 };
for (uint8_t byte_data : header) buffer.push_back (byte_data);
for (char word : serial) buffer.push_back ((uint8_t)word);
if (type == 5) {
std::vector<uint8_t> folder = { 0xFF, 0xFF, (uint8_t)(songNoes.size () * 2), (uint8_t)(type & 0xFF), (uint8_t)((type >> 8) & 0xFF) };
for (uint8_t byte_data : folder) buffer.push_back (byte_data);
for (i64 songNo : songNoes) {
buffer.push_back ((uint8_t)(songNo & 0xFF));
buffer.push_back ((uint8_t)((songNo >> 8) & 0xFF));
}
}
buffer.push_back (0xEE);
buffer.push_back (0xFF);
return buffer;
}
std::vector<uint8_t> &
ReadQRImage (std::vector<uint8_t> &buffer) {
std::string imagePath = "";
buffer.clear ();
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) {
auto qr = openConfigSection (config_ptr.get (), "qr");
if (qr) imagePath = readConfigString (qr, "image_path", "");
}
std::u8string u8PathStr (imagePath.begin (), imagePath.end ());
std::filesystem::path u8Path (u8PathStr);
if (!std::filesystem::is_regular_file (u8Path)) {
LogMessage (LogLevel::ERROR, "Failed to open image: {} (file not found)", u8Path.string());
return buffer;
}
int width, height, channels;
std::unique_ptr<stbi_uc, void (*) (void *)> img_buffer (stbi_load (u8Path.string ().c_str (), &width, &height, &channels, 3), stbi_image_free);
if (!img_buffer) {
LogMessage (LogLevel::ERROR, "Failed to read image: {} ({})\n", u8Path.string(), stbi_failure_reason ());
return buffer;
}
ZXing::ImageView image{img_buffer.get (), width, height, ZXing::ImageFormat::RGB};
auto result = ReadBarcode (image);
if (!result.isValid ()) {
LogMessage (LogLevel::ERROR, "Failed to read QR: {} ({})\n", u8Path.string(), ToString (result.error ()));
return buffer;
}
for (uint8_t byte_data : result.bytes()) buffer.push_back (byte_data);
return buffer;
}
void
Init () {
LogMessage (LogLevel::INFO, "Init Qr patches");
if (!emulateQr) {
LogMessage (LogLevel::WARN, "[QR] QR emulation disabled!");
return;
}
patches::Plugins::InitQr (gameVersion);
SetConsoleOutputCP (CP_UTF8);
auto amHandle = reinterpret_cast<u64> (GetModuleHandle ("AMFrameWork.dll"));
switch (gameVersion) {
case GameVersion::JPN00: {
INSTALL_FAST_HOOK_DYNAMIC (QrInit, (LPVOID)(amHandle + 0x1B3E0));
INSTALL_FAST_HOOK_DYNAMIC (QrClose, (LPVOID)(amHandle + 0x1B5B0));
INSTALL_FAST_HOOK_DYNAMIC (QrRead, (LPVOID)(amHandle + 0x1B600));
INSTALL_FAST_HOOK_DYNAMIC (CallQrUnknown, (LPVOID)(amHandle + 0xFD40));
INSTALL_FAST_HOOK_DYNAMIC (Send1, (LPVOID)(amHandle + 0x1BBB0));
INSTALL_FAST_HOOK_DYNAMIC (Send2, (LPVOID)(amHandle + 0x1BBF0));
INSTALL_FAST_HOOK_DYNAMIC (Send3, (LPVOID)(amHandle + 0x1BC60));
// JPN00 has no Send4
INSTALL_FAST_HOOK_DYNAMIC (CopyData, (LPVOID)(amHandle + 0x1BC30));
break;
}
case GameVersion::JPN08: {
INSTALL_FAST_HOOK_DYNAMIC (QrInit, (LPVOID)(amHandle + 0x1BA00));
INSTALL_FAST_HOOK_DYNAMIC (QrClose, (LPVOID)(amHandle + 0x1BBD0));
INSTALL_FAST_HOOK_DYNAMIC (QrRead, (LPVOID)(amHandle + 0x1BC20));
INSTALL_FAST_HOOK_DYNAMIC (CallQrUnknown, (LPVOID)(amHandle + 0xFD40));
INSTALL_FAST_HOOK_DYNAMIC (Send1, (LPVOID)(amHandle + 0x1C220));
INSTALL_FAST_HOOK_DYNAMIC (Send2, (LPVOID)(amHandle + 0x1C260));
INSTALL_FAST_HOOK_DYNAMIC (Send3, (LPVOID)(amHandle + 0x1C2D0));
// JPN08 has no Send4
INSTALL_FAST_HOOK_DYNAMIC (CopyData, (LPVOID)(amHandle + 0x1C2A0));
break;
}
case GameVersion::JPN39: {
INSTALL_FAST_HOOK_DYNAMIC (QrInit, (LPVOID)(amHandle + 0x1EDC0));
INSTALL_FAST_HOOK_DYNAMIC (QrClose, (LPVOID)(amHandle + 0x1EF60));
INSTALL_FAST_HOOK_DYNAMIC (QrRead, (LPVOID)(amHandle + 0x1EFB0));
INSTALL_FAST_HOOK_DYNAMIC (CallQrUnknown, (LPVOID)(amHandle + 0x11A70));
INSTALL_FAST_HOOK_DYNAMIC (Send1, (LPVOID)(amHandle + 0x1F5B0));
INSTALL_FAST_HOOK_DYNAMIC (Send2, (LPVOID)(amHandle + 0x1F5F0));
INSTALL_FAST_HOOK_DYNAMIC (Send3, (LPVOID)(amHandle + 0x1F660));
INSTALL_FAST_HOOK_DYNAMIC (Send4, (LPVOID)(amHandle + 0x1F690));
INSTALL_FAST_HOOK_DYNAMIC (CopyData, (LPVOID)(amHandle + 0x1F630));
break;
}
case GameVersion::CHN00: {
INSTALL_FAST_HOOK_DYNAMIC (QrInit, (LPVOID)(amHandle + 0x161B0));
INSTALL_FAST_HOOK_DYNAMIC (QrClose, (LPVOID)(amHandle + 0x16350));
INSTALL_FAST_HOOK_DYNAMIC (QrRead, (LPVOID)(amHandle + 0x163A0));
INSTALL_FAST_HOOK_DYNAMIC (CallQrUnknown, (LPVOID)(amHandle + 0x8F60));
INSTALL_FAST_HOOK_DYNAMIC (Send1, (LPVOID)(amHandle + 0x16940));
INSTALL_FAST_HOOK_DYNAMIC (Send2, (LPVOID)(amHandle + 0x16990));
INSTALL_FAST_HOOK_DYNAMIC (Send3, (LPVOID)(amHandle + 0x16A00));
INSTALL_FAST_HOOK_DYNAMIC (Send4, (LPVOID)(amHandle + 0x16A30));
INSTALL_FAST_HOOK_DYNAMIC (CopyData, (LPVOID)(amHandle + 0x169D0));
break;
}
default: {
break;
}
}
patches::Plugins::InitQRScanner (patches::Scanner::Qr::Commit);
patches::Plugins::InitQRLogin (patches::Scanner::Qr::CommitLogin);
}
}
void
Update() {
patches::Scanner::Card::Update ();
patches::Scanner::Qr::Update ();
}
void
Init() {
LogMessage (LogLevel::INFO, "Init Scanner patches");
patches::Scanner::Card::Init ();
patches::Scanner::Qr::Init ();
}
}