624 lines
27 KiB
C++
624 lines
27 KiB
C++
|
#include "bi2x_hook.h"
|
||
|
|
||
|
#include <cstdint>
|
||
|
#include "util/detour.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::ccj {
|
||
|
|
||
|
/*
|
||
|
* class definitions
|
||
|
*/
|
||
|
|
||
|
struct AIO_SCI_COMM {
|
||
|
};
|
||
|
|
||
|
struct AIO_NMGR_IOB2 {
|
||
|
};
|
||
|
|
||
|
struct AIO_IOB2_BI2X_TBS {
|
||
|
};
|
||
|
|
||
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||
|
};
|
||
|
|
||
|
struct AIO_NMGR_IOB__NODEINFO {
|
||
|
uint8_t data[0xA3];
|
||
|
};
|
||
|
|
||
|
struct AIO_IOB2_BI2X_AC1__INPUTDATA {
|
||
|
uint8_t data[247];
|
||
|
};
|
||
|
|
||
|
struct AIO_IOB2_BI2X_AC1__OUTPUTDATA {
|
||
|
uint8_t data[48];
|
||
|
};
|
||
|
|
||
|
struct AIO_IOB2_BI2X_TBS__INPUT {
|
||
|
uint8_t DevIoCounter;
|
||
|
uint8_t bExIoAErr;
|
||
|
uint8_t bExIoBErr;
|
||
|
uint8_t bPcPowerOn;
|
||
|
uint8_t bPcPowerCheck;
|
||
|
uint8_t CoinCount;
|
||
|
uint8_t bTest;
|
||
|
uint8_t bService;
|
||
|
uint8_t bCoinSw;
|
||
|
uint8_t bCoinJam;
|
||
|
uint8_t bHPDetect;
|
||
|
uint16_t StickY;
|
||
|
uint16_t StickX;
|
||
|
uint8_t bStickBtn;
|
||
|
uint8_t bTrigger1;
|
||
|
uint8_t bTrigger2;
|
||
|
uint8_t bButton0;
|
||
|
uint8_t bButton1;
|
||
|
uint8_t bButton2;
|
||
|
uint8_t bButton3;
|
||
|
};
|
||
|
|
||
|
struct AIO_IOB2_BI2X_TBS__DEVSTATUS {
|
||
|
uint8_t InputCounter;
|
||
|
uint8_t OutputCounter;
|
||
|
uint8_t IoResetCounter;
|
||
|
uint8_t TapeLedCounter;
|
||
|
AIO_IOB2_BI2X_TBS__INPUT Input;
|
||
|
AIO_IOB2_BI2X_AC1__INPUTDATA InputData;
|
||
|
AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData;
|
||
|
};
|
||
|
|
||
|
static void write_iccr_led(Lights::ccj_lights_t light, uint8_t value);
|
||
|
|
||
|
/*
|
||
|
* typedefs
|
||
|
*/
|
||
|
|
||
|
// libaio-iob2_video.dll
|
||
|
typedef AIO_IOB2_BI2X_TBS* (__fastcall *aioIob2Bi2xTBS_Create_t)(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_GetDeviceStatus_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl,
|
||
|
AIO_IOB2_BI2X_TBS__DEVSTATUS *o_DevStatus);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_IoReset_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_bfIoReset);
|
||
|
typedef void (__fastcall *aioIob2Bi2xAC1_IoReset_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_bfIoReset);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetWatchDogTimer_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint8_t i_Count);
|
||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetWatchDogTimer_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint8_t i_Count);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_ControlCoinBlocker_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_Slot,
|
||
|
bool i_bOpen);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_AddCounter_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_Counter,
|
||
|
uint32_t i_Count);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetAmpVolume_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_Amp,
|
||
|
uint32_t i_Volume);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_EnableUsbCharger_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, bool i_bEnable);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetIrLed_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, bool i_bOn);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetButton0Lamp_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, bool i_bOn);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetIccrLed_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_RGB);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetStickLed_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_RGB);
|
||
|
typedef void (__fastcall *aioIob2Bi2xTBS_SetTapeLedData_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_TapeLed, uint8_t *i_pData);
|
||
|
typedef AIO_SCI_COMM* (__fastcall *aioIob2Bi2x_OpenSciUsbCdc_t)(uint32_t i_SerialNumber);
|
||
|
typedef AIO_IOB2_BI2X_WRFIRM* (__fastcall *aioIob2Bi2x_CreateWriteFirmContext_t)(uint32_t i_SerialNumber,
|
||
|
uint32_t i_bfIob);
|
||
|
typedef void (__fastcall *aioIob2Bi2x_DestroyWriteFirmContext_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||
|
typedef int32_t (__fastcall *aioIob2Bi2x_WriteFirmGetState_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsCompleted_t)(int32_t i_State);
|
||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsError_t)(int32_t i_State);
|
||
|
|
||
|
// libaio-iob.dll
|
||
|
typedef AIO_NMGR_IOB2* (__fastcall *aioNMgrIob2_Create_t)(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode);
|
||
|
typedef void (__fastcall *aioNMgrIob_BeginManage_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||
|
typedef void (__fastcall *aioNCtlIob_GetNodeInfo_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl,
|
||
|
AIO_NMGR_IOB__NODEINFO *o_NodeInfo);
|
||
|
|
||
|
// libaio.dll
|
||
|
typedef void (__fastcall *aioNodeMgr_Destroy_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||
|
typedef int32_t (__fastcall *aioNodeMgr_GetState_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||
|
typedef bool (__fastcall *aioNodeMgr_IsReady_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||
|
typedef bool (__fastcall *aioNodeMgr_IsError_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||
|
typedef void (__fastcall *aioNodeCtl_Destroy_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl);
|
||
|
typedef int32_t (__fastcall *aioNodeCtl_GetState_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl);
|
||
|
typedef bool (__fastcall *aioNodeCtl_IsReady_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, int32_t i_State);
|
||
|
typedef bool (__fastcall *aioNodeCtl_IsError_t)(AIO_IOB2_BI2X_TBS *i_pNodeCtl, int32_t i_State);
|
||
|
|
||
|
/*
|
||
|
* function pointers
|
||
|
*/
|
||
|
|
||
|
// libaio-iob2_video.dll
|
||
|
static aioIob2Bi2xTBS_Create_t aioIob2Bi2xTBS_Create_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_GetDeviceStatus_t aioIob2Bi2xTBS_GetDeviceStatus_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_IoReset_t aioIob2Bi2xTBS_IoReset_orig = nullptr;
|
||
|
static aioIob2Bi2xAC1_IoReset_t aioIob2Bi2xAC1_IoReset_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetWatchDogTimer_t aioIob2Bi2xTBS_SetWatchDogTimer_orig = nullptr;
|
||
|
static aioIob2Bi2xAC1_SetWatchDogTimer_t aioIob2Bi2xAC1_SetWatchDogTimer_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_ControlCoinBlocker_t aioIob2Bi2xTBS_ControlCoinBlocker_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_AddCounter_t aioIob2Bi2xTBS_AddCounter_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetAmpVolume_t aioIob2Bi2xTBS_SetAmpVolume_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_EnableUsbCharger_t aioIob2Bi2xTBS_EnableUsbCharger_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetIrLed_t aioIob2Bi2xTBS_SetIrLed_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetButton0Lamp_t aioIob2Bi2xTBS_SetButton0Lamp_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetIccrLed_t aioIob2Bi2xTBS_SetIccrLed_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetStickLed_t aioIob2Bi2xTBS_SetStickLed_orig = nullptr;
|
||
|
static aioIob2Bi2xTBS_SetTapeLedData_t aioIob2Bi2xTBS_SetTapeLedData_orig = nullptr;
|
||
|
static aioIob2Bi2x_OpenSciUsbCdc_t aioIob2Bi2x_OpenSciUsbCdc_orig = nullptr;
|
||
|
static aioIob2Bi2x_CreateWriteFirmContext_t aioIob2Bi2x_CreateWriteFirmContext_orig = nullptr;
|
||
|
static aioIob2Bi2x_DestroyWriteFirmContext_t aioIob2Bi2x_DestroyWriteFirmContext_orig = nullptr;
|
||
|
static aioIob2Bi2x_WriteFirmGetState_t aioIob2Bi2x_WriteFirmGetState_orig = nullptr;
|
||
|
static aioIob2Bi2x_WriteFirmIsCompleted_t aioIob2Bi2x_WriteFirmIsCompleted_orig = nullptr;
|
||
|
static aioIob2Bi2x_WriteFirmIsError_t aioIob2Bi2x_WriteFirmIsError_orig = nullptr;
|
||
|
|
||
|
// libaio-iob.dll
|
||
|
static aioNMgrIob2_Create_t aioNMgrIob2_Create_orig = nullptr;
|
||
|
static aioNMgrIob_BeginManage_t aioNMgrIob_BeginManage_orig = nullptr;
|
||
|
static aioNCtlIob_GetNodeInfo_t aioNCtlIob_GetNodeInfo_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_IOB2 *aioNmgrIob2;
|
||
|
static AIO_IOB2_BI2X_TBS *aioIob2Bi2xTbs;
|
||
|
static AIO_IOB2_BI2X_WRFIRM *aioIob2Bi2xWrfirm;
|
||
|
|
||
|
static uint8_t count = 0;
|
||
|
|
||
|
/*
|
||
|
* implementations
|
||
|
*/
|
||
|
|
||
|
static AIO_IOB2_BI2X_TBS* __fastcall aioIob2Bi2xTBS_Create(
|
||
|
AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId) {
|
||
|
|
||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||
|
log_info("bi2x_hook", "node created");
|
||
|
aioIob2Bi2xTbs = new AIO_IOB2_BI2X_TBS;
|
||
|
return aioIob2Bi2xTbs;
|
||
|
} else {
|
||
|
return aioIob2Bi2xTBS_Create_orig(i_pNodeMgr, i_DevId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_GetDeviceStatus(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, AIO_IOB2_BI2X_TBS__DEVSTATUS *o_DevStatus) {
|
||
|
|
||
|
RI_MGR->devices_flush_output();
|
||
|
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_GetDeviceStatus_orig(i_pNodeCtl, o_DevStatus);
|
||
|
}
|
||
|
|
||
|
memset(o_DevStatus, 0x00, sizeof(AIO_IOB2_BI2X_TBS__DEVSTATUS));
|
||
|
|
||
|
o_DevStatus->Input.DevIoCounter = count;
|
||
|
count++;
|
||
|
|
||
|
o_DevStatus->Input.StickX = 32768;
|
||
|
o_DevStatus->Input.StickY = 32768;
|
||
|
|
||
|
auto &analogs = get_analogs();
|
||
|
if (analogs[Analogs::Joystick_X].isSet() || analogs[Analogs::Joystick_Y].isSet()) {
|
||
|
o_DevStatus->Input.StickX =
|
||
|
65535 - (uint16_t) (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::Joystick_X]) * 65535);
|
||
|
o_DevStatus->Input.StickY =
|
||
|
65535 - (uint16_t) (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::Joystick_Y]) * 65535);
|
||
|
}
|
||
|
|
||
|
auto &buttons = get_buttons();
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test]))
|
||
|
o_DevStatus->Input.bTest = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service]))
|
||
|
o_DevStatus->Input.bService = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech]))
|
||
|
o_DevStatus->Input.bCoinSw = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Joystick_Up]))
|
||
|
o_DevStatus->Input.StickY = 65535;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Joystick_Down]))
|
||
|
o_DevStatus->Input.StickY = 0;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Joystick_Left]))
|
||
|
o_DevStatus->Input.StickX = 65535;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Joystick_Right]))
|
||
|
o_DevStatus->Input.StickX = 0;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button_Dash]))
|
||
|
o_DevStatus->Input.bTrigger1 = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button_Special]))
|
||
|
o_DevStatus->Input.bButton0 = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button_Action]))
|
||
|
o_DevStatus->Input.bButton1 = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button_Jump]))
|
||
|
o_DevStatus->Input.bButton2 = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button_Slide]))
|
||
|
o_DevStatus->Input.bButton3 = 1;
|
||
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Headphones]))
|
||
|
o_DevStatus->Input.bHPDetect = 1;
|
||
|
|
||
|
o_DevStatus->Input.CoinCount = eamuse_coin_get_stock();
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xAC1_IoReset(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_bfIoReset) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
} else {
|
||
|
return aioIob2Bi2xAC1_IoReset_orig(i_pNodeCtl, i_bfIoReset);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_IoReset(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_bfIoReset) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xAC1_IoReset(i_pNodeCtl, i_bfIoReset);
|
||
|
} else {
|
||
|
return aioIob2Bi2xTBS_IoReset_orig(i_pNodeCtl, i_bfIoReset);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xAC1_SetWatchDogTimer(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint8_t i_Count) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
} else {
|
||
|
return aioIob2Bi2xAC1_SetWatchDogTimer_orig(i_pNodeCtl, i_Count);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetWatchDogTimer(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint8_t i_Count) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xAC1_SetWatchDogTimer(i_pNodeCtl, i_Count);
|
||
|
} else {
|
||
|
return aioIob2Bi2xTBS_SetWatchDogTimer_orig(i_pNodeCtl, i_Count);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_ControlCoinBlocker(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_Slot, bool i_bOpen) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
eamuse_coin_set_block(!i_bOpen);
|
||
|
} else {
|
||
|
return aioIob2Bi2xTBS_ControlCoinBlocker_orig(i_pNodeCtl, i_Slot, i_bOpen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_AddCounter(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_Counter, uint32_t i_Count) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs && i_Count == 0) {
|
||
|
eamuse_coin_set_stock((uint16_t) i_Count);
|
||
|
} else {
|
||
|
return aioIob2Bi2xTBS_AddCounter_orig(i_pNodeCtl, i_Counter, i_Count);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetAmpVolume(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_Amp, uint32_t i_Volume) {
|
||
|
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_SetAmpVolume_orig(i_pNodeCtl, i_Amp, i_Volume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_EnableUsbCharger(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, bool i_bEnable) {
|
||
|
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_EnableUsbCharger_orig(i_pNodeCtl, i_bEnable);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetIrLed(AIO_IOB2_BI2X_TBS *i_pNodeCtl, bool i_bOn) {
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_SetIrLed_orig(i_pNodeCtl, i_bOn);
|
||
|
}
|
||
|
|
||
|
// handle ir led
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetButton0Lamp(AIO_IOB2_BI2X_TBS *i_pNodeCtl, bool i_bOn) {
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_SetButton0Lamp_orig(i_pNodeCtl, i_bOn);
|
||
|
}
|
||
|
|
||
|
auto &lights = get_lights();
|
||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::SpecialButton), (i_bOn ? 1.f : 0.f));
|
||
|
}
|
||
|
|
||
|
static void write_iccr_led(Lights::ccj_lights_t light, uint8_t value) {
|
||
|
auto &lights = get_lights();
|
||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(light), value / 255);
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetIccrLed(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_RGB) {
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_SetIccrLed_orig(i_pNodeCtl, i_RGB);
|
||
|
}
|
||
|
|
||
|
write_iccr_led(Lights::CardReader_B, i_RGB);
|
||
|
write_iccr_led(Lights::CardReader_G, i_RGB >> 8);
|
||
|
write_iccr_led(Lights::CardReader_R, i_RGB >> 16);
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetStickLed(AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_RGB) {
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_SetStickLed_orig(i_pNodeCtl, i_RGB);
|
||
|
}
|
||
|
|
||
|
// handle stick led
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2xTBS_SetTapeLedData(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, uint32_t i_TapeLed, uint8_t *i_pData) {
|
||
|
|
||
|
if (i_pNodeCtl != aioIob2Bi2xTbs) {
|
||
|
return aioIob2Bi2xTBS_SetTapeLedData_orig(i_pNodeCtl, i_TapeLed, i_pData);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* index mapping
|
||
|
* 0 - title panel - 144 bytes - 48 colors
|
||
|
* 1 - side panel - 147 bytes - 49 colors
|
||
|
*
|
||
|
* data is stored in RGB order, 3 bytes per color
|
||
|
*
|
||
|
* TODO: expose this data via API
|
||
|
*/
|
||
|
static struct TapeLedMapping {
|
||
|
size_t data_size;
|
||
|
int r, g, b;
|
||
|
|
||
|
TapeLedMapping(size_t data_size, int r, int g, int b)
|
||
|
: data_size(data_size), r(r), g(g), b(b) {}
|
||
|
|
||
|
} mapping[] = {
|
||
|
{ 48, Lights::TitlePanel_R, Lights::TitlePanel_G, Lights::TitlePanel_B },
|
||
|
{ 49, Lights::SidePanel_R, Lights::SidePanel_G, Lights::SidePanel_B },
|
||
|
};
|
||
|
|
||
|
if (tapeledutils::is_enabled() && i_TapeLed < std::size(mapping)) {
|
||
|
auto &map = mapping[i_TapeLed];
|
||
|
|
||
|
// pick a color to use
|
||
|
const auto rgb = tapeledutils::pick_color_from_led_tape(i_pData, map.data_size);
|
||
|
|
||
|
// program the lights into API
|
||
|
auto &lights = get_lights();
|
||
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.r], rgb.r);
|
||
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.g], rgb.g);
|
||
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.b], rgb.b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static AIO_SCI_COMM* __fastcall aioIob2Bi2x_OpenSciUsbCdc(uint32_t i_SerialNumber) {
|
||
|
aioSciComm = new AIO_SCI_COMM;
|
||
|
return aioSciComm;
|
||
|
}
|
||
|
|
||
|
static AIO_IOB2_BI2X_WRFIRM* __fastcall aioIob2Bi2x_CreateWriteFirmContext(
|
||
|
uint32_t i_SerialNumber, uint32_t i_bfIob) {
|
||
|
|
||
|
aioIob2Bi2xWrfirm = new AIO_IOB2_BI2X_WRFIRM;
|
||
|
return aioIob2Bi2xWrfirm;
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioIob2Bi2x_DestroyWriteFirmContext(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||
|
delete aioIob2Bi2xWrfirm;
|
||
|
aioIob2Bi2xWrfirm = nullptr;
|
||
|
} else {
|
||
|
return aioIob2Bi2x_DestroyWriteFirmContext_orig(i_pWrFirm);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int32_t __fastcall aioIob2Bi2x_WriteFirmGetState(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||
|
return 8;
|
||
|
} else {
|
||
|
return aioIob2Bi2x_WriteFirmGetState_orig(i_pWrFirm);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsCompleted(int32_t i_State) {
|
||
|
if (aioIob2Bi2xWrfirm != nullptr)
|
||
|
return true;
|
||
|
return aioIob2Bi2x_WriteFirmIsCompleted_orig(i_State);
|
||
|
}
|
||
|
|
||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsError(int32_t i_State) {
|
||
|
if (aioIob2Bi2xWrfirm != nullptr)
|
||
|
return false;
|
||
|
return aioIob2Bi2x_WriteFirmIsError_orig(i_State);
|
||
|
}
|
||
|
|
||
|
static AIO_NMGR_IOB2* __fastcall aioNMgrIob2_Create(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode) {
|
||
|
if (i_pSci == aioSciComm) {
|
||
|
aioNmgrIob2 = new AIO_NMGR_IOB2;
|
||
|
return aioNmgrIob2;
|
||
|
} else {
|
||
|
return aioNMgrIob2_Create_orig(i_pSci, i_bfMode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioNMgrIob_BeginManage(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||
|
} else {
|
||
|
return aioNMgrIob_BeginManage_orig(i_pNodeMgr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioNCtlIob_GetNodeInfo(
|
||
|
AIO_IOB2_BI2X_TBS *i_pNodeCtl, AIO_NMGR_IOB__NODEINFO *o_NodeInfo) {
|
||
|
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
memset(o_NodeInfo, 0, sizeof(AIO_NMGR_IOB__NODEINFO));
|
||
|
} else {
|
||
|
return aioNCtlIob_GetNodeInfo_orig(i_pNodeCtl, o_NodeInfo);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioNodeMgr_Destroy(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||
|
delete aioNmgrIob2;
|
||
|
aioNmgrIob2 = nullptr;
|
||
|
} else {
|
||
|
return aioNodeMgr_Destroy_orig(i_pNodeMgr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int32_t __fastcall aioNodeMgr_GetState(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return aioNodeMgr_GetState_orig(i_pNodeMgr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool __fastcall aioNodeMgr_IsReady(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return aioNodeMgr_IsReady_orig(i_pNodeMgr, i_State);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool __fastcall aioNodeMgr_IsError(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||
|
return false;
|
||
|
} else {
|
||
|
return aioNodeMgr_IsError_orig(i_pNodeMgr, i_State);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void __fastcall aioNodeCtl_Destroy(AIO_IOB2_BI2X_TBS *i_pNodeCtl) {
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
delete aioIob2Bi2xTbs;
|
||
|
aioIob2Bi2xTbs = nullptr;
|
||
|
} else {
|
||
|
return aioNodeCtl_Destroy_orig(i_pNodeCtl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int32_t __fastcall aioNodeCtl_GetState(AIO_IOB2_BI2X_TBS *i_pNodeCtl) {
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
return 1;
|
||
|
} else {
|
||
|
return aioNodeCtl_GetState_orig(i_pNodeCtl);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool __fastcall aioNodeCtl_IsReady(AIO_IOB2_BI2X_TBS *i_pNodeCtl, int32_t i_State) {
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return aioNodeCtl_IsReady_orig(i_pNodeCtl, i_State);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool __fastcall aioNodeCtl_IsError(AIO_IOB2_BI2X_TBS *i_pNodeCtl, int32_t i_State) {
|
||
|
if (i_pNodeCtl == aioIob2Bi2xTbs) {
|
||
|
return false;
|
||
|
} else {
|
||
|
return aioNodeCtl_IsError_orig(i_pNodeCtl, i_State);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void bi2x_hook_init() {
|
||
|
// avoid double init
|
||
|
static bool initialized = false;
|
||
|
if (initialized) {
|
||
|
return;
|
||
|
} else {
|
||
|
initialized = true;
|
||
|
}
|
||
|
|
||
|
// announce
|
||
|
log_info("bi2x_hook", "init");
|
||
|
|
||
|
// libaio-iob2_video.dll
|
||
|
const auto libaioIob2VideoDll = "libaio-iob2_video.dll";
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_Create",
|
||
|
aioIob2Bi2xTBS_Create, &aioIob2Bi2xTBS_Create_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_GetDeviceStatus",
|
||
|
aioIob2Bi2xTBS_GetDeviceStatus, &aioIob2Bi2xTBS_GetDeviceStatus_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_IoReset",
|
||
|
aioIob2Bi2xTBS_IoReset, &aioIob2Bi2xTBS_IoReset_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_IoReset",
|
||
|
aioIob2Bi2xAC1_IoReset, &aioIob2Bi2xAC1_IoReset_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetWatchDogTimer",
|
||
|
aioIob2Bi2xTBS_SetWatchDogTimer, &aioIob2Bi2xTBS_SetWatchDogTimer_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetWatchDogTimer",
|
||
|
aioIob2Bi2xAC1_SetWatchDogTimer, &aioIob2Bi2xAC1_SetWatchDogTimer_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_ControlCoinBlocker",
|
||
|
aioIob2Bi2xTBS_ControlCoinBlocker, &aioIob2Bi2xTBS_ControlCoinBlocker_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_AddCounter",
|
||
|
aioIob2Bi2xTBS_AddCounter, &aioIob2Bi2xTBS_AddCounter_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetAmpVolume",
|
||
|
aioIob2Bi2xTBS_SetAmpVolume, &aioIob2Bi2xTBS_SetAmpVolume_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_EnableUsbCharger",
|
||
|
aioIob2Bi2xTBS_EnableUsbCharger, &aioIob2Bi2xTBS_EnableUsbCharger_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetIrLed",
|
||
|
aioIob2Bi2xTBS_SetIrLed, &aioIob2Bi2xTBS_SetIrLed_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetButton0Lamp",
|
||
|
aioIob2Bi2xTBS_SetButton0Lamp, &aioIob2Bi2xTBS_SetButton0Lamp_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetIccrLed",
|
||
|
aioIob2Bi2xTBS_SetIccrLed, &aioIob2Bi2xTBS_SetIccrLed_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetStickLed",
|
||
|
aioIob2Bi2xTBS_SetStickLed, &aioIob2Bi2xTBS_SetStickLed_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTBS_SetTapeLedData",
|
||
|
aioIob2Bi2xTBS_SetTapeLedData, &aioIob2Bi2xTBS_SetTapeLedData_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_OpenSciUsbCdc",
|
||
|
aioIob2Bi2x_OpenSciUsbCdc, &aioIob2Bi2x_OpenSciUsbCdc_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_CreateWriteFirmContext",
|
||
|
aioIob2Bi2x_CreateWriteFirmContext, &aioIob2Bi2x_CreateWriteFirmContext_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_DestroyWriteFirmContext",
|
||
|
aioIob2Bi2x_DestroyWriteFirmContext, &aioIob2Bi2x_DestroyWriteFirmContext_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmGetState",
|
||
|
aioIob2Bi2x_WriteFirmGetState, &aioIob2Bi2x_WriteFirmGetState_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsCompleted",
|
||
|
aioIob2Bi2x_WriteFirmIsCompleted, &aioIob2Bi2x_WriteFirmIsCompleted_orig);
|
||
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsError",
|
||
|
aioIob2Bi2x_WriteFirmIsError, &aioIob2Bi2x_WriteFirmIsError_orig);
|
||
|
|
||
|
// libaio-iob.dll
|
||
|
const auto libaioIobDll = "libaio-iob.dll";
|
||
|
detour::trampoline_try(libaioIobDll, "aioNMgrIob2_Create",
|
||
|
aioNMgrIob2_Create, &aioNMgrIob2_Create_orig);
|
||
|
detour::trampoline_try(libaioIobDll, "aioNMgrIob_BeginManage",
|
||
|
aioNMgrIob_BeginManage, &aioNMgrIob_BeginManage_orig);
|
||
|
detour::trampoline_try(libaioIobDll, "aioNCtlIob_GetNodeInfo",
|
||
|
aioNCtlIob_GetNodeInfo, &aioNCtlIob_GetNodeInfo_orig);
|
||
|
|
||
|
// libaio.dll
|
||
|
const auto libaioDll = "libaio.dll";
|
||
|
detour::trampoline_try(libaioDll, "aioNodeMgr_Destroy",
|
||
|
aioNodeMgr_Destroy, &aioNodeMgr_Destroy_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeMgr_GetState",
|
||
|
aioNodeMgr_GetState, &aioNodeMgr_GetState_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeMgr_IsReady",
|
||
|
aioNodeMgr_IsReady, &aioNodeMgr_IsReady_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeMgr_IsError",
|
||
|
aioNodeMgr_IsError, &aioNodeMgr_IsError_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeCtl_Destroy",
|
||
|
aioNodeCtl_Destroy, &aioNodeCtl_Destroy_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeCtl_GetState",
|
||
|
aioNodeCtl_GetState, &aioNodeCtl_GetState_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeCtl_IsReady",
|
||
|
aioNodeCtl_IsReady, &aioNodeCtl_IsReady_orig);
|
||
|
detour::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||
|
}
|
||
|
}
|