Update to spice2x-25-04-25 (pre-apply)

> broken commit
This commit is contained in:
[ ]
2025-05-07 00:25:31 +09:00
parent 04dee88276
commit c94de456b5
543 changed files with 78491 additions and 91698 deletions
+16 -23
View File
@@ -10,6 +10,8 @@
#include "launcher/options.h"
#include "io.h"
#include "games/sdvx/sdvx.h"
#include "util/tapeled.h"
#include "acioemu/icca.h"
namespace games::sdvx {
constexpr bool BI2X_PASSTHROUGH = false;
@@ -293,12 +295,9 @@ namespace games::sdvx {
static struct TapeLedMapping {
size_t data_size;
int index_r, index_g, index_b;
float avg_mult;
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) {
avg_mult = 1.f / (data_size * 255);
}
: data_size(data_size), index_r(index_r), index_g(index_g), index_b(index_b) {}
} mapping[] = {
{ 74, Lights::TITLE_AVG_R, Lights::TITLE_AVG_G, Lights::TITLE_AVG_B },
@@ -314,32 +313,20 @@ namespace games::sdvx {
};
// check index bounds
if (index < std::size(mapping)) {
if (tapeledutils::is_enabled() && index < std::size(mapping)) {
auto &map = mapping[index];
// calculate average color
size_t avg_ri = 0;
size_t avg_gi = 0;
size_t avg_bi = 0;
for (size_t i = 0; i < map.data_size; i++) {
auto color = &data[i * 3];
avg_ri += color[0];
avg_gi += color[1];
avg_bi += color[2];
}
float avg_r = avg_ri * map.avg_mult;
float avg_g = avg_gi * map.avg_mult;
float avg_b = avg_bi * map.avg_mult;
// pick a color to use
const auto rgb = tapeledutils::pick_color_from_led_tape(data, map.data_size);
// set average color
// program the lights into API
auto &lights = get_lights();
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], avg_r);
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], avg_g);
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], avg_b);
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_UFC__SetTapeLedData_orig(This, index, data);
}
@@ -366,6 +353,12 @@ namespace games::sdvx {
}
log_info("bi2x_hook", "aioNMgrIob2_Create");
BI2X_INITIALIZED = true;
// enable hack to make PIN pad work for KFC in BI2X mode
// this explicit check in the I/O init path is necessary
// (as opposed to just doing a check for "isValkyrieCabMode?")
// because there are hex edits that allow you to use legacy (KFC/BIO2) IO while in Valk mode
acioemu::ICCA_DEVICE_HACK = true;
return &aioNmgrIob2;
}
+14
View File
@@ -29,6 +29,20 @@ std::vector<Button> &games::sdvx::get_buttons() {
return buttons;
}
std::string games::sdvx::get_buttons_help() {
// keep to max 100 characters wide
return
" Start\n"
"\n"
" VOL-L VOL_R\n"
"\n"
" BT-A BT-B BT-C BT-D\n"
" FX-L FX-R \n"
"\n"
"For controllers, use Analog tab for knobs."
;
}
std::vector<Analog> &games::sdvx::get_analogs() {
static std::vector<Analog> analogs;
+1
View File
@@ -110,6 +110,7 @@ namespace games::sdvx {
// getters
std::vector<Button> &get_buttons();
std::string get_buttons_help();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}
+82 -19
View File
@@ -8,8 +8,10 @@
#include "hooks/graphics/graphics.h"
#include "hooks/devicehook.h"
#include "hooks/libraryhook.h"
#include "hooks/graphics/nvapi_hook.h"
#include "hooks/powrprof.h"
#include "hooks/sleephook.h"
#include "hooks/winuser.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/logging.h"
@@ -21,6 +23,7 @@
#include "camera.h"
#include "io.h"
#include "acioemu/handle.h"
#include "cfg/configurator.h"
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
@@ -40,6 +43,7 @@ namespace games::sdvx {
bool NATIVETOUCH = false;
uint8_t DIGITAL_KNOB_SENS = 16;
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
bool ENABLE_COM_PORT_SCAN_HOOK = false;
std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt;
std::optional<std::string> ASIO_DRIVER = std::nullopt;
@@ -66,6 +70,7 @@ namespace games::sdvx {
static LONG WINAPI RegOpenKeyExA_hook(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired,
PHKEY phkResult)
{
// ASIO hook
if (lpSubKey != nullptr && phkResult != nullptr) {
if (hKey == PARENT_ASIO_REG_HANDLE &&
ASIO_DRIVER.has_value() &&
@@ -74,12 +79,36 @@ namespace games::sdvx {
*phkResult = DEVICE_ASIO_REG_HANDLE;
log_info("sdvx::asio", "replacing '{}' with '{}'", lpSubKey, ASIO_DRIVER.value());
return RegOpenKeyExA_orig(real_asio_reg_handle, ASIO_DRIVER.value().c_str(), ulOptions, samDesired,
const auto result = RegOpenKeyExA_orig(
real_asio_reg_handle,
ASIO_DRIVER.value().c_str(),
ulOptions,
samDesired,
&real_asio_device_reg_handle);
if (result != ERROR_SUCCESS) {
log_warning(
"sdvx::asio",
"failed to open registry subkey '{}', error=0x{:x}",
ASIO_DRIVER.value().c_str(), result);
log_warning(
"sdvx::asio",
"due to improper ASIO setting, game will likely fall back to WASAPI; double check -sdvxasio and the registry",
ASIO_DRIVER.value().c_str(), result);
}
return result;
}
}
// COM hook
if (ENABLE_COM_PORT_SCAN_HOOK &&
lpSubKey != nullptr && phkResult != nullptr &&
_stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) {
log_info("sdvx::io", "failing HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
return 2; //ERROR_FILE_NOT_FOUND
}
return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}
@@ -111,9 +140,9 @@ namespace games::sdvx {
log_info("sdvx::asio", "RegQueryValueExA({}, \"{}\")", fmt::ptr((void *) hKey), lpValueName);
if (_stricmp(lpValueName, "Description") == 0) {
// sdvx does a comparison against "XONAR SOUND CARD(64)"
// otherwise you end up with this error:
// M:BMSoundLib: ASIODriver: No such driver: XONAR SOUND CARD(64)
// sdvx does a comparison against hardcoded string "XONAR SOUND CARD(64)" (same as iidx31)
// so what's in the registry must be overridden with "XONAR SOUND CARD(64)"
// otherwise you end up with this error: M:BMSoundLib: ASIODriver: No such driver
memcpy(lpData, ORIGINAL_ASIO_DEVICE_NAME, strlen(ORIGINAL_ASIO_DEVICE_NAME) + 1);
return ERROR_SUCCESS;
@@ -144,7 +173,7 @@ namespace games::sdvx {
}
#ifdef SPICE64
static bool sdvx5_spam_remover(void *user, const std::string &data, logger::Style style, std::string &out) {
static bool sdvx64_spam_remover(void *user, const std::string &data, logger::Style style, std::string &out) {
if (data.empty() || data[0] != '[') {
return false;
}
@@ -176,6 +205,11 @@ namespace games::sdvx {
out = "";
return true;
}
// M:AppConfig: [env/APPDATA]=C:\Users\username\AppData\Roaming
if (data.find("M:AppConfig: [env/") != std::string::npos) {
out = "";
return true;
}
return false;
}
@@ -223,6 +257,25 @@ namespace games::sdvx {
}
#endif
void SDVXGame::pre_attach() {
// for whatever reason, sdvx latches onto cards for much longer than other games
// needed because the game waits forever on the game over screen until a card is not detected
AUTO_INSERT_CARD_COOLDOWN = 15.f;
// check bad model name
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("UFC")) {
log_fatal(
"sdvx",
"BAD MODEL NAME ERROR\n\n\n"
"!!! model name set to UFC, this is WRONG and will break your game !!!\n"
"!!! !!!\n"
"!!! If you are trying to boot Valkyrie Model, !!!\n"
"!!! change <spec> from F to G. !!!\n"
"!!! !!!\n"
"!!! model name set to UFC, this is WRONG and will break your game !!!\n\n\n"
);
}
}
void SDVXGame::attach() {
Game::attach();
@@ -260,14 +313,20 @@ namespace games::sdvx {
// enable 9on12 for AMD
if (!libutils::try_library("nvapi64.dll")) {
log_info("sdvx", "nvapi64.dll not found, force enabling 9on12");
GRAPHICS_9_ON_12 = true;
log_info(
"sdvx",
"nvapi64.dll not found; for non-NVIDIA GPUs, requesting 9on12 to be enabled");
GRAPHICS_9_ON_12_REQUESTED_BY_GAME = true;
} else {
// don't let nvapi mess with display settings
nvapi_hook::initialize(avs::game::DLL_INSTANCE);
}
// check for Valkyrie cabinet mode
if (isValkyrieCabinetMode) {
// hook touch window
if (!NATIVETOUCH) {
// in windowed mode, game can accept mouse input on the second screen
if (!NATIVETOUCH && !GRAPHICS_WINDOWED) {
wintouchemu::FORCE = true;
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook_title_ends(
@@ -282,10 +341,13 @@ namespace games::sdvx {
// add card readers
devicehook_init(aio);
devicehook_add(new acioemu::ACIOHandle(L"COM1"));
} else {
// don't let nvapi mess with display settings (force failure)
libraryhook_hook_proc("nvapi_QueryInterface", static_cast<void *>(nullptr));
libraryhook_enable(avs::game::DLL_INSTANCE);
// this is needed because on some newer versions of SDVX6, soundvoltex.dll will open
// HKLM\HARDWARE\DEVICEMAP\SERIALCOMM, go through some of the keys, and depending on
// what is present, pick a port other than COM1 (seemingly the highest port
// available). We want the game to pick COM1 still, so a workaround is needed to
// fool the game.
ENABLE_COM_PORT_SCAN_HOOK = true;
}
}
#endif
@@ -304,6 +366,7 @@ namespace games::sdvx {
#ifdef SPICE64
powrprof_hook_init(avs::game::DLL_INSTANCE);
winuser_hook_init(avs::game::DLL_INSTANCE);
// hook camera
if (!DISABLECAMS) {
@@ -316,11 +379,11 @@ namespace games::sdvx {
"418D480484C074218D51FD",
"????????????9090??????",
0, 0)) {
log_warning("sdvx", "failed to insert camera error fix");
log_info("sdvx", "did not find matching signature for camera error patch");
}
// remove log spam
logger::hook_add(sdvx5_spam_remover, nullptr);
logger::hook_add(sdvx64_spam_remover, nullptr);
#endif
}
@@ -366,7 +429,7 @@ namespace games::sdvx {
// calculate target RVA
auto volume_set_rva = libutils::offset2rva(MODULE_PATH / avs::game::DLL_NAME, rva);
if (volume_set_rva == -1) {
log_warning("sdvx", "failed to insert set volume hook (convert rva {})", rva);
log_info("sdvx", "could not apply volume hook patch (convert rva {})", rva);
break;
}
@@ -374,7 +437,7 @@ namespace games::sdvx {
auto *volume_set_ptr = reinterpret_cast<uint16_t *>(
reinterpret_cast<intptr_t>(avs::game::DLL_INSTANCE) + volume_set_rva);
if (volume_set_ptr[0] != 0x8B48) {
log_warning("sdvx", "failed to insert set volume hook (invalid target)");
log_info("sdvx", "could not apply volume hook patch (invalid target)", rva);
break;
}
@@ -384,7 +447,7 @@ namespace games::sdvx {
volume_set_hook,
&volume_set_orig))
{
log_warning("sdvx", "failed to insert set volume hook (insert trampoline)");
log_info("sdvx", "could not apply volume hook patch (insert trampoline)", rva);
}
// success
@@ -395,7 +458,7 @@ namespace games::sdvx {
// check if version not found
if (!volume_hook_found) {
log_warning("sdvx", "volume hook unavailable for this game version");
log_info("sdvx", "volume hook unavailable for this game version");
// set volumes to sdvx 4 defaults
auto &lights = games::sdvx::get_lights();
+5 -1
View File
@@ -2,6 +2,7 @@
#pragma once
#include <optional>
#include <cstdint>
#include "games/game.h"
@@ -10,7 +11,9 @@ namespace games::sdvx {
enum SdvxOverlayPosition {
SDVX_OVERLAY_TOP,
SDVX_OVERLAY_MIDDLE,
SDVX_OVERLAY_BOTTOM
SDVX_OVERLAY_BOTTOM,
SDVX_OVERLAY_BOTTOM_LEFT,
SDVX_OVERLAY_BOTTOM_RIGHT
};
// settings
@@ -24,6 +27,7 @@ namespace games::sdvx {
class SDVXGame : public games::Game {
public:
SDVXGame();
virtual void pre_attach() override;
virtual void attach() override;
virtual void post_attach() override;
virtual void detach() override;