From 1b7ebd6fc2378529d8902af1a79629ea0e0488bc Mon Sep 17 00:00:00 2001 From: oleg238948234 <155594697+oleg238948234@users.noreply.github.com> Date: Tue, 25 Mar 2025 04:06:55 +0500 Subject: [PATCH] Add Mahjong Fight Girl Support (#275) ## Link to GitHub Issue, if one exists n/a ## Description of change Adds Mahjong Fight Girl Support ## Compiling + ## Testing Tested with VFG:J:E:A:2024100800 in HG mode with VFG IO. No modifications made to data, other than avs-config.xml and ea3-config.xml. B and C modes don't work because of serial touchscreen. UKS mode doesn't work because of IO. --- src/spice2x/CMakeLists.txt | 4 + src/spice2x/acioemu/handle.cpp | 5 +- src/spice2x/acioemu/handle.h | 4 +- src/spice2x/acioemu/icca.cpp | 3 + src/spice2x/games/io.cpp | 8 + src/spice2x/games/mfg/bi2a_hook.cpp | 385 ++++++++++++++++++++++++++++ src/spice2x/games/mfg/bi2a_hook.h | 5 + src/spice2x/games/mfg/io.cpp | 23 ++ src/spice2x/games/mfg/io.h | 19 ++ src/spice2x/games/mfg/mfg.cpp | 74 ++++++ src/spice2x/games/mfg/mfg.h | 18 ++ src/spice2x/launcher/launcher.cpp | 31 +++ src/spice2x/launcher/options.cpp | 42 +++ src/spice2x/launcher/options.h | 4 + src/spice2x/launcher/signal.cpp | 3 +- src/spice2x/launcher/signal.h | 1 + src/spice2x/misc/eamuse.cpp | 2 + src/spice2x/util/execexe.cpp | 180 +++++++++++++ src/spice2x/util/execexe.h | 38 +++ src/spice2x/util/unity_player.cpp | 97 ++++--- src/spice2x/util/unity_player.h | 2 + 21 files changed, 915 insertions(+), 33 deletions(-) create mode 100644 src/spice2x/games/mfg/bi2a_hook.cpp create mode 100644 src/spice2x/games/mfg/bi2a_hook.h create mode 100644 src/spice2x/games/mfg/io.cpp create mode 100644 src/spice2x/games/mfg/io.h create mode 100644 src/spice2x/games/mfg/mfg.cpp create mode 100644 src/spice2x/games/mfg/mfg.h create mode 100644 src/spice2x/util/execexe.cpp create mode 100644 src/spice2x/util/execexe.h diff --git a/src/spice2x/CMakeLists.txt b/src/spice2x/CMakeLists.txt index 859eac8..9b395c5 100644 --- a/src/spice2x/CMakeLists.txt +++ b/src/spice2x/CMakeLists.txt @@ -442,6 +442,9 @@ set(SOURCE_FILES ${SOURCE_FILES} games/qks/qks.cpp games/qks/io.cpp games/qks/bi2x_hook.cpp + games/mfg/mfg.cpp + games/mfg/io.cpp + games/mfg/bi2a_hook.cpp # hooks hooks/audio/audio.cpp @@ -587,6 +590,7 @@ set(SOURCE_FILES ${SOURCE_FILES} util/sysutils.cpp util/lz77.cpp util/tapeled.cpp + util/execexe.cpp ) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES}) diff --git a/src/spice2x/acioemu/handle.cpp b/src/spice2x/acioemu/handle.cpp index 7ed2e8c..4ebe3ea 100644 --- a/src/spice2x/acioemu/handle.cpp +++ b/src/spice2x/acioemu/handle.cpp @@ -4,8 +4,9 @@ #include "rawinput/rawinput.h" #include "util/utils.h" -acioemu::ACIOHandle::ACIOHandle(LPCWSTR lpCOMPort) { +acioemu::ACIOHandle::ACIOHandle(LPCWSTR lpCOMPort, uint8_t iccaNodeCount) { this->com_port = lpCOMPort; + this->icca_node_count = iccaNodeCount; } bool acioemu::ACIOHandle::open(LPCWSTR lpFileName) { @@ -16,7 +17,7 @@ bool acioemu::ACIOHandle::open(LPCWSTR lpFileName) { log_info("acioemu", "Opened {} (ACIO)", ws2s(com_port)); // ACIO device - acio_emu.add_device(new acioemu::ICCADevice(false, true, 2)); + acio_emu.add_device(new acioemu::ICCADevice(false, true, icca_node_count)); return true; } diff --git a/src/spice2x/acioemu/handle.h b/src/spice2x/acioemu/handle.h index acff798..5caa3d7 100644 --- a/src/spice2x/acioemu/handle.h +++ b/src/spice2x/acioemu/handle.h @@ -9,10 +9,12 @@ namespace acioemu { private: LPCWSTR com_port; + uint8_t icca_node_count; + acioemu::ACIOEmu acio_emu; public: - ACIOHandle(LPCWSTR lpCOMPort); + ACIOHandle(LPCWSTR lpCOMPort, uint8_t iccaNodeCount = 2); bool open(LPCWSTR lpFileName) override; diff --git a/src/spice2x/acioemu/icca.cpp b/src/spice2x/acioemu/icca.cpp index 1f75a10..2733aa7 100644 --- a/src/spice2x/acioemu/icca.cpp +++ b/src/spice2x/acioemu/icca.cpp @@ -107,6 +107,8 @@ bool ICCADevice::parse_msg(MessageData *msg_in, (avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H')) ) { this->set_version(msg, 0x3, 0, 1, 7, 0, "ICCA"); + } else if (avs::game::is_model({"VFG"})) { + this->set_version(msg, 0x3, 0, 1, 7, 0, "ICCB"); } else { this->set_version(msg, 0x3, 0, 1, 6, 0, "ICCA"); } @@ -333,6 +335,7 @@ bool ICCADevice::parse_msg(MessageData *msg_in, case ACIO_CMD_CLEAR: case 0x30: // GetBoardProductNumber case 0x31: // GetMicomInfo + case 0x3A: // ??? case 0x0116: // ??? case 0x0120: // ??? case 0xFF: // BROADCAST diff --git a/src/spice2x/games/io.cpp b/src/spice2x/games/io.cpp index ad91129..d74270a 100644 --- a/src/spice2x/games/io.cpp +++ b/src/spice2x/games/io.cpp @@ -35,6 +35,7 @@ #include "bc/io.h" #include "ccj/io.h" #include "qks/io.h" +#include "mfg/io.h" namespace games { @@ -305,6 +306,13 @@ namespace games { buttons.insert({ qks, qks::get_buttons() }); buttons_help.insert({ qks, qks::get_buttons_help() }); file_hints[qks].emplace_back("game/uks.exe"); + + // Mahjong Fight Girl + const std::string mfg("Mahjong Fight Girl"); + games.push_back(mfg); + buttons.insert({ mfg, mfg::get_buttons() }); + buttons_help.insert({ mfg, mfg::get_buttons_help() }); + file_hints[mfg].emplace_back("game/MFGClient_Data"); } const std::vector &get_games() { diff --git a/src/spice2x/games/mfg/bi2a_hook.cpp b/src/spice2x/games/mfg/bi2a_hook.cpp new file mode 100644 index 0000000..e36e2e9 --- /dev/null +++ b/src/spice2x/games/mfg/bi2a_hook.cpp @@ -0,0 +1,385 @@ +#include "bi2a_hook.h" + +#include "util/execexe.h" +#include "util/logging.h" +#include "rawinput/rawinput.h" +#include "misc/eamuse.h" +#include "games/io.h" +#include "io.h" +#include "util/tapeled.h" + +namespace games::mfg { + + /* + * class definitions + */ + + struct AIO_SCI_COMM { + }; + + struct AIO_NMGR_IOB { + }; + + struct AIO_IOB_BI2A_VFG { + }; + + struct AIO_IOB_BI2A_VFG__INPUTDATA { + uint8_t data[16]; + }; + + struct AIO_IOB_BI2A_VFG__OUTPUTDATA { + uint8_t data[40]; + }; + + struct AIO_IOB_BI2A_VFG__INPUT + { + uint8_t bPcPowerCheck; + uint8_t CoinCount; + uint8_t bTest; + uint8_t bService; + uint8_t bCoinSw; + uint8_t bCoinJam; + uint8_t bCabinet; + uint8_t bHPDetect; + uint8_t bRecDetect; + uint8_t bStart; + }; + + struct AIO_IOB_BI2A_VFG__DEVSTATUS + { + uint8_t MechType; + uint8_t bIsBi2a; + uint8_t IoCounter; + AIO_IOB_BI2A_VFG__INPUT Input; + AIO_IOB_BI2A_VFG__INPUTDATA InputData; + AIO_IOB_BI2A_VFG__OUTPUTDATA OutputData; + }; + + /* + * typedefs + */ + + // libaio-iob_video.dll + typedef AIO_SCI_COMM* (__fastcall *aioIobBi2a_OpenSciUsbCdc_t)(uint32_t i_SerialNumber); + typedef AIO_IOB_BI2A_VFG* (__fastcall *aioIobBi2aVFG_Create_t)(AIO_NMGR_IOB *i_pNodeMgr, uint32_t i_DevId); + typedef void (__fastcall *aioIobBi2aVFG_SetMechType_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl, uint32_t i_MechType); + typedef void (__fastcall *aioIobBi2aVFG_GetDeviceStatus_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, + AIO_IOB_BI2A_VFG__DEVSTATUS *o_pDevStatus, + uint32_t i_cbDevStatus); + typedef void (__fastcall *aioIobBi2aVFG_SetWatchDogTimer_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint16_t i_Count); + typedef void (__fastcall *aioIobBi2aVFG_ControlCoinBlocker_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Slot, + bool i_bOpen); + typedef void (__fastcall *aioIobBi2aVFG_AddCounter_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Counter, + uint32_t i_Count); + typedef void (__fastcall *aioIobBi2aVFG_SetAmpVolume_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Amp, + uint32_t i_Volume); + typedef void (__fastcall *aioIobBi2aVFG_EnableUsbCharger_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, bool i_bEnable); + typedef void (__fastcall *aioIobBi2aVFG_SetLamp_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Lamp, uint8_t i_Bright); + typedef void (__fastcall *aioIobBi2aVFG_SetIccrLed_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_RGB); + typedef void (__fastcall *aioIobBi2aVFG_SetLedData_t)(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint8_t *i_pData, + uint32_t i_cbData); + + // libaio-iob.dll + typedef AIO_NMGR_IOB* (__fastcall *aioNMgrIob_Create_t)(AIO_SCI_COMM* i_pSci, uint32_t i_bfMode); + + // libaio.dll + typedef void (__fastcall *aioNodeMgr_Destroy_t)(AIO_NMGR_IOB *i_pNodeMgr); + typedef int32_t (__fastcall *aioNodeMgr_GetState_t)(AIO_NMGR_IOB *i_pNodeMgr); + typedef bool (__fastcall *aioNodeMgr_IsReady_t)(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State); + typedef bool (__fastcall *aioNodeMgr_IsError_t)(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State); + typedef void (__fastcall *aioNodeCtl_Destroy_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl); + typedef int32_t (__fastcall *aioNodeCtl_GetState_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl); + typedef bool (__fastcall *aioNodeCtl_IsReady_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State); + typedef bool (__fastcall *aioNodeCtl_IsError_t)(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State); + + /* + * function pointers + */ + + // libaio-iob_video.dll + static aioIobBi2a_OpenSciUsbCdc_t aioIobBi2a_OpenSciUsbCdc_orig = nullptr; + static aioIobBi2aVFG_Create_t aioIobBi2aVFG_Create_orig = nullptr; + static aioIobBi2aVFG_SetMechType_t aioIobBi2aVFG_SetMechType_orig = nullptr; + static aioIobBi2aVFG_GetDeviceStatus_t aioIobBi2aVFG_GetDeviceStatus_orig = nullptr; + static aioIobBi2aVFG_SetWatchDogTimer_t aioIobBi2aVFG_SetWatchDogTimer_orig = nullptr; + static aioIobBi2aVFG_ControlCoinBlocker_t aioIobBi2aVFG_ControlCoinBlocker_orig = nullptr; + static aioIobBi2aVFG_AddCounter_t aioIobBi2aVFG_AddCounter_orig = nullptr; + static aioIobBi2aVFG_SetAmpVolume_t aioIobBi2aVFG_SetAmpVolume_orig = nullptr; + static aioIobBi2aVFG_EnableUsbCharger_t aioIobBi2aVFG_EnableUsbCharger_orig = nullptr; + static aioIobBi2aVFG_SetLamp_t aioIobBi2aVFG_SetLamp_orig = nullptr; + static aioIobBi2aVFG_SetIccrLed_t aioIobBi2aVFG_SetIccrLed_orig = nullptr; + static aioIobBi2aVFG_SetLedData_t aioIobBi2aVFG_SetLedData_orig = nullptr; + + // libaio-iob.dll + static aioNMgrIob_Create_t aioNMgrIob_Create_orig = nullptr; + + // libaio.dll + static aioNodeMgr_Destroy_t aioNodeMgr_Destroy_orig = nullptr; + static aioNodeMgr_GetState_t aioNodeMgr_GetState_orig = nullptr; + static aioNodeMgr_IsReady_t aioNodeMgr_IsReady_orig = nullptr; + static aioNodeMgr_IsError_t aioNodeMgr_IsError_orig = nullptr; + static aioNodeCtl_Destroy_t aioNodeCtl_Destroy_orig = nullptr; + static aioNodeCtl_GetState_t aioNodeCtl_GetState_orig = nullptr; + static aioNodeCtl_IsReady_t aioNodeCtl_IsReady_orig = nullptr; + static aioNodeCtl_IsError_t aioNodeCtl_IsError_orig = nullptr; + + /* + * variables + */ + + static AIO_SCI_COMM *aioSciComm; + static AIO_NMGR_IOB *aioNmgrIob; + static AIO_IOB_BI2A_VFG *aioIobBi2aVfg; + static uint8_t mechType = 0; + static uint8_t count = 0; + + /* + * implementations + */ + + static AIO_SCI_COMM* __fastcall aioIob2Bi2a_OpenSciUsbCdc(uint32_t i_SerialNumber) { + log_info("bi2a_hook", "aioIob2Bi2a_OpenSciUsbCdc hook hit"); + aioSciComm = new AIO_SCI_COMM; + return aioSciComm; + } + + static AIO_IOB_BI2A_VFG* __fastcall aioIobBi2aVFG_Create(AIO_NMGR_IOB *i_pNodeMgr, uint32_t i_DevId) { + if (i_pNodeMgr == aioNmgrIob) { + log_info("bi2a_hook", "node created"); + aioIobBi2aVfg = new AIO_IOB_BI2A_VFG; + return aioIobBi2aVfg; + } else { + return aioIobBi2aVFG_Create_orig(i_pNodeMgr, i_DevId); + } + } + + void __fastcall aioIobBi2aVFG_SetMechType(AIO_IOB_BI2A_VFG *i_pNodeCtl, uint32_t i_MechType) { + if (i_pNodeCtl == aioIobBi2aVfg) { + mechType = i_MechType; + } else { + return aioIobBi2aVFG_SetMechType_orig(i_pNodeCtl, i_MechType); + } + } + + void __fastcall aioIobBi2aVFG_GetDeviceStatus(AIO_IOB_BI2A_VFG* i_pNodeCtl, + AIO_IOB_BI2A_VFG__DEVSTATUS *o_pDevStatus, + uint32_t i_cbDevStatus) { + + RI_MGR->devices_flush_output(); + + if (i_pNodeCtl != aioIobBi2aVfg) { + return aioIobBi2aVFG_GetDeviceStatus_orig(i_pNodeCtl, o_pDevStatus, i_cbDevStatus); + } + + memset(o_pDevStatus, 0x00, sizeof(AIO_IOB_BI2A_VFG__DEVSTATUS)); + + o_pDevStatus->MechType = mechType; + o_pDevStatus->bIsBi2a = 1; + o_pDevStatus->IoCounter = count++; + + auto &buttons = get_buttons(); + if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test])) + o_pDevStatus->Input.bTest = 1; + if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service])) + o_pDevStatus->Input.bService = 1; + if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech])) + o_pDevStatus->Input.bCoinSw = 1; + + o_pDevStatus->Input.CoinCount = eamuse_coin_get_stock(); + } + + void __fastcall aioIobBi2aVFG_SetWatchDogTimer(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint16_t i_Count) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_SetWatchDogTimer_orig(i_pNodeCtl, i_Count); + } + } + + void __fastcall aioIobBi2aVFG_ControlCoinBlocker(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Slot, bool i_bOpen) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_ControlCoinBlocker_orig(i_pNodeCtl, i_Slot, i_bOpen); + } + } + + void __fastcall aioIobBi2aVFG_AddCounter(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Counter, uint32_t i_Count) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_AddCounter_orig(i_pNodeCtl, i_Counter, i_Count); + } + } + + void __fastcall aioIobBi2aVFG_SetAmpVolume(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Amp, uint32_t i_Volume) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_SetAmpVolume_orig(i_pNodeCtl, i_Amp, i_Volume); + } + } + + void __fastcall aioIobBi2aVFG_EnableUsbCharger(AIO_IOB_BI2A_VFG* i_pNodeCtl, bool i_bEnable) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_EnableUsbCharger_orig(i_pNodeCtl, i_bEnable); + } + } + + void __fastcall aioIobBi2aVFG_SetLamp(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_Lamp, uint8_t i_Bright) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_SetLamp_orig(i_pNodeCtl, i_Lamp, i_Bright); + } + } + + void __fastcall aioIobBi2aVFG_SetIccrLed(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint32_t i_RGB) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_SetIccrLed_orig(i_pNodeCtl, i_RGB); + } + } + + void __fastcall aioIobBi2aVFG_SetLedData(AIO_IOB_BI2A_VFG* i_pNodeCtl, uint8_t *i_pData, uint32_t i_cbData) { + if (i_pNodeCtl == aioIobBi2aVfg) { + } else { + return aioIobBi2aVFG_SetLedData_orig(i_pNodeCtl, i_pData, i_cbData); + } + } + + static AIO_NMGR_IOB* __fastcall aioNMgrIob_Create(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode) { + if (i_pSci == aioSciComm) { + aioNmgrIob = new AIO_NMGR_IOB; + return aioNmgrIob; + } else { + return aioNMgrIob_Create_orig(i_pSci, i_bfMode); + } + } + + static void __fastcall aioNodeMgr_Destroy(AIO_NMGR_IOB *i_pNodeMgr) { + if (i_pNodeMgr == aioNmgrIob) { + delete aioNmgrIob; + aioNmgrIob = nullptr; + } else { + return aioNodeMgr_Destroy_orig(i_pNodeMgr); + } + } + + static int32_t __fastcall aioNodeMgr_GetState(AIO_NMGR_IOB *i_pNodeMgr) { + if (i_pNodeMgr == aioNmgrIob) { + return 1; + } else { + return aioNodeMgr_GetState_orig(i_pNodeMgr); + } + } + + static bool __fastcall aioNodeMgr_IsReady(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State) { + if (i_pNodeMgr == aioNmgrIob) { + return true; + } else { + return aioNodeMgr_IsReady_orig(i_pNodeMgr, i_State); + } + } + + static bool __fastcall aioNodeMgr_IsError(AIO_NMGR_IOB *i_pNodeMgr, int32_t i_State) { + if (i_pNodeMgr == aioNmgrIob) { + return false; + } else { + return aioNodeMgr_IsError_orig(i_pNodeMgr, i_State); + } + } + + static void __fastcall aioNodeCtl_Destroy(AIO_IOB_BI2A_VFG *i_pNodeCtl) { + if (i_pNodeCtl == aioIobBi2aVfg) { + delete aioIobBi2aVfg; + aioIobBi2aVfg = nullptr; + } else { + return aioNodeCtl_Destroy_orig(i_pNodeCtl); + } + } + + static int32_t __fastcall aioNodeCtl_GetState(AIO_IOB_BI2A_VFG *i_pNodeCtl) { + if (i_pNodeCtl == aioIobBi2aVfg) { + return 1; + } else { + return aioNodeCtl_GetState_orig(i_pNodeCtl); + } + } + + static bool __fastcall aioNodeCtl_IsReady(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State) { + if (i_pNodeCtl == aioIobBi2aVfg) { + return true; + } else { + return aioNodeCtl_IsReady_orig(i_pNodeCtl, i_State); + } + } + + static bool __fastcall aioNodeCtl_IsError(AIO_IOB_BI2A_VFG *i_pNodeCtl, int32_t i_State) { + if (i_pNodeCtl == aioIobBi2aVfg) { + return false; + } else { + return aioNodeCtl_IsError_orig(i_pNodeCtl, i_State); + } + } + + void bi2a_hook_init() { + // avoid double init + static bool initialized = false; + if (initialized) { + return; + } else { + initialized = true; + } + + // announce + log_info("bi2a_hook", "init"); + + // libaio-iob_video.dll + const auto libaioIobVideoDll = "libaio-iob_video.dll"; + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2a_OpenSciUsbCdc", + aioIob2Bi2a_OpenSciUsbCdc, &aioIobBi2a_OpenSciUsbCdc_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_Create", + aioIobBi2aVFG_Create, &aioIobBi2aVFG_Create_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetMechType", + aioIobBi2aVFG_SetMechType, &aioIobBi2aVFG_SetMechType_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_GetDeviceStatus", + aioIobBi2aVFG_GetDeviceStatus, &aioIobBi2aVFG_GetDeviceStatus_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetWatchDogTimer", + aioIobBi2aVFG_SetWatchDogTimer, &aioIobBi2aVFG_SetWatchDogTimer_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_ControlCoinBlocker", + aioIobBi2aVFG_ControlCoinBlocker, &aioIobBi2aVFG_ControlCoinBlocker_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_AddCounter", + aioIobBi2aVFG_AddCounter, &aioIobBi2aVFG_AddCounter_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetAmpVolume", + aioIobBi2aVFG_SetAmpVolume, &aioIobBi2aVFG_SetAmpVolume_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_EnableUsbCharger", + aioIobBi2aVFG_EnableUsbCharger, &aioIobBi2aVFG_EnableUsbCharger_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetLamp", + aioIobBi2aVFG_SetLamp, &aioIobBi2aVFG_SetLamp_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetIccrLed", + aioIobBi2aVFG_SetIccrLed, &aioIobBi2aVFG_SetIccrLed_orig); + execexe::trampoline_try(libaioIobVideoDll, "aioIobBi2aVFG_SetLedData", + aioIobBi2aVFG_SetLedData, &aioIobBi2aVFG_SetLedData_orig); + + // libaio-iob.dll + const auto libaioIobDll = "libaio-iob.dll"; + execexe::trampoline_try(libaioIobDll, "aioNMgrIob_Create", + aioNMgrIob_Create, &aioNMgrIob_Create_orig); + + // libaio.dll + const auto libaioDll = "libaio.dll"; + execexe::trampoline_try(libaioDll, "aioNodeMgr_Destroy", + aioNodeMgr_Destroy, &aioNodeMgr_Destroy_orig); + execexe::trampoline_try(libaioDll, "aioNodeMgr_GetState", + aioNodeMgr_GetState, &aioNodeMgr_GetState_orig); + execexe::trampoline_try(libaioDll, "aioNodeMgr_IsReady", + aioNodeMgr_IsReady, &aioNodeMgr_IsReady_orig); + execexe::trampoline_try(libaioDll, "aioNodeMgr_IsError", + aioNodeMgr_IsError, &aioNodeMgr_IsError_orig); + execexe::trampoline_try(libaioDll, "aioNodeCtl_Destroy", + aioNodeCtl_Destroy, &aioNodeCtl_Destroy_orig); + execexe::trampoline_try(libaioDll, "aioNodeCtl_GetState", + aioNodeCtl_GetState, &aioNodeCtl_GetState_orig); + execexe::trampoline_try(libaioDll, "aioNodeCtl_IsReady", + aioNodeCtl_IsReady, &aioNodeCtl_IsReady_orig); + execexe::trampoline_try(libaioDll, "aioNodeCtl_IsError", + aioNodeCtl_IsError, &aioNodeCtl_IsError_orig); + } +} \ No newline at end of file diff --git a/src/spice2x/games/mfg/bi2a_hook.h b/src/spice2x/games/mfg/bi2a_hook.h new file mode 100644 index 0000000..cb083d2 --- /dev/null +++ b/src/spice2x/games/mfg/bi2a_hook.h @@ -0,0 +1,5 @@ +#pragma once + +namespace games::mfg { + void bi2a_hook_init(); +} \ No newline at end of file diff --git a/src/spice2x/games/mfg/io.cpp b/src/spice2x/games/mfg/io.cpp new file mode 100644 index 0000000..7569bb8 --- /dev/null +++ b/src/spice2x/games/mfg/io.cpp @@ -0,0 +1,23 @@ +#include "io.h" + +std::vector