diff --git a/src/spice2x/games/ccj/bi2x_hook.cpp b/src/spice2x/games/ccj/bi2x_hook.cpp index 03ec5a8..ddfb772 100644 --- a/src/spice2x/games/ccj/bi2x_hook.cpp +++ b/src/spice2x/games/ccj/bi2x_hook.cpp @@ -1,5 +1,7 @@ #include "bi2x_hook.h" +#if SPICE64 + #include #include "util/detour.h" #include "util/logging.h" @@ -16,15 +18,19 @@ namespace games::ccj { */ struct AIO_SCI_COMM { + uint8_t data[0xf8]; }; struct AIO_NMGR_IOB2 { + uint8_t data[0xe30]; }; struct AIO_IOB2_BI2X_TBS { + uint8_t data[0x4680]; }; struct AIO_IOB2_BI2X_WRFIRM { + uint8_t data[0x20f48]; }; struct AIO_NMGR_IOB__NODEINFO { @@ -72,6 +78,12 @@ namespace games::ccj { AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData; }; + // checked with UJK-001-2024060400 + static_assert(sizeof(AIO_SCI_COMM) == 0xf8); + static_assert(sizeof(AIO_NMGR_IOB2) == 0xe30); + static_assert(sizeof(AIO_IOB2_BI2X_TBS) == 0x4680); + static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48); + static void write_iccr_led(Lights::ccj_lights_t light, uint8_t value); /* @@ -621,4 +633,6 @@ namespace games::ccj { detour::trampoline_try(libaioDll, "aioNodeCtl_IsError", aioNodeCtl_IsError, &aioNodeCtl_IsError_orig); } -} \ No newline at end of file +} + +#endif diff --git a/src/spice2x/games/ccj/bi2x_hook.h b/src/spice2x/games/ccj/bi2x_hook.h index 4417688..35b5250 100644 --- a/src/spice2x/games/ccj/bi2x_hook.h +++ b/src/spice2x/games/ccj/bi2x_hook.h @@ -1,5 +1,9 @@ #pragma once +#if SPICE64 + namespace games::ccj { void bi2x_hook_init(); -} \ No newline at end of file +} + +#endif diff --git a/src/spice2x/games/ccj/ccj.cpp b/src/spice2x/games/ccj/ccj.cpp index fad70a8..5a825d3 100644 --- a/src/spice2x/games/ccj/ccj.cpp +++ b/src/spice2x/games/ccj/ccj.cpp @@ -68,9 +68,13 @@ namespace games::ccj { detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(11), (void*)execexe_CreateFileW_hook,(void**)&execexe_CreateFileW_orig); +#if SPICE64 + // insert BI2X hooks bi2x_hook_init(); +#endif + // insert trackball hooks trackball_hook_init(); diff --git a/src/spice2x/games/gitadora/bi2x_hook.cpp b/src/spice2x/games/gitadora/bi2x_hook.cpp index 4d6c9c7..9488156 100644 --- a/src/spice2x/games/gitadora/bi2x_hook.cpp +++ b/src/spice2x/games/gitadora/bi2x_hook.cpp @@ -1,5 +1,7 @@ #include "bi2x_hook.h" +#if SPICE64 + #include #include #include "util/detour.h" @@ -18,24 +20,29 @@ namespace games::gitadora { // */ struct AIO_NMGR_IOB2 { + uint8_t data[0xe18]; }; struct AIO_IOB2_BI2X_AC1__SETTING { }; struct AIO_NMGR_IOB5 { + uint8_t data[0xb10]; }; struct AIO_SCI_COMM { + uint8_t data[0x100]; }; struct AIO_IOB5_Y32D { + uint8_t data[0x2e8]; }; // struct AIO_IOB5_Y33I { // }; struct AIO_IOB2_BI2X_AC1 { + uint8_t data[0x4570]; }; struct AIO_NMGR_IOB__NODEINFO { @@ -43,6 +50,7 @@ namespace games::gitadora { }; struct AIO_IOB2_BI2X_WRFIRM { + uint8_t data[0x20f48]; }; struct AIO_SCI_COMM_T { @@ -159,6 +167,14 @@ namespace games::gitadora { uint8_t unk[0xB1]; }; + // verified with M32-007-2025092400 + static_assert(sizeof(AIO_NMGR_IOB2) == 0xe18); + static_assert(sizeof(AIO_NMGR_IOB5) == 0xb10); + static_assert(sizeof(AIO_SCI_COMM) == 0x100); + static_assert(sizeof(AIO_IOB5_Y32D) == 0x2e8); + static_assert(sizeof(AIO_IOB2_BI2X_AC1) == 0x4570); + static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48); + /* * typedefs */ @@ -701,4 +717,6 @@ namespace games::gitadora { detour::trampoline_try(libaioDll, "aioNodeCtl_UpdateDevicesStatus", aioNodeCtl_UpdateDevicesStatus, &aioNodeCtl_UpdateDevicesStatus_orig); } -} \ No newline at end of file +} + +#endif diff --git a/src/spice2x/games/gitadora/bi2x_hook.h b/src/spice2x/games/gitadora/bi2x_hook.h index 8572bd9..6114208 100644 --- a/src/spice2x/games/gitadora/bi2x_hook.h +++ b/src/spice2x/games/gitadora/bi2x_hook.h @@ -1,5 +1,9 @@ #pragma once +#if SPICE64 + namespace games::gitadora { void bi2x_hook_init(); -} \ No newline at end of file +} + +#endif diff --git a/src/spice2x/games/pc/bi2x_hook.cpp b/src/spice2x/games/pc/bi2x_hook.cpp index c1100e9..bfbb58d 100644 --- a/src/spice2x/games/pc/bi2x_hook.cpp +++ b/src/spice2x/games/pc/bi2x_hook.cpp @@ -1,5 +1,7 @@ #include "bi2x_hook.h" +#if SPICE64 + #include "util/execexe.h" #include "util/logging.h" #include "rawinput/rawinput.h" @@ -9,9 +11,10 @@ #include "util/tapeled.h" #include "pc.h" #include "util/utils.h" +#include "util/time.h" +#include "util/socd_cleaner.h" namespace games::pc { - bool PC_KNOB_MODE = false; constexpr float RELATIVE_DECAY = 0.02f; struct FADER_RELATIVE { @@ -75,18 +78,22 @@ namespace games::pc { */ struct AIO_SCI_COMM { + uint8_t data[0xf8]; }; struct AIO_NMGR_IOB2 { + uint8_t data[0xe30]; }; struct AIO_IOB2_BI2X_AC1 { + uint8_t data[0x4538]; }; struct AIO_IOB2_BI2X_AC1__SETTING { }; struct AIO_IOB2_BI2X_WRFIRM { + uint8_t data[0x20f48]; }; struct AIO_IOB2_BI2X_AC1__INPUT @@ -191,6 +198,12 @@ namespace games::pc { AIO_IOB2_BI2X_AC1__ICNPIN ICnPinHist[20]; }; + // verified with XIF-2024122300 + static_assert(sizeof(AIO_SCI_COMM) == 0xf8); + static_assert(sizeof(AIO_NMGR_IOB2) == 0xe30); + static_assert(sizeof(AIO_IOB2_BI2X_AC1) == 0x4538); + static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48); + /* * typedefs */ @@ -338,14 +351,21 @@ namespace games::pc { val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2; } } - if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]) && - GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) { - val = 0.f; - } else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left])) { + + const auto now = get_performance_milliseconds(); + + const auto fader_l_socd = socd::socd_clean( + 0, // Fader-L + GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]), + GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right]), + now); + + if (fader_l_socd == socd::SocdCCW) { val = -1.0f; - } else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) { + } else if (fader_l_socd == socd::SocdCW) { val = +1.0f; } + o_DevStatus->Input.CN15_7 = (val < 0.2f) ? 0xFF : 0; o_DevStatus->Input.CN15_6 = (val > -0.85f && val < 0.35f) ? 0xFF : 0; o_DevStatus->Input.CN15_5 = (val > -0.6f && val < 0.6f) ? 0xFF : 0; @@ -363,14 +383,19 @@ namespace games::pc { val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2; } } - if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]) && - GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) { - val = 0.f; - } else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left])) { + + const auto fader_r_socd = socd::socd_clean( + 1, // Fader-R + GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]), + GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right]), + now); + + if (fader_r_socd == socd::SocdCCW) { val = -1.0f; - } else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) { + } else if (fader_r_socd == socd::SocdCW) { val = +1.0f; } + o_DevStatus->Input.CN11_20 = (val < 0.2f) ? 0xFF : 0; o_DevStatus->Input.CN11_19 = (val > -0.85f && val < 0.35f) ? 0xFF : 0; o_DevStatus->Input.CN9_10 = (val > -0.6f && val < 0.6f) ? 0xFF : 0; @@ -737,3 +762,5 @@ namespace games::pc { } } + +#endif \ No newline at end of file diff --git a/src/spice2x/games/pc/bi2x_hook.h b/src/spice2x/games/pc/bi2x_hook.h index 3a30b3c..7f52b4d 100644 --- a/src/spice2x/games/pc/bi2x_hook.h +++ b/src/spice2x/games/pc/bi2x_hook.h @@ -1,5 +1,9 @@ #pragma once +#if SPICE64 + namespace games::pc { void bi2x_hook_init(); } + +#endif diff --git a/src/spice2x/games/pc/pc.cpp b/src/spice2x/games/pc/pc.cpp index 23b2716..a1ed135 100644 --- a/src/spice2x/games/pc/pc.cpp +++ b/src/spice2x/games/pc/pc.cpp @@ -12,10 +12,12 @@ #include "misc/wintouchemu.h" #include "hooks/graphics/graphics.h" #include "rawinput/rawinput.h" +#include "util/socd_cleaner.h" namespace games::pc { std::string PC_INJECT_ARGS = ""; bool PC_NO_IO = false; + bool PC_KNOB_MODE = false; static acioemu::ACIOHandle *acioHandle = nullptr; static std::wstring portName = L"COM1"; @@ -61,6 +63,11 @@ namespace games::pc { return ERROR_NOT_SUPPORTED; } + void PCGame::pre_attach() { + // SOCD + socd::ALGORITHM = socd::SocdAlgorithm::PreferRecent; + } + void PCGame::attach() { Game::attach(); @@ -78,9 +85,14 @@ namespace games::pc { execexe::load_library("libaio-iob2_video.dll"); execexe::load_library("win10actlog.dll"); +#if SPICE64 + if (!PC_NO_IO) { bi2x_hook_init(); } + +#endif + }); const auto user32Dll = "user32.dll"; diff --git a/src/spice2x/games/pc/pc.h b/src/spice2x/games/pc/pc.h index 0eca4c3..487d9b5 100644 --- a/src/spice2x/games/pc/pc.h +++ b/src/spice2x/games/pc/pc.h @@ -11,6 +11,7 @@ namespace games::pc { public: PCGame() : Game("Polaris Chord") {} + virtual void pre_attach() override; virtual void attach() override; virtual void detach() override; }; diff --git a/src/spice2x/games/qks/bi2x_hook.cpp b/src/spice2x/games/qks/bi2x_hook.cpp index 36ed09a..795d931 100644 --- a/src/spice2x/games/qks/bi2x_hook.cpp +++ b/src/spice2x/games/qks/bi2x_hook.cpp @@ -1,5 +1,7 @@ #include "bi2x_hook.h" +#if SPICE64 + #include "util/detour.h" #include "util/logging.h" #include "rawinput/rawinput.h" @@ -15,15 +17,19 @@ namespace games::qks { */ struct AIO_SCI_COMM { + uint8_t data[0xf8]; }; struct AIO_NMGR_IOB { + uint8_t data[0xa00]; }; struct AIO_IOB2_BI2X_AC1 { + uint8_t data[0x3908]; }; struct AIO_IOB2_BI2X_WRFIRM { + uint8_t data[0x20f48]; }; struct AIO_NMGR_IOB__NODEINFO { @@ -174,6 +180,12 @@ namespace games::qks { AIO_IOB2_BI2X_AC1__SETTING Setting; }; + // verified with UKS-001-2024030600 + static_assert(sizeof(AIO_IOB2_BI2X_AC1) == 0x3908); + static_assert(sizeof(AIO_SCI_COMM) == 0xf8); + static_assert(sizeof(AIO_NMGR_IOB) == 0xa00); + static_assert(sizeof(AIO_IOB2_BI2X_WRFIRM) == 0x20f48); + /* * typedefs */ @@ -602,4 +614,6 @@ namespace games::qks { detour::trampoline_try(libaioDll, "aioNodeCtl_IsError", aioNodeCtl_IsError, &aioNodeCtl_IsError_orig); } -} \ No newline at end of file +} + +#endif diff --git a/src/spice2x/games/qks/bi2x_hook.h b/src/spice2x/games/qks/bi2x_hook.h index fcaabbb..e36509f 100644 --- a/src/spice2x/games/qks/bi2x_hook.h +++ b/src/spice2x/games/qks/bi2x_hook.h @@ -1,7 +1,11 @@ #pragma once +#if SPICE64 + #include namespace games::qks { void bi2x_hook_init(); -} \ No newline at end of file +} + +#endif diff --git a/src/spice2x/games/qks/qks.cpp b/src/spice2x/games/qks/qks.cpp index 5223ada..6924b96 100644 --- a/src/spice2x/games/qks/qks.cpp +++ b/src/spice2x/games/qks/qks.cpp @@ -86,9 +86,13 @@ namespace games::qks { detour::trampoline_try("execexe.dll", MAKEINTRESOURCE(9), execexe_CreateFileA_hook,&execexe_CreateFileA_orig); +#if SPICE64 + // insert BI2X hooks bi2x_hook_init(); +#endif + // add card reader acioHandle = new acioemu::ACIOHandle(portName.c_str()); devicehook_init_trampoline();