Compare commits

..

10 Commits

Author SHA1 Message Date
sp2xdev 0fc3aa5818 update changelog 2025-09-30 13:07:49 -07:00
sp2xdev 276874f882 update options 2025-09-29 19:28:08 -07:00
sp2xdev 1fdd270480 hide bio2 firmware update option 2025-09-29 19:03:13 -07:00
bicarus-dev 07cb6048a0 Add explanation for common exception codes (#386)
## Link to GitHub Issue, if one exists
#345 

## Description of change
Add a little warning message that shows when well-known exception codes
are encountered & caught by signal hooks.

## Testing
Tested by injecting bad instructions into the DLL.
2025-09-28 23:49:08 -07:00
bicarus-dev 61d79f76b2 ea3: remove verbose debug logs by default (#385)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Recently distributed iidx data has this enabled in ea3-config.xml by
default, exposing people's PCBID in the logs.

Find the node in the XML and remove it on boot, unless user overrides it
with a new option.

## Testing
Tested using asphyxia.
2025-09-28 20:31:48 -07:00
sp2xdev 7335d07e30 update changelog 2025-09-27 18:38:57 -07:00
bicarus-dev 9f99b71112 avs: when nvram/raw folder creation fails, show a warning message when the game eventually crashes (#383)
## Link to GitHub Issue, if one exists
#345 

## Description of change
When the directory specified in the mounttable (in avs-config.xml) lead
to bad path, remember this and show a warning message block before the
game crashes.

## Testing
Tested with simulated bad mounttable set up.
2025-09-27 18:16:20 -07:00
sp2xdev 5c3921a99c fix up error messages 2025-09-27 14:31:29 -07:00
sp2xdev 9fc397b8bc update loadlibrary failure message, again 2025-09-27 02:16:28 -07:00
bicarus-dev ddc8061268 iidx: apply signature patch for ASIO compatibility fix in iidx32 (#381)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Apply this fix automatically when needed -
https://github.com/two-torial/sp2xpatcher/pull/33

## Testing
Tested iidx31 to see that the patch does not apply
Checked -audiohookdisable to see that the logic gets skipped
Tested 2025041500 and 2025082500.
2025-09-26 01:26:49 -07:00
13 changed files with 191 additions and 48 deletions
+13 -3
View File
@@ -8,6 +8,7 @@
#include "external/robin_hood.h" #include "external/robin_hood.h"
#include "launcher/logger.h" #include "launcher/logger.h"
#include "launcher/signal.h"
#include "util/detour.h" #include "util/detour.h"
#include "util/fileutils.h" #include "util/fileutils.h"
#include "util/libutils.h" #include "util/libutils.h"
@@ -1736,7 +1737,13 @@ namespace avs {
return; return;
} }
static void create_dir( static void avs_dir_err(const std::filesystem::path &src_path)
{
launcher::signal::AVS_DIR_CREATION_FAILURE = TRUE;
launcher::signal::AVS_SRC_PATH = src_path.string();
}
static void create_avs_dir(
const std::string_view &avs_path, const std::string_view &avs_path,
const std::string_view &src_path) const std::string_view &src_path)
{ {
@@ -1745,6 +1752,7 @@ namespace avs {
auto real_path = std::filesystem::absolute(src_path, err); auto real_path = std::filesystem::absolute(src_path, err);
if (err) { if (err) {
avs_dir_err(real_path);
log_warning("avs-core", "failed to resolve '{}' path: {}", avs_path, err.message()); log_warning("avs-core", "failed to resolve '{}' path: {}", avs_path, err.message());
return; return;
} }
@@ -1754,7 +1762,9 @@ namespace avs {
if (created) { if (created) {
log_info("avs-core", "created '{}' at '{}'", avs_path, real_path.string()); log_info("avs-core", "created '{}' at '{}'", avs_path, real_path.string());
} }
if (err) { if (err) {
avs_dir_err(real_path);
log_warning("avs-core", "failed to create '{}' folder at '{}': {}", log_warning("avs-core", "failed to create '{}' folder at '{}': {}",
avs_path, avs_path,
real_path.string(), real_path.string(),
@@ -1815,7 +1825,7 @@ namespace avs {
return; return;
} }
create_dir(avs_path, device_path); create_avs_dir(avs_path, device_path);
} }
static void create_avs_config_fs_table( static void create_avs_config_fs_table(
@@ -1870,7 +1880,7 @@ namespace avs {
continue; continue;
} }
create_dir(dst_path, src_path); create_avs_dir(dst_path, src_path);
} while ((vfs_node = property_node_traversal(vfs_node, TRAVERSE_NEXT_SEARCH_RESULT))); } while ((vfs_node = property_node_traversal(vfs_node, TRAVERSE_NEXT_SEARCH_RESULT)));
} }
+6
View File
@@ -41,6 +41,7 @@ namespace avs {
int HTTP11 = -1; int HTTP11 = -1;
int URL_SLASH = -1; int URL_SLASH = -1;
int PCB_TYPE = -1; int PCB_TYPE = -1;
bool EA3_DEBUG_VERBOSE = false;
// handle // handle
std::string VERSION_STR = "unknown"; std::string VERSION_STR = "unknown";
@@ -412,6 +413,11 @@ namespace avs {
log_fatal("avs-ea3", "no PCBID set (try using -p to specify PCBID)"); log_fatal("avs-ea3", "no PCBID set (try using -p to specify PCBID)");
} }
// remove <debug> since it can expose pcbid in logged requests
if (!EA3_DEBUG_VERBOSE) {
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/debug/verbose");
}
// remember IDs // remember IDs
char pcbid_buffer[256] { 0 }; char pcbid_buffer[256] { 0 };
char accountid_buffer[256] { 0 }; char accountid_buffer[256] { 0 };
+1
View File
@@ -28,6 +28,7 @@ namespace avs {
extern int HTTP11; extern int HTTP11;
extern int URL_SLASH; extern int URL_SLASH;
extern int PCB_TYPE; extern int PCB_TYPE;
extern bool EA3_DEBUG_VERBOSE;
// handle // handle
extern std::string VERSION_STR; extern std::string VERSION_STR;
+8
View File
@@ -1,3 +1,11 @@
09/30/2025 [spice2x]
Prevent verbose debug EA3 logging by default
Options UI tweaks
09/28/2025 [spice2x]
IIDX: auto apply ASIO compatibility fix for IIDX32+
Misc diagnosability updates
09/22/2025 [spice2x] 09/22/2025 [spice2x]
Add Polaris Chord lights Add Polaris Chord lights
Add boot.dll to Gitadora patches target Add boot.dll to Gitadora patches target
+45 -1
View File
@@ -8,6 +8,7 @@
#include "games/iidx/legacy_camera.h" #include "games/iidx/legacy_camera.h"
#include "hooks/audio/audio.h"
#include "hooks/avshook.h" #include "hooks/avshook.h"
#include "hooks/cfgmgr32hook.h" #include "hooks/cfgmgr32hook.h"
#include "hooks/devicehook.h" #include "hooks/devicehook.h"
@@ -376,7 +377,11 @@ namespace games::iidx {
} }
} }
apply_audio_hacks(); if (hooks::audio::ENABLED) {
apply_audio_hacks();
} else {
log_warning("iidx", "skipping audio hooks; disabled by user");
}
// ASIO device hook // ASIO device hook
RegCloseKey_orig = detour::iat_try( RegCloseKey_orig = detour::iat_try(
@@ -766,22 +771,26 @@ namespace games::iidx {
0); 0);
// attempt to detect ASIO support // attempt to detect ASIO support
// <=24 : 32-bit only
// 25-26: has neither (no patch needed - WASAPI Exclusive by default) // 25-26: has neither (no patch needed - WASAPI Exclusive by default)
// 27-30: has both (envvar will be respected, ASIO or WASAPI) // 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+: only has XONAR (ASIO by default, signature patch can be used to force WASAPI - for now)
if (!has_SOUND_OUTPUT_DEVICE && !has_XONAR_SOUND_CARD) { if (!has_SOUND_OUTPUT_DEVICE && !has_XONAR_SOUND_CARD) {
// iidx 25-26
log_info("iidx", "This game only uses WASAPI audio engine"); log_info("iidx", "This game only uses WASAPI audio engine");
return; return;
} }
if (has_SOUND_OUTPUT_DEVICE && has_XONAR_SOUND_CARD) { if (has_SOUND_OUTPUT_DEVICE && has_XONAR_SOUND_CARD) {
// iidx 27-30
log_info("iidx", "This game accepts SOUND_OUTPUT_DEVICE environment variable"); log_info("iidx", "This game accepts SOUND_OUTPUT_DEVICE environment variable");
return; return;
} }
log_info("iidx", "This game supports ASIO but does not accept SOUND_OUTPUT_DEVICE environment variable"); 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 (SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
intptr_t result = replace_pattern( intptr_t result = replace_pattern(
avs::game::DLL_INSTANCE, avs::game::DLL_INSTANCE,
@@ -800,6 +809,41 @@ namespace games::iidx {
"Successfully forced WASAPI as audio engine using signature matching @ 0x{:x}.", "Successfully forced WASAPI as audio engine using signature matching @ 0x{:x}.",
result); result);
} }
} else {
log_info("iidx", "Not applying force wasapi patch; game will use ASIO");
}
// patch iidx32+ for asio compatibility
// only do this if NOT wasapi (as opposed to checking if it's asio)
// 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")) {
// in iidx32 final:
// ff 50 08 call QWORD PTR [rax+0x8] ; ASIO instance AddRef
// 48 8b 4b 08 mov rcx,QWORD PTR [rbx+0x8]
// 48 8b 01 mov rax,QWORD PTR [rcx]
// ff 50 08 call QWORD PTR [rax+0x8] ; ASIO instance AddRef
intptr_t result = replace_pattern(
avs::game::DLL_INSTANCE,
"FF50????????????????FF50??4533C94533C0418D51",
"????????????????????909090??????????????????",
0, 0);
if (result == 0) {
log_warning(
"iidx",
"Failed to apply ASIO compatibility fix for iidx32+. "
"Unless patches are applied, your ASIO device ({}) may hang or fail to work",
ASIO_DRIVER->c_str());
} else {
log_info(
"iidx",
"Successfully applied ASIO compatibility fix for iidx32+ using signature matching @ 0x{:x}.",
result);
}
} }
#endif #endif
+38 -15
View File
@@ -85,12 +85,19 @@ namespace games::iidx {
&m_pwszSymbolicLink, &m_pwszSymbolicLink,
&m_cchSymbolicLink &m_cchSymbolicLink
); );
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] GetAllocatedString failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
log_misc("iidx:camhook", "[{}] Symlink: {}", m_name, GetSymLink()); log_misc("iidx:camhook", "[{}] Symlink: {}", m_name, GetSymLink());
// Create the media source object. // Create the media source object.
hr = pActivate->ActivateObject(IID_PPV_ARGS(&m_pSource)); hr = pActivate->ActivateObject(IID_PPV_ARGS(&m_pSource));
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] ActivateObject failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
// Retain reference to the camera // Retain reference to the camera
m_pSource->AddRef(); m_pSource->AddRef();
@@ -98,13 +105,22 @@ namespace games::iidx {
// Create an attribute store to hold initialization settings. // Create an attribute store to hold initialization settings.
hr = WrappedMFCreateAttributes(&pAttributes, 2); hr = WrappedMFCreateAttributes(&pAttributes, 2);
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] MFCreateAttributes failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
hr = pAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, pD3DManager); hr = pAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, pD3DManager);
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] SetUnknown(MF_SOURCE_READER_D3D_MANAGER) failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
hr = pAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE); hr = pAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE);
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] SetUINT32(MF_SOURCE_READER_DISABLE_DXVA) failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
// TODO: Color space conversion // TODO: Color space conversion
// if (SUCCEEDED(hr)) { // if (SUCCEEDED(hr)) {
@@ -120,11 +136,18 @@ namespace games::iidx {
pAttributes, pAttributes,
&m_pSourceReader &m_pSourceReader
); );
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] MFCreateSourceReaderFromMediaSource failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
log_misc("iidx:camhook", "[{}] Created source reader", m_name); log_misc("iidx:camhook", "[{}] Created source reader", m_name);
hr = InitTargetTexture(); hr = InitTargetTexture();
if (FAILED(hr)) { goto done; } if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] InitTargetTexture failed with {:#x}", m_name, (ULONG)hr);
goto done;
}
// Camera should be still usable even if camera control is not supported // Camera should be still usable even if camera control is not supported
InitCameraControl(); InitCameraControl();
@@ -134,7 +157,7 @@ namespace games::iidx {
m_initialized = true; m_initialized = true;
log_misc("iidx:camhook", "[{}] Initialized", m_name); log_misc("iidx:camhook", "[{}] Initialized", m_name);
} else { } else {
log_warning("iidx:camhook", "[{}] Failed to create camera: {}", m_name, hr); log_warning("iidx:camhook", "[{}] Failed to create camera: {:#x}", m_name, (ULONG)hr);
} }
SafeRelease(&pAttributes); SafeRelease(&pAttributes);
LeaveCriticalSection(&m_critsec); LeaveCriticalSection(&m_critsec);
@@ -165,7 +188,7 @@ namespace games::iidx {
if (FAILED(hr)) { if (FAILED(hr)) {
if (hr != MF_E_NO_MORE_TYPES) { if (hr != MF_E_NO_MORE_TYPES) {
log_warning("iidx:camhook", "[{}] Cannot get media type {} {}", m_name, i, hr); log_warning("iidx:camhook", "[{}] Cannot get media type {} {:#x}", m_name, i, (ULONG)hr);
} }
break; break;
} }
@@ -584,7 +607,7 @@ namespace games::iidx {
* Return values: * Return values:
* S_OK: this is a "better" media type than the existing one * S_OK: this is a "better" media type than the existing one
* S_FALSE: valid media type, but not "better" * S_FALSE: valid media type, but not "better"
* E_*: invalid meia type * E_*: invalid media type
*/ */
HRESULT IIDXLocalCamera::TryMediaType(IMFMediaType *pType, UINT32 *pBestWidth, double *pBestFrameRate) { HRESULT IIDXLocalCamera::TryMediaType(IMFMediaType *pType, UINT32 *pBestWidth, double *pBestFrameRate) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@@ -595,13 +618,13 @@ namespace games::iidx {
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
if (FAILED(hr)) { if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] Failed to get subtype: {}", m_name, hr); log_warning("iidx:camhook", "[{}] Failed to get subtype: {:#x}", m_name, (ULONG)hr);
return hr; return hr;
} }
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height); hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
if (FAILED(hr)) { if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] Failed to get frame size: {}", m_name, hr); log_warning("iidx:camhook", "[{}] Failed to get frame size: {:#x}", m_name, (ULONG)hr);
return hr; return hr;
} }
@@ -619,7 +642,7 @@ namespace games::iidx {
(UINT32*)&frameRate.Denominator (UINT32*)&frameRate.Denominator
); );
if (FAILED(hr)) { if (FAILED(hr)) {
log_warning("iidx:camhook", "[{}] Failed to get frame rate: {}", m_name, hr); log_warning("iidx:camhook", "[{}] Failed to get frame rate: {:#x}", m_name, (ULONG)hr);
return hr; return hr;
} }
double frameRateValue = frameRate.Numerator / frameRate.Denominator; double frameRateValue = frameRate.Numerator / frameRate.Denominator;
@@ -696,7 +719,7 @@ namespace games::iidx {
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
log_misc("iidx:camhook", "[{}] Created texture", m_name); log_misc("iidx:camhook", "[{}] Created texture", m_name);
} else { } else {
log_warning("iidx:camhook", "[{}] Failed to create texture: {}", m_name, hr); log_warning("iidx:camhook", "[{}] Failed to create texture: {:#x}", m_name, (ULONG)hr);
} }
return hr; return hr;
} }
@@ -785,7 +808,7 @@ namespace games::iidx {
FlushDrawCommands(); FlushDrawCommands();
if (FAILED(hr)) { if (FAILED(hr)) {
log_warning("iidx:camhook", "Error in DrawSample {}", hr); log_warning("iidx:camhook", "Error in DrawSample {:#x}", (ULONG)hr);
} }
SafeRelease(&pCameraSurf); SafeRelease(&pCameraSurf);
LeaveCriticalSection(&m_critsec); LeaveCriticalSection(&m_critsec);
+3
View File
@@ -365,6 +365,9 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::VerboseAVSLogging].value_bool()) { if (options[launcher::Options::VerboseAVSLogging].value_bool()) {
hooks::avs::config::LOG = true; hooks::avs::config::LOG = true;
} }
if (options[launcher::Options::AllowEA3Verbose].value_bool()) {
avs::ea3::EA3_DEBUG_VERBOSE = true;
}
if (options[launcher::Options::spice2x_AutoOrientation].is_active()) { if (options[launcher::Options::spice2x_AutoOrientation].is_active()) {
GRAPHICS_ADJUST_ORIENTATION = GRAPHICS_ADJUST_ORIENTATION =
(graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32(); (graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32();
+22 -8
View File
@@ -359,7 +359,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.name = "r", .name = "r",
.desc = "Set custom SOFTID override", .desc = "Set custom SOFTID override",
.type = OptionType::Text, .type = OptionType::Text,
.category = "Network (Development)", .category = "Development",
.sensitive = true, .sensitive = true,
}, },
{ {
@@ -554,10 +554,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options", .category = "Game Options",
}, },
{ {
.title = "IIDX BIO2 Firmware", .title = "IIDX BIO2 Firmware Update",
.name = "iidxbio2fw", .name = "iidxbio2fw",
.desc = "Enables BIO2 firmware updates", .desc = "Enables BIO2 firmware updates. WARNING - can cause semi-permanent change to your I/O board",
.type = OptionType::Bool, .type = OptionType::Bool,
.hidden = true,
.game_name = "Beatmania IIDX", .game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)", .category = "Game Options (Advanced)",
}, },
@@ -1135,11 +1136,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Path Overrides", .category = "Path Overrides",
}, },
{ {
.title = "Intel SDE Folder", .title = "Intel SDE",
.name = "sde", .name = "sde",
.desc = "Path to Intel SDE kit path for automatic attaching", .desc = "Path to Intel SDE kit path for automatic attaching",
.type = OptionType::Text, .type = OptionType::Text,
.category = "Path Overrides", .category = "Development",
}, },
{ {
.title = "ea3-config.xml Override", .title = "ea3-config.xml Override",
@@ -1544,10 +1545,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.title = "Spice Audio Hook Backend", .title = "Spice Audio Hook Backend",
.name = "audiobackend", .name = "audiobackend",
.desc = "Selects the audio backend to use when spice audio hook is enabled, overriding exclusive WASAPI. " .desc = "Selects the audio backend to use when spice audio hook is enabled, overriding exclusive WASAPI. "
" Does nothing for games that do not output to exclusive WASAPI", "Does nothing for games that do not output to exclusive WASAPI",
.type = OptionType::Enum, .type = OptionType::Enum,
.category = "Audio", .category = "Audio",
.elements = {{"asio", "ASIO"}, {"waveout", "waveOut"}}, .elements = {
{"asio", "ASIO"},
{"waveout", "broken, do not use"}
},
}, },
{ {
.title = "Spice Audio Hook ASIO Driver ID", .title = "Spice Audio Hook ASIO Driver ID",
@@ -1672,6 +1676,16 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.type = OptionType::Bool, .type = OptionType::Bool,
.category = "Debug Log", .category = "Debug Log",
}, },
{
// AllowEA3Verbose
.title = "Allow EA3 Verbose Debug Logging",
.name = "ea3verbose",
.desc = "This option is only useful for network developers; leave this OFF.\n\n"
"By default, ea3/debug/verbose node is removed by spice to prevent exposing PCBID in the logs. "
"When this is enabled, ea3/debug/verbose node in the XML will be kept and exposed to the game",
.type = OptionType::Bool,
.category = "Debug Log",
},
{ {
.title = "Disable Colored Output", .title = "Disable Colored Output",
.name = "nocolor", .name = "nocolor",
@@ -2375,7 +2389,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.type = OptionType::Bool, .type = OptionType::Bool,
.category = "Development", .category = "Development",
.disabled = true, .disabled = true,
}, }
}; };
const std::vector<std::string> &launcher::get_categories(Options::OptionsCategory category) { const std::vector<std::string> &launcher::get_categories(Options::OptionsCategory category) {
+1
View File
@@ -188,6 +188,7 @@ namespace launcher {
DebugCreateFile, DebugCreateFile,
VerboseGraphicsLogging, VerboseGraphicsLogging,
VerboseAVSLogging, VerboseAVSLogging,
AllowEA3Verbose,
DisableColoredOutput, DisableColoredOutput,
DisableACPHook, DisableACPHook,
DisableSignalHandling, DisableSignalHandling,
+32 -1
View File
@@ -1,11 +1,12 @@
#include "signal.h" #include "signal.h"
#include <exception> #include <exception>
#include <string>
#include <windows.h> #include <windows.h>
#include <dbghelp.h> #include <dbghelp.h>
#include "avs/core.h"
#include "avs/game.h"
#include "acio/acio.h" #include "acio/acio.h"
#include "external/stackwalker/stackwalker.h" #include "external/stackwalker/stackwalker.h"
#include "hooks/libraryhook.h" #include "hooks/libraryhook.h"
@@ -32,6 +33,8 @@ namespace launcher::signal {
// states // states
bool SUPERSTEP_SOUND_ERROR = false; bool SUPERSTEP_SOUND_ERROR = false;
bool AVS_DIR_CREATION_FAILURE = false;
std::string AVS_SRC_PATH;
} }
#define V(variant) case variant: return #variant #define V(variant) case variant: return #variant
@@ -101,6 +104,22 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
// print signal // print signal
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord)); log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
std::string err;
switch (ExceptionRecord->ExceptionCode) {
case EXCEPTION_ILLEGAL_INSTRUCTION:
err = "Illegal instruction: either your CPU is too old (e.g., does not support "
"SSE4.2 or AVX2 but perhaps the game requires it); or, a bad patch was applied.";
break;
default:
break;
}
if (!err.empty()) {
log_warning(
"signal",
"likely cause for your error based on the exception code:\n {}",
err.c_str());
}
// check ACIO init failures // check ACIO init failures
if (acio::IO_INIT_IN_PROGRESS) { if (acio::IO_INIT_IN_PROGRESS) {
log_warning( log_warning(
@@ -121,6 +140,18 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
log_warning("signal", " fix your audio device, double check your audio options/patches, and try again"); log_warning("signal", " fix your audio device, double check your audio options/patches, and try again");
} }
if (launcher::signal::AVS_DIR_CREATION_FAILURE) {
log_warning("signal",
"AVS filesystem initialization failure was previously detected during boot!");
log_warning("signal",
" ERROR: directory could not be created: {}",
launcher::signal::AVS_SRC_PATH.c_str());
log_warning("signal",
" this crash may have been caused by bad <mounttable> contents in {}",
avs::core::CFG_PATH.c_str());
log_warning("signal", " fix the XML file and try again");
}
// walk the exception chain // walk the exception chain
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord; struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
while (record_cause != nullptr) { while (record_cause != nullptr) {
+5
View File
@@ -1,11 +1,16 @@
#pragma once #pragma once
#include <string>
namespace launcher::signal { namespace launcher::signal {
// settings // settings
extern bool DISABLE; extern bool DISABLE;
extern bool USE_VEH_WORKAROUND; extern bool USE_VEH_WORKAROUND;
extern bool SUPERSTEP_SOUND_ERROR; extern bool SUPERSTEP_SOUND_ERROR;
extern bool AVS_DIR_CREATION_FAILURE;
extern std::string AVS_XML_PATH;
extern std::string AVS_SRC_PATH;
//void print_stacktrace(); //void print_stacktrace();
void attach(); void attach();
+6 -7
View File
@@ -2633,17 +2633,16 @@ namespace overlay::windows {
// check hidden option // check hidden option
if (!this->options_show_hidden && option.value.empty()) { if (!this->options_show_hidden && option.value.empty()) {
// skip hidden entries // skip hidden entries
if (definition.hidden) { if (definition.hidden) {
continue; continue;
} }
}
// check for game exclusivity
if (!definition.game_name.empty()) { // check for game exclusivity
if (definition.game_name != this->games_selected_name) { if (!definition.game_name.empty()) {
continue; if (definition.game_name != this->games_selected_name) {
} continue;
} }
} }
+11 -13
View File
@@ -29,19 +29,17 @@ std::filesystem::path libutils::module_file_name(HMODULE module) {
static inline void load_library_fail(const std::string &file_name, bool fatal) { static inline void load_library_fail(const std::string &file_name, bool fatal) {
std::string info_str { fmt::format( std::string info_str { fmt::format(
"\n\nPlease check if {} exists and the permissions are fine.\n" "DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:\n"
"\n" " 1. Confirm if the file ({}) exists on the disk and check the file permissions.\n"
"* If the problem still persists, try installing things on this list:\n" " 2. Follow this link and install DLL prerequisites on this list:\n"
" https://github.com/spice2x/spice2x.github.io/wiki/DLL-Dependencies \n" " https://github.com/spice2x/spice2x.github.io/wiki/DLL-Dependencies \n"
"\n" " 3. Still have problems after installing from above and rebooting PC?\n"
"* Still have problems after installing from above and rebooting PC?\n" " a. Avoid manually specifying DLL path (-exec) and module directory (-modules); let spice2x auto-detect unless you have a good reason not to\n"
" Avoid manually specifying DLL path (-exec) and module directory (-modules); let spice2x auto-detect unless you have a good reason not to\n" " b. Ensure you do NOT have multiple copies of the game DLLs (e.g., in contents and in contents\\modules)\n"
" Ensure you do NOT have multiple copies of the game DLLs (e.g., in contents and in contents\\modules)\n" " c. Certain games require specific NVIDIA DLLs when running with AMD/Intel GPUs (hint: look inside stub directory for DLLs)\n"
" Certain games require specific NVIDIA DLLs when running with AMD/Intel GPUs (hint: look inside stub directory for DLLs)\n" " 4. (For advanced users) if none of the above helps, find the missing dependency using:\n"
"\n" " a. https://github.com/lucasg/Dependencies (recommended for most) \n"
"* (For advanced users) if none of the above helps, find the missing dependency using:\n" " b. http://www.dependencywalker.com/ (for old OS) \n"
" https://github.com/lucasg/Dependencies (recommended for most) \n"
" http://www.dependencywalker.com/ (for old OS) \n"
, file_name) }; , file_name) };
if (fatal) { if (fatal) {
log_fatal("libutils", "{}", info_str); log_fatal("libutils", "{}", info_str);