Update to spice2x-25-04-25 (pre-apply)
> broken commit
This commit is contained in:
+16
-23
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user