iidx: detect ldj/tdj I/O mismatch (#470)

## Link to GitHub Issue, if one exists
#345 

## Description of change
For IIDX31+, detect if BI2A or BI2X I/O emulation becomes active, and
see if there is a mismatch between the -iidxtdj setting.

Right now a mismatch results in warning in log + deferred error log, but
in the future we could turn this into a fatal error and crash the game
to make it more obvious.

## Testing
Tested 4 combinations:

1. DLL in LDJ mode + -iidxtdj off (pass)
2. DLL in LDJ mode + -iidxtdj on (error)
3. DLL in TDJ mode + -iidxtdj off (error)
4. DLL in TDJ mode + -iidxtdj on (pass)
This commit is contained in:
bicarus-dev
2025-12-22 18:52:37 -08:00
committed by GitHub
parent 462a07680b
commit 4c8d4ebab6
5 changed files with 68 additions and 5 deletions
+3 -3
View File
@@ -195,11 +195,11 @@ bool games::iidx::IIDXFMSerialHandle::open(LPCWSTR lpFileName) {
return false;
}
log_info("iidx", "Opened COM2 (FM DEVICE)");
log_info("iidx", "Opened COM2 (FM DEVICE / bi2a)");
games::iidx::update_io_emulation_state(games::iidx::iidx_aio_emulation_state::bi2a_com2);
// ACIO device
acio_emu.add_device(new FMSerialDevice());
return true;
}
@@ -240,7 +240,7 @@ int games::iidx::IIDXFMSerialHandle::device_io(DWORD dwIoControlCode, LPVOID lpI
}
bool games::iidx::IIDXFMSerialHandle::close() {
log_info("iidx", "Closed COM2 (FM DEVICE)");
log_info("iidx", "Closed COM2 (FM DEVICE / bi2a)");
return true;
}
+5
View File
@@ -120,6 +120,11 @@ namespace games::iidx {
static AIO_IOB2_BI2X_TDJ* __fastcall aioIob2Bi2xTDJ_Create(AIO_NMGR_IOB2 *nmgr, int a2) {
if (!BI2X_PASSTHROUGH) {
log_info("bi2x_hook", "aioIob2Bi2xTDJ_Create called (TDJ I/O emulation active)");
games::iidx::update_io_emulation_state(
games::iidx::iidx_aio_emulation_state::bi2x_hook);
custom_node = new AIO_IOB2_BI2X_TDJ;
memset(&custom_node->data, 0, sizeof(custom_node->data));
+53 -1
View File
@@ -80,6 +80,9 @@ namespace games::iidx {
bool IIDXIO_LED_TICKER_READONLY = false;
std::mutex IIDX_LED_TICKER_LOCK;
// io
static bool HAS_LIBAIO; // this is how we detect iidx27+
tapeledutils::tape_led TAPELED_MAPPING[IIDX_TAPELED_TOTAL] = {
{ 19, Lights::StageLeftAvgR, Lights::StageLeftAvgG, Lights::StageLeftAvgB, "Stage Left" },
{ 19, Lights::StageRightAvgR, Lights::StageRightAvgG, Lights::StageRightAvgB, "Stage Right" },
@@ -311,13 +314,14 @@ namespace games::iidx {
memcpy(settings2.interface_detail, interface_detail2, sizeof(interface_detail2));
setupapihook_add(settings2);
// IIDX 25-27 BIO2 BI2A input device
// IIDX 25+ BIO2 BI2A input device
devicehook_add(new IIDXFMSerialHandle());
}
// check for new I/O DLL
auto aio = libutils::try_library("libaio.dll");
if (aio != nullptr) {
HAS_LIBAIO = true;
// check TDJ mode
TDJ_MODE |= fileutils::text_read("C:\\000rom.txt") == "TDJ-JA";
@@ -895,4 +899,52 @@ namespace games::iidx {
#endif
}
void update_io_emulation_state(iidx_aio_emulation_state state) {
// <iidx27, don't care, since tdj wasn't a thing before
// this is also how we detect that iidx module is attached
if (!HAS_LIBAIO) {
return;
}
// in iidx27-30, most DLL types can handle both, caching things in nvram and possibly end
// up with wrong i/o (temporarily until nvram is initialized again)
// to avoid false positives, only do this for iidx31+, since we know for sure that iidx31
// has a clean 010/012 split
if (avs::game::is_ext(0, 2023101000)) {
return;
}
// log_warning below could be turned into log_fatal in the future once we gain confidence
// that this isn't triggering when it's not supposed to
if (state == iidx_aio_emulation_state::bi2a_com2 && TDJ_MODE) {
deferredlogs::defer_error_messages({
"IIDX I/O mode conflict",
" game is currently configured to use LDJ I/O;",
" however, you turned on IIDX TDJ Mode (-iidxtdj)",
" two options to fix this:",
" For TDJ mode (120Hz): import patches and enable Force TDJ Mode patch",
" For LDJ mode (60Hz): turn off IIDX TDJ Mode option",
});
log_warning(
"iidx",
"game is using LDJ I/O but spice TDJ mode is turned on! "
"enable Force TDJ I/O patch, OR turn off -iidxtdj");
} else if (state == iidx_aio_emulation_state::bi2x_hook && !TDJ_MODE) {
deferredlogs::defer_error_messages({
"IIDX I/O mode conflict",
" game is currently configured to use TDJ I/O;",
" however, you turned off IIDX TDJ Mode (-iidxtdj)",
" two options to fix this:",
" For TDJ mode (120Hz): turn on IIDX TDJ Mode option",
" For LDJ mode (60Hz): import patches and enable Force LDJ Mode patch",
});
log_warning(
"iidx",
"game is using TDJ I/O but spice TDJ mode is turned off! "
"turn on -iidxtdj, OR enable Force LDJ I/O patch");
} else {
log_misc("iidx", "i/o mode validation passed");
}
}
}
+6
View File
@@ -62,4 +62,10 @@ namespace games::iidx {
const char* get_16seg();
bool is_tdj_fhd();
void apply_audio_hacks();
enum class iidx_aio_emulation_state {
bi2a_com2,
bi2x_hook
};
void update_io_emulation_state(iidx_aio_emulation_state state);
}