548 lines
24 KiB
C++
548 lines
24 KiB
C++
#include "bi2x_hook.h"
|
|
|
|
#include <cstdint>
|
|
#include "util/detour.h"
|
|
#include "util/logging.h"
|
|
#include "util/utils.h"
|
|
#include "rawinput/rawinput.h"
|
|
#include "misc/eamuse.h"
|
|
#include "games/io.h"
|
|
#include "launcher/options.h"
|
|
#include "io.h"
|
|
#include "iidx.h"
|
|
#include "util/tapeled.h"
|
|
|
|
namespace games::iidx {
|
|
constexpr bool BI2X_PASSTHROUGH = false;
|
|
|
|
/*
|
|
* class definitions
|
|
*/
|
|
|
|
struct AC_HNDLIF {
|
|
// dummy
|
|
uint8_t data[0x10];
|
|
};
|
|
|
|
struct AIO_NMGR_IOB2 {
|
|
uint8_t dummy0[0x50];
|
|
void (__fastcall *pAIO_NMGR_IOB_BeginManage)(int64_t a1);
|
|
uint8_t dummy1[0x9A0];
|
|
};
|
|
|
|
struct AIO_IOB2_BI2X_TDJ {
|
|
// who knows
|
|
uint8_t data[0x13F8];
|
|
};
|
|
|
|
struct AIO_IOB2_BI2X_TDJ__DEVSTATUS {
|
|
// of course you could work with variables here
|
|
uint8_t buffer[0xCA];
|
|
};
|
|
|
|
/*
|
|
* typedefs
|
|
*/
|
|
|
|
// libaio-iob2_video.dll
|
|
typedef AIO_IOB2_BI2X_TDJ* (__fastcall *aioIob2Bi2xTDJ_Create_t)(AIO_NMGR_IOB2 *nmgr, int a2);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__GetDeviceStatus_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
AIO_IOB2_BI2X_TDJ__DEVSTATUS *a2);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__IoReset_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int a2);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetWatchDogTimer_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
uint8_t a2);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__ControlCoinBlocker_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
int index, uint8_t state);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__AddCounter_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
int a2, int a3);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetStartLamp_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
int player, uint8_t state);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
uint8_t state);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
uint8_t state);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
int player, int button, uint8_t state);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetWooferLED_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint32_t color);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetIccrLed_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint32_t color);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetTurnTableLed_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint32_t color);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetTurnTableResist_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint8_t resistance);
|
|
typedef void (__fastcall *AIO_IOB2_BI2X_TDJ__SetTapeLedData_t)(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint8_t *data);
|
|
|
|
// libaio-iob.dll
|
|
typedef AC_HNDLIF* (__fastcall *aioIob2Bi2x_OpenSciUsbCdc_t)(uint8_t device_num);
|
|
typedef int64_t (__fastcall *aioIob2Bi2x_WriteFirmGetState_t)(int64_t a1);
|
|
typedef AIO_NMGR_IOB2** (__fastcall *aioNMgrIob2_Create_t)(AC_HNDLIF *a1, unsigned int a2);
|
|
|
|
/*
|
|
* function pointers
|
|
*/
|
|
|
|
// libaio-iob2_video.dll
|
|
static aioIob2Bi2xTDJ_Create_t aioIob2Bi2xTDJ_Create_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__GetDeviceStatus_t AIO_IOB2_BI2X_TDJ__GetDeviceStatus_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__IoReset_t AIO_IOB2_BI2X_TDJ__IoReset_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetWatchDogTimer_t AIO_IOB2_BI2X_TDJ__SetWatchDogTimer_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__ControlCoinBlocker_t AIO_IOB2_BI2X_TDJ__ControlCoinBlocker_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__AddCounter_t AIO_IOB2_BI2X_TDJ__AddCounter_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetStartLamp_t AIO_IOB2_BI2X_TDJ__SetStartLamp_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp_t AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp_t AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp_t AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetWooferLED_t AIO_IOB2_BI2X_TDJ__SetWooferLED_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetIccrLed_t AIO_IOB2_BI2X_TDJ__SetIccrLed_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetTurnTableLed_t AIO_IOB2_BI2X_TDJ__SetTurnTableLed_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetTurnTableResist_t AIO_IOB2_BI2X_TDJ__SetTurnTableResist_orig = nullptr;
|
|
static AIO_IOB2_BI2X_TDJ__SetTapeLedData_t AIO_IOB2_BI2X_TDJ__SetTapeLedData_orig = nullptr;
|
|
|
|
// libaio-iob.dll
|
|
static aioIob2Bi2x_OpenSciUsbCdc_t aioIob2Bi2x_OpenSciUsbCdc_orig = nullptr;
|
|
static aioIob2Bi2x_WriteFirmGetState_t aioIob2Bi2x_WriteFirmGetState_orig = nullptr;
|
|
static aioNMgrIob2_Create_t aioNMgrIob2_Create_orig = nullptr;
|
|
|
|
/*
|
|
* variables
|
|
*/
|
|
|
|
AIO_IOB2_BI2X_TDJ *custom_node = nullptr;
|
|
AC_HNDLIF *acHndlif = nullptr;
|
|
AIO_NMGR_IOB2 *aioNmgrIob2 = nullptr;
|
|
|
|
/*
|
|
* implementations
|
|
*/
|
|
|
|
static AIO_IOB2_BI2X_TDJ* __fastcall aioIob2Bi2xTDJ_Create(AIO_NMGR_IOB2 *nmgr, int a2) {
|
|
if (!BI2X_PASSTHROUGH) {
|
|
custom_node = new AIO_IOB2_BI2X_TDJ;
|
|
memset(&custom_node->data, 0, sizeof(custom_node->data));
|
|
|
|
return custom_node;
|
|
} else {
|
|
|
|
// call original
|
|
return aioIob2Bi2xTDJ_Create_orig(nmgr, a2);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__GetDeviceStatus(AIO_IOB2_BI2X_TDJ *This,
|
|
AIO_IOB2_BI2X_TDJ__DEVSTATUS *status) {
|
|
|
|
// flush raw input
|
|
RI_MGR->devices_flush_output();
|
|
|
|
// check handle
|
|
if (This == custom_node) {
|
|
|
|
// clear input data
|
|
memset(status, 0x00, sizeof(AIO_IOB2_BI2X_TDJ__DEVSTATUS));
|
|
} else {
|
|
|
|
// get data from real device
|
|
AIO_IOB2_BI2X_TDJ__GetDeviceStatus_orig(This, status);
|
|
}
|
|
|
|
// get buttons
|
|
auto &buttons = get_buttons();
|
|
|
|
// control buttons
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test]))
|
|
status->buffer[4] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service]))
|
|
status->buffer[5] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech]))
|
|
status->buffer[6] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::VEFX]))
|
|
status->buffer[10] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Effect]))
|
|
status->buffer[11] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_Headphone]))
|
|
status->buffer[12] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_Headphone]))
|
|
status->buffer[13] = 0xFF;
|
|
|
|
// coin stock
|
|
status->buffer[22] += eamuse_coin_get_stock();
|
|
|
|
// player 1 buttons
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_Start]))
|
|
status->buffer[8] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_1]))
|
|
status->buffer[27] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_2]))
|
|
status->buffer[28] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_3]))
|
|
status->buffer[29] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_4]))
|
|
status->buffer[30] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_5]))
|
|
status->buffer[31] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_6]))
|
|
status->buffer[32] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P1_7]))
|
|
status->buffer[33] = 0xFF;
|
|
|
|
// player 2 buttons
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_Start]))
|
|
status->buffer[9] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_1]))
|
|
status->buffer[34] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_2]))
|
|
status->buffer[35] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_3]))
|
|
status->buffer[36] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_4]))
|
|
status->buffer[37] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_5]))
|
|
status->buffer[38] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_6]))
|
|
status->buffer[39] = 0xFF;
|
|
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::P2_7]))
|
|
status->buffer[40] = 0xFF;
|
|
|
|
// turntables
|
|
status->buffer[20] += get_tt(0, false);
|
|
status->buffer[21] += get_tt(1, false);
|
|
|
|
return;
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__IoReset(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int a2)
|
|
{
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__IoReset_orig(This, a2);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetWatchDogTimer(AIO_IOB2_BI2X_TDJ *This,
|
|
uint8_t a2)
|
|
{
|
|
if (This != custom_node) {
|
|
|
|
// comment this out if you want to disable the BI2X watchdog timer
|
|
return AIO_IOB2_BI2X_TDJ__SetWatchDogTimer_orig(This, a2);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__ControlCoinBlocker(AIO_IOB2_BI2X_TDJ *This,
|
|
int index, uint8_t state) {
|
|
|
|
// coin blocker is closed when state is zero
|
|
eamuse_coin_set_block(state == 0);
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__ControlCoinBlocker_orig(This, index, state);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__AddCounter(AIO_IOB2_BI2X_TDJ *This,
|
|
int a2, int a3)
|
|
{
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__AddCounter_orig(This, a2, a3);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetStartLamp(AIO_IOB2_BI2X_TDJ *This,
|
|
int player, uint8_t state)
|
|
{
|
|
auto &lights = get_lights();
|
|
|
|
if (player == 0) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::P1_Start], state ? 1.f : 0.f);
|
|
} else if (player == 1) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::P2_Start], state ? 1.f : 0.f);
|
|
}
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetStartLamp_orig(This, player, state);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp(AIO_IOB2_BI2X_TDJ *This,
|
|
uint8_t state)
|
|
{
|
|
auto &lights = get_lights();
|
|
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::VEFX], state ? 1.f : 0.f);
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp_orig(This, state);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp(AIO_IOB2_BI2X_TDJ *This,
|
|
uint8_t state)
|
|
{
|
|
auto &lights = get_lights();
|
|
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::Effect], state ? 1.f : 0.f);
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp_orig(This, state);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp(AIO_IOB2_BI2X_TDJ *This,
|
|
int player, int button, uint8_t state)
|
|
{
|
|
auto &lights = get_lights();
|
|
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::P1_1 + player * 7 + button], state ? 1.f : 0.f);
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp_orig(This, player, button, state);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetWooferLED(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint32_t color)
|
|
{
|
|
uint32_t col_r = (color & 0xFF0000) >> 16;
|
|
uint32_t col_g = (color & 0x00FF00) >> 8;
|
|
uint32_t col_b = (color & 0x0000FF) >> 0;
|
|
|
|
auto &lights = get_lights();
|
|
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::WooferR], col_r / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::WooferG], col_g / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::WooferB], col_b / 255.f);
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetWooferLED_orig(This, index, color);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetIccrLed(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint32_t color)
|
|
{
|
|
uint32_t col_r = (color & 0xFF0000) >> 16;
|
|
uint32_t col_g = (color & 0x00FF00) >> 8;
|
|
uint32_t col_b = (color & 0x0000FF) >> 0;
|
|
|
|
auto &lights = get_lights();
|
|
|
|
if (index == 0) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::ICCR_P1_R], col_r / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::ICCR_P1_G], col_g / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::ICCR_P1_B], col_b / 255.f);
|
|
} else if (index == 1) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::ICCR_P2_R], col_r / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::ICCR_P2_G], col_g / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::ICCR_P2_B], col_b / 255.f);
|
|
}
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetIccrLed_orig(This, index, color);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetTurnTableLed(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint32_t color)
|
|
{
|
|
uint32_t col_r = (color & 0xFF0000) >> 16;
|
|
uint32_t col_g = (color & 0x00FF00) >> 8;
|
|
uint32_t col_b = (color & 0x0000FF) >> 0;
|
|
|
|
auto &lights = get_lights();
|
|
|
|
if (index == 0) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P1_R], col_r / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P1_G], col_g / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P1_B], col_b / 255.f);
|
|
} else if (index == 1) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P2_R], col_r / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P2_G], col_g / 255.f);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P2_B], col_b / 255.f);
|
|
}
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetTurnTableLed_orig(This, index, color);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetTurnTableResist(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint8_t resistance)
|
|
{
|
|
auto &lights = get_lights();
|
|
|
|
if (index == 0) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P1_Resistance], resistance / 255.f);
|
|
} else if (index == 1) {
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[Lights::TT_P2_Resistance], resistance / 255.f);
|
|
}
|
|
|
|
if (This != custom_node) {
|
|
return AIO_IOB2_BI2X_TDJ__SetTurnTableResist_orig(This, index, resistance);
|
|
}
|
|
}
|
|
|
|
static void __fastcall AIO_IOB2_BI2X_TDJ__SetTapeLedData(AIO_IOB2_BI2X_TDJ *This,
|
|
unsigned int index, uint8_t *data)
|
|
{
|
|
/*
|
|
* index mapping
|
|
*
|
|
* 0 - stage left - 57 bytes - 19 colors
|
|
* 1 - stage right - 57 bytes - 19 colors
|
|
* 2 - cabinet left - 135 bytes - 45 colors
|
|
* 3 - cabinet right - 135 bytes - 45 colors
|
|
* 4 - control panel under - 63 bytes - 21 colors
|
|
* 5 - ceiling left - 162 bytes - 54 colors
|
|
* 6 - title left - 33 bytes - 11 colors
|
|
* 7 - title right - 33 bytes - 11 colors
|
|
* 8 - ceiling right - 162 bytes - 54 colors
|
|
* 9 - touch panel left - 51 bytes - 17 colors
|
|
* 10 - touch panel right - 51 bytes - 17 colors
|
|
* 11 - side panel left inner - 204 bytes - 68 colors
|
|
* 12 - side panel left outer - 204 bytes - 68 colors
|
|
* 13 - side panel left - 183 bytes - 61 colors
|
|
* 14 - side panel right outer - 204 bytes - 68 colors
|
|
* 15 - side panel right inner - 204 bytes - 68 colors
|
|
* 16 - side panel right - 183 bytes - 61 colors
|
|
*
|
|
* data is stored in RGB order, 3 bytes per color
|
|
*
|
|
* TODO: expose this data via API
|
|
*/
|
|
|
|
// data mapping
|
|
static struct TapeLedMapping {
|
|
size_t data_size;
|
|
int index_r, index_g, index_b;
|
|
|
|
TapeLedMapping(size_t data_size, int index_r, int index_g, int index_b)
|
|
: data_size(data_size), index_r(index_r), index_g(index_g), index_b(index_b) {}
|
|
|
|
} mapping[] = {
|
|
{ 19, Lights::StageLeftAvgR, Lights::StageLeftAvgG, Lights::StageLeftAvgB },
|
|
{ 19, Lights::StageRightAvgR, Lights::StageRightAvgG, Lights::StageRightAvgB },
|
|
{ 45, Lights::CabinetLeftAvgR, Lights::CabinetLeftAvgG, Lights::CabinetLeftAvgB },
|
|
{ 45, Lights::CabinetRightAvgR, Lights::CabinetRightAvgG, Lights::CabinetRightAvgB },
|
|
{ 21, Lights::ControlPanelUnderAvgR, Lights::ControlPanelUnderAvgG, Lights::ControlPanelUnderAvgB },
|
|
{ 54, Lights::CeilingLeftAvgR, Lights::CeilingLeftAvgG, Lights::CeilingLeftAvgB },
|
|
{ 11, Lights::TitleLeftAvgR, Lights::TitleLeftAvgG, Lights::TitleLeftAvgB },
|
|
{ 11, Lights::TitleRightAvgR, Lights::TitleRightAvgG, Lights::TitleRightAvgB },
|
|
{ 54, Lights::CeilingRightAvgR, Lights::CeilingRightAvgG, Lights::CeilingRightAvgB },
|
|
{ 17, Lights::TouchPanelLeftAvgR, Lights::TouchPanelLeftAvgG, Lights::TouchPanelLeftAvgB },
|
|
{ 17, Lights::TouchPanelRightAvgR, Lights::TouchPanelRightAvgG, Lights::TouchPanelRightAvgB },
|
|
{ 68, Lights::SidePanelLeftInnerAvgR, Lights::SidePanelLeftInnerAvgG, Lights::SidePanelLeftInnerAvgB },
|
|
{ 68, Lights::SidePanelLeftOuterAvgR, Lights::SidePanelLeftOuterAvgG, Lights::SidePanelLeftOuterAvgB },
|
|
{ 61, Lights::SidePanelLeftAvgR, Lights::SidePanelLeftAvgG, Lights::SidePanelLeftAvgB },
|
|
{ 68, Lights::SidePanelRightOuterAvgR, Lights::SidePanelRightOuterAvgG, Lights::SidePanelRightOuterAvgB },
|
|
{ 68, Lights::SidePanelRightInnerAvgR, Lights::SidePanelRightInnerAvgG, Lights::SidePanelRightInnerAvgB },
|
|
{ 61, Lights::SidePanelRightAvgR, Lights::SidePanelRightAvgG, Lights::SidePanelRightAvgB },
|
|
};
|
|
|
|
// check index bounds
|
|
if (tapeledutils::is_enabled() && index < std::size(mapping)) {
|
|
auto &map = mapping[index];
|
|
|
|
// pick a color to use
|
|
const auto rgb = tapeledutils::pick_color_from_led_tape(data, map.data_size);
|
|
|
|
// program the lights into API
|
|
auto &lights = get_lights();
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
|
}
|
|
|
|
if (This != custom_node) {
|
|
// send tape data to real device
|
|
return AIO_IOB2_BI2X_TDJ__SetTapeLedData_orig(This, index, data);
|
|
}
|
|
}
|
|
|
|
static AC_HNDLIF* __fastcall aioIob2Bi2X_OpenSciUsbCdc(uint8_t device_num) {
|
|
if (acHndlif == nullptr) {
|
|
acHndlif = new AC_HNDLIF;
|
|
memset(acHndlif->data, 0x0, sizeof(acHndlif->data));
|
|
}
|
|
log_info("bi2x_hook", "aioIob2Bi2x_OpenSciUsbCdc");
|
|
return acHndlif;
|
|
}
|
|
|
|
static void __fastcall AIO_NMGR_IOB_BeginManageStub(int64_t a1) {
|
|
log_info("bi2x_hook", "AIO_NMGR_IOB::BeginManage");
|
|
};
|
|
|
|
static AIO_NMGR_IOB2** __fastcall aioNMgrIob2_Create(AC_HNDLIF *a1, unsigned int a2) {
|
|
if (aioNmgrIob2 == nullptr) {
|
|
aioNmgrIob2 = new AIO_NMGR_IOB2;
|
|
memset(aioNmgrIob2, 0x0, sizeof(AIO_NMGR_IOB2));
|
|
aioNmgrIob2->pAIO_NMGR_IOB_BeginManage = AIO_NMGR_IOB_BeginManageStub;
|
|
}
|
|
log_info("bi2x_hook", "aioNMgrIob2_Create");
|
|
return &aioNmgrIob2;
|
|
}
|
|
|
|
static int64_t __fastcall aioIob2Bi2x_WriteFirmGetState(int64_t a1) {
|
|
log_info("bi2x_hook", "aioIob2Bi2x_WriteFirmGetState");
|
|
return 8;
|
|
}
|
|
|
|
void bi2x_hook_init() {
|
|
|
|
// avoid double init
|
|
static bool initialized = false;
|
|
if (initialized) {
|
|
return;
|
|
} else {
|
|
initialized = true;
|
|
}
|
|
|
|
// announce
|
|
log_info("bi2x_hook", "init");
|
|
|
|
// hook IOB2 video
|
|
const auto libaioIob2VideoDll = "libaio-iob2_video.dll";
|
|
detour::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xTDJ_Create",
|
|
aioIob2Bi2xTDJ_Create, &aioIob2Bi2xTDJ_Create_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?GetDeviceStatus@AIO_IOB2_BI2X_TDJ@@QEBAXAEAUDEVSTATUS@1@@Z",
|
|
AIO_IOB2_BI2X_TDJ__GetDeviceStatus, &AIO_IOB2_BI2X_TDJ__GetDeviceStatus_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?IoReset@AIO_IOB2_BI2X_TDJ@@QEAAXI@Z",
|
|
AIO_IOB2_BI2X_TDJ__IoReset, &AIO_IOB2_BI2X_TDJ__IoReset_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetWatchDogTimer@AIO_IOB2_BI2X_TDJ@@QEAAXE@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetWatchDogTimer, &AIO_IOB2_BI2X_TDJ__SetWatchDogTimer_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?ControlCoinBlocker@AIO_IOB2_BI2X_TDJ@@QEAAXI_N@Z",
|
|
AIO_IOB2_BI2X_TDJ__ControlCoinBlocker, &AIO_IOB2_BI2X_TDJ__ControlCoinBlocker_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?AddCounter@AIO_IOB2_BI2X_TDJ@@QEAAXII@Z",
|
|
AIO_IOB2_BI2X_TDJ__AddCounter, &AIO_IOB2_BI2X_TDJ__AddCounter_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetStartLamp@AIO_IOB2_BI2X_TDJ@@QEAAXI_N@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetStartLamp, &AIO_IOB2_BI2X_TDJ__SetStartLamp_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetVefxButtonLamp@AIO_IOB2_BI2X_TDJ@@QEAAX_N@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp, &AIO_IOB2_BI2X_TDJ__SetVefxButtonLamp_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetEffectButtonLamp@AIO_IOB2_BI2X_TDJ@@QEAAX_N@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp, &AIO_IOB2_BI2X_TDJ__SetEffectButtonLamp_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetPlayerButtonLamp@AIO_IOB2_BI2X_TDJ@@QEAAXII_N@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp, &AIO_IOB2_BI2X_TDJ__SetPlayerButtonLamp_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetWooferLed@AIO_IOB2_BI2X_TDJ@@QEAAXI@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetWooferLED, &AIO_IOB2_BI2X_TDJ__SetWooferLED_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetIccrLed@AIO_IOB2_BI2X_TDJ@@QEAAXII@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetIccrLed, &AIO_IOB2_BI2X_TDJ__SetIccrLed_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetTurnTableLed@AIO_IOB2_BI2X_TDJ@@QEAAXII@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetTurnTableLed, &AIO_IOB2_BI2X_TDJ__SetTurnTableLed_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetTurnTableResist@AIO_IOB2_BI2X_TDJ@@QEAAXIE@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetTurnTableResist, &AIO_IOB2_BI2X_TDJ__SetTurnTableResist_orig);
|
|
detour::trampoline_try(libaioIob2VideoDll, "?SetTapeLedData@AIO_IOB2_BI2X_TDJ@@QEAAXIPEBX@Z",
|
|
AIO_IOB2_BI2X_TDJ__SetTapeLedData, &AIO_IOB2_BI2X_TDJ__SetTapeLedData_orig);
|
|
|
|
// hook IOB
|
|
const auto libaioIobDll = "libaio-iob.dll";
|
|
detour::trampoline_try(libaioIobDll, "aioIob2Bi2x_OpenSciUsbCdc",
|
|
aioIob2Bi2X_OpenSciUsbCdc, &aioIob2Bi2x_OpenSciUsbCdc_orig);
|
|
detour::trampoline_try(libaioIobDll, "aioIob2Bi2x_WriteFirmGetState",
|
|
aioIob2Bi2x_WriteFirmGetState, &aioIob2Bi2x_WriteFirmGetState_orig);
|
|
detour::trampoline_try(libaioIobDll, "aioNMgrIob2_Create",
|
|
aioNMgrIob2_Create, &aioNMgrIob2_Create_orig);
|
|
}
|
|
}
|