Update to spice2x-26-02-17 (pre-apply)
> broken commit
This commit is contained in:
+155
-44
@@ -20,6 +20,7 @@
|
||||
#include "hooks/sleephook.h"
|
||||
#include "launcher/options.h"
|
||||
#include "touch/touch.h"
|
||||
#include "misc/nativetouchhook.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "util/detour.h"
|
||||
@@ -28,6 +29,8 @@
|
||||
#include "util/libutils.h"
|
||||
#include "util/memutils.h"
|
||||
#include "util/sigscan.h"
|
||||
#include "util/socd_cleaner.h"
|
||||
#include "util/time.h"
|
||||
#include "util/utils.h"
|
||||
#include "launcher/signal.h"
|
||||
|
||||
@@ -53,7 +56,7 @@ namespace games::iidx {
|
||||
|
||||
// settings
|
||||
bool FLIP_CAMS = false;
|
||||
bool DISABLE_CAMS = false;
|
||||
std::optional<bool> DISABLE_CAMS;
|
||||
bool TDJ_CAMERA = false;
|
||||
bool TDJ_CAMERA_PREFER_16_9 = true;
|
||||
bool TDJ_MODE = false;
|
||||
@@ -78,6 +81,11 @@ namespace games::iidx {
|
||||
char IIDXIO_LED_TICKER[10] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\x00'};
|
||||
bool IIDXIO_LED_TICKER_READONLY = false;
|
||||
std::mutex IIDX_LED_TICKER_LOCK;
|
||||
bool IIDX_TDJ_MONITOR_WARNING = false;
|
||||
iidx_aio_emulation_state CURRENT_IO_EMULATION_STATE = iidx_aio_emulation_state::unknown;
|
||||
|
||||
// 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" },
|
||||
@@ -235,6 +243,9 @@ namespace games::iidx {
|
||||
} else if (data.find(" W:touch: missing trigger:") != std::string::npos) {
|
||||
out.clear();
|
||||
return true;
|
||||
} else if (data.find(" W:CTexture: no such texture: id 0") != std::string::npos) {
|
||||
out.clear();
|
||||
return true;
|
||||
} else if (data.find("SuperstepSound: Audio device is not available") != std::string::npos) {
|
||||
deferredlogs::defer_error_messages(deferredlogs::SUPERSTEP_SOUND_ERROR_MESSAGE);
|
||||
return false;
|
||||
@@ -243,6 +254,8 @@ namespace games::iidx {
|
||||
}
|
||||
}
|
||||
|
||||
#if SPICE64
|
||||
|
||||
typedef void* (*aioIob2Bi2x_CreateWriteFirmContext_t)(unsigned int, int);
|
||||
static aioIob2Bi2x_CreateWriteFirmContext_t aioIob2Bi2x_CreateWriteFirmContext_orig = nullptr;
|
||||
|
||||
@@ -261,6 +274,8 @@ namespace games::iidx {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
IIDXGame::IIDXGame() : Game("Beatmania IIDX") {
|
||||
logger::hook_add(log_hook, this);
|
||||
}
|
||||
@@ -307,13 +322,16 @@ 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());
|
||||
}
|
||||
|
||||
#if SPICE64
|
||||
|
||||
// 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";
|
||||
@@ -329,16 +347,13 @@ namespace games::iidx {
|
||||
// need to hook `avs2-core.dll` so AVS win32fs operations go through rom hook
|
||||
devicehook_init(avs::core::DLL_INSTANCE);
|
||||
|
||||
if (!NATIVE_TOUCH) {
|
||||
if (NATIVE_TOUCH) {
|
||||
nativetouchhook::hook(avs::game::DLL_INSTANCE);
|
||||
} else {
|
||||
wintouchemu::FORCE = true;
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends("beatmania IIDX", "main", avs::game::DLL_INSTANCE);
|
||||
}
|
||||
|
||||
// prevent crash on TDJ mode without correct DLL
|
||||
if (!GetModuleHandle("nvcuda.dll")) {
|
||||
DISABLE_CAMS = true;
|
||||
}
|
||||
}
|
||||
|
||||
// insert BI2X hooks
|
||||
@@ -378,6 +393,8 @@ namespace games::iidx {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (hooks::audio::ENABLED) {
|
||||
apply_audio_hacks();
|
||||
} else {
|
||||
@@ -399,38 +416,45 @@ namespace games::iidx {
|
||||
"RegQueryValueExA", RegQueryValueExA_hook, avs::game::DLL_INSTANCE);
|
||||
|
||||
// check if cam hook should be enabled
|
||||
if (!DISABLE_CAMS) {
|
||||
if (!DISABLE_CAMS.has_value()) {
|
||||
log_fatal("iidx", "assertion failure - DISABLE_CAMS not set during attach");
|
||||
}
|
||||
if (!DISABLE_CAMS.value()) {
|
||||
init_legacy_camera_hook(FLIP_CAMS);
|
||||
}
|
||||
|
||||
// init cfgmgr32 hooks
|
||||
cfgmgr32hook_init(avs::game::DLL_INSTANCE);
|
||||
|
||||
// report common errors on iidx31 and above
|
||||
if (avs::game::is_ext(2023091500, MAXINT) && GRAPHICS_9_ON_12_STATE == DX9ON12_FORCE_ON) {
|
||||
deferredlogs::defer_error_messages({
|
||||
"common incompatibility with DX 9on12 + IIDX 31 and above",
|
||||
" IIDX31+ is known to be incompatible with DX 9on12, leading to blank screen or crashes"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void IIDXGame::pre_attach() {
|
||||
Game::pre_attach();
|
||||
auto options = games::get_options(eamuse_get_game());
|
||||
|
||||
// environment variables must be set before the DLL is loaded as the VC++ runtime copies all
|
||||
// environment variables at startup
|
||||
if (DISABLE_CAMS) {
|
||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||
}
|
||||
|
||||
if (SCREEN_MODE.has_value()) {
|
||||
log_misc("iidx", "SCREEN_MODE env var set to {}", SCREEN_MODE.value().c_str());
|
||||
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
|
||||
}
|
||||
|
||||
// check for cab camera access for the second time (first time was in launcher.cpp)
|
||||
// this time, we are inside -iidx module hook, which means the user is likely NOT on a cab
|
||||
// therefore, start with cams OFF by default, and allow user to forcibly override to ON
|
||||
if (!games::iidx::DISABLE_CAMS.has_value()) {
|
||||
games::iidx::DISABLE_CAMS = true;
|
||||
if (options->at(launcher::Options::IIDXCabCamAccess).is_active() &&
|
||||
options->at(launcher::Options::IIDXCabCamAccess).value_text() == "on") {
|
||||
games::iidx::DISABLE_CAMS = false;
|
||||
}
|
||||
if (games::iidx::DISABLE_CAMS.value()) {
|
||||
log_misc("iidx", "CONNECT_CAMERA env var set to 0");
|
||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||
}
|
||||
}
|
||||
|
||||
// windowed subscreen, enabled by default, unless turned off by user
|
||||
auto options = games::get_options(eamuse_get_game());
|
||||
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool()) {
|
||||
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool() && TDJ_MODE) {
|
||||
GRAPHICS_IIDX_WSUB = true;
|
||||
}
|
||||
|
||||
@@ -440,7 +464,7 @@ namespace games::iidx {
|
||||
|
||||
// check bad model name
|
||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDJ")) {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"iidx",
|
||||
"BAD MODEL NAME ERROR\n\n\n"
|
||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n"
|
||||
@@ -449,7 +473,7 @@ namespace games::iidx {
|
||||
"!!! please do the following instead: !!!\n"
|
||||
"!!! !!!\n"
|
||||
"!!! Revert your changes to XML file so it says !!!\n"
|
||||
"!!! <model __type=\"str\">LDJ</model> !!!\n"
|
||||
"!!! <model __type=\"str\">LDJ</model> !!!\n"
|
||||
"!!! !!!\n"
|
||||
"!!! In SpiceCfg, enable 'IIDX TDJ Mode' or provide -iidxtdj flag !!!\n"
|
||||
"!!! in command line !!!\n"
|
||||
@@ -458,6 +482,43 @@ namespace games::iidx {
|
||||
"!!! !!!\n"
|
||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n\n\n"
|
||||
);
|
||||
|
||||
log_fatal("iidx", "BAD MODEL NAME ERROR - TDJ specified, must be LDJ instead");
|
||||
}
|
||||
|
||||
// check -monitor + TDJ mode
|
||||
if (!GRAPHICS_WINDOWED && D3D9_ADAPTER.has_value() && TDJ_MODE) {
|
||||
IIDX_TDJ_MONITOR_WARNING = true;
|
||||
log_warning(
|
||||
"iidx",
|
||||
"\n\n!!! using -monitor option with TDJ is NOT recommended due to known !!!\n"
|
||||
"!!! compatibility issues with the game !!!\n"
|
||||
"!!! !!!\n"
|
||||
"!!! * game may launch in wrong resolution or refresh rate !!!\n"
|
||||
"!!! * touch / mouse input may stop working in subscreen / overlay !!!\n"
|
||||
"!!! !!!\n"
|
||||
"!!! recommendation is to NOT use -monitor and instead set the !!!\n"
|
||||
"!!! primary monitor in Windows settings before launching the game !!!\n\n"
|
||||
);
|
||||
|
||||
deferredlogs::defer_error_messages({
|
||||
"-monitor option is NOT recommended when running with TDJ mode",
|
||||
" due to known compatibility issues with the game:",
|
||||
" * game may launch in wrong resolution or refresh rate",
|
||||
" * touch / mouse input may stop working in subscreen / overlay",
|
||||
" recommended fix is to NOT use -monitor and instead set the primary",
|
||||
" monitor in Windows settings before launching the game"
|
||||
});
|
||||
}
|
||||
|
||||
// socd
|
||||
socd::ALGORITHM = socd::SocdAlgorithm::Neutral;
|
||||
if (options->at(launcher::Options::IIDXDigitalTTSocd).is_active()) {
|
||||
if (options->at(launcher::Options::IIDXDigitalTTSocd).value_text() == "last") {
|
||||
socd::ALGORITHM = socd::SocdAlgorithm::PreferRecent;
|
||||
} else if (options->at(launcher::Options::IIDXDigitalTTSocd).value_text() == "first") {
|
||||
socd::ALGORITHM = socd::SocdAlgorithm::PreferFirst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,13 +743,12 @@ namespace games::iidx {
|
||||
bool ttpm_alt = GameAPI::Buttons::getState(RI_MGR, buttons.at(
|
||||
player != 0 ? Buttons::P2_TTPlusMinusAlt : Buttons::P1_TTPlusMinusAlt));
|
||||
|
||||
// TT+
|
||||
if (ttp)
|
||||
const auto tt_socd = socd::socd_clean(player, ttm, ttp, get_performance_milliseconds());
|
||||
if (tt_socd == socd::SocdCW) {
|
||||
IIDXIO_TT_STATE[player] += change;
|
||||
|
||||
// TT-
|
||||
if (ttm)
|
||||
} else if (tt_socd == socd::SocdCCW) {
|
||||
IIDXIO_TT_STATE[player] -= change;
|
||||
}
|
||||
|
||||
// TT+/-
|
||||
bool ttpm_rising_edge = !IIDXIO_TT_PRESSED[player] && ttpm;
|
||||
@@ -783,7 +843,15 @@ namespace games::iidx {
|
||||
// <=24 : 32-bit only
|
||||
// 25-26: has neither (no patch needed - WASAPI Exclusive by default)
|
||||
// 27-30: has both (envvar will be respected, ASIO or WASAPI)
|
||||
// 31+: only has XONAR (ASIO by default, signature patch can be used to force WASAPI - for now)
|
||||
// 31-32: only has XONAR (ASIO by default, signature patch can be used to force WASAPI - for now)
|
||||
// 33 : early versions only have XONAR, but later datecodes have both; SOUND_OUTPUT_DEVICE
|
||||
// returned and it works again when set as env var
|
||||
|
||||
log_info(
|
||||
"iidx",
|
||||
"has_SOUND_OUTPUT_DEVICE: {}, has_XONAR_SOUND_CARD: {}",
|
||||
(has_SOUND_OUTPUT_DEVICE != 0),
|
||||
(has_XONAR_SOUND_CARD != 0));
|
||||
|
||||
if (!has_SOUND_OUTPUT_DEVICE && !has_XONAR_SOUND_CARD) {
|
||||
// iidx 25-26
|
||||
@@ -791,16 +859,10 @@ namespace games::iidx {
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_SOUND_OUTPUT_DEVICE && has_XONAR_SOUND_CARD) {
|
||||
// iidx 27-30
|
||||
log_info("iidx", "This game accepts SOUND_OUTPUT_DEVICE environment variable");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("iidx", "This game supports ASIO but does not accept SOUND_OUTPUT_DEVICE environment variable");
|
||||
|
||||
// patch game to force wasapi
|
||||
if (SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
|
||||
// if the game doesn't accept SOUND_OUTPUT_DEVICE, patch game to force wasapi
|
||||
if (!has_SOUND_OUTPUT_DEVICE &&
|
||||
SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() &&
|
||||
SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
|
||||
intptr_t result = replace_pattern(
|
||||
avs::game::DLL_INSTANCE,
|
||||
"FF5008E8??????FF83780803740D",
|
||||
@@ -818,8 +880,6 @@ namespace games::iidx {
|
||||
"Successfully forced WASAPI as audio engine using signature matching @ 0x{:x}.",
|
||||
result);
|
||||
}
|
||||
} else {
|
||||
log_info("iidx", "Not applying force wasapi patch; game will use ASIO");
|
||||
}
|
||||
|
||||
// patch iidx32+ for asio compatibility
|
||||
@@ -827,7 +887,8 @@ namespace games::iidx {
|
||||
// the patch is only really needed for (some) non-XONAR devices but since people sometimes disguise
|
||||
// other devices as a XONAR, don't check for the exact string (common ASIO workaround for INF)
|
||||
if (avs::game::is_ext(2024090100, MAXINT) &&
|
||||
!(SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi")) {
|
||||
!(SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() &&
|
||||
SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi")) {
|
||||
|
||||
// in iidx32 final:
|
||||
// ff 50 08 call QWORD PTR [rax+0x8] ; ASIO instance AddRef
|
||||
@@ -858,4 +919,54 @@ 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;
|
||||
}
|
||||
|
||||
CURRENT_IO_EMULATION_STATE = state;
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user