Compare commits

..

53 Commits

Author SHA1 Message Date
bicarus-dev 5641e06a19 iidx: fix kana input broken in subscreen when system language is not Japanese (#421)
## Link to GitHub Issue, if one exists
user-reported

## Description of change
When the system non-Unicode language is not set to Japanese, TDJ
subscreen katakana keyboard was broken (weird behavior with characters
not erasing, ending with corrupt characters, etc)

To fix this, add a hook for `IsDBCSLeadByte`. `IsDBCSLeadByte` assumes
system ACP (which may not be SHIFT_JIS). Instead, redirect bm2dx.dll to
use `IsDBCSLeadByteEx` instead with SHIFT_JIS explicitly specified as a
parameter.

Presumably the game was using IsDBCSLeadByte to manage the keyboard
typing logic.... which is weird because SDVX doesn't do the same.

## Testing
Tested iidx 31 and tried to do searches.
2025-11-10 11:35:46 -08:00
bicarus-dev 88ec6dbcee launcher: hide pcbid when -cmdoverride specified (#420)
## Link to GitHub Issue, if one exists
Fixes #419 

## Description of change
-cmdoverride caused pcbid to be logged in plain text

## Testing
2025-11-07 14:20:37 -08:00
bicarus-dev 1b614c94a7 mfc: remove log spam (#418)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Remove mutex lock/unlock log spam

Are they important? Idk

## Testing
2025-11-06 17:51:39 -08:00
bicarus-dev 37c5913f69 mfc: detect 2025 version (#416)
## Link to GitHub Issue, if one exists
n/a

## Description of change
They moved some DLLs around so MFC wasn't being auto-detected, and I/O
hooks were not being performed. Fix that.

## Testing
The game boots into test menu, some i/o works, touch doesn't, not
playable yet.
2025-11-05 19:23:10 -08:00
wrigglebug 2eca668593 update readme.txt (#415)
please merge this important code
2025-11-02 23:29:48 -08:00
bicarus-dev aec1da9d16 troubleshooter: detect ea3_report_posev error (#413)
## Link to GitHub Issue, if one exists
#345 

## Description of change
When `ea3-pos: ea3_report_posev: no such node:` is detected, add a
deferred error message and guide user to the FAQ.

## Testing
Tested SDVX with the missing XML node.
2025-11-02 14:13:04 -08:00
sp2xdev 548b441f1f update build script 2025-11-01 17:33:40 -07:00
bicarus-dev 98bc285d98 logger: show message popup for log_fatal (#412)
## Link to GitHub Issue, if one exists
#410 

## Description of change
When raising fatal errors via `log_fatal`, also show a modal popup.

Update instances of `log_fatal` where the message was too long to fit.

## Testing
Tested various failure conditions.
2025-11-01 13:41:58 -07:00
bicarus-dev 553c180bee signal: force minimize widnows before showing crash handler dialog (#411)
## Link to GitHub Issue, if one exists
#410 

## Description of change
Forcibly minimize all windows before showing the crash dialog. Without
this, the dialog shows "behind" the game when launching multi-monitor
fullscreen games (TDJ, VM)

## Testing
Tested TDJ and VM in fullscreen.
2025-11-01 02:08:14 -07:00
bicarus-dev 537252440e signal: show Windows popup window on crash (#410)
## Link to GitHub Issue, if one exists
#345 

## Description of change
Show a MessageBox when signal detects a crash.

## Testing
Tested full screen and windowed games.
2025-10-31 20:54:56 -07:00
sp2xdev 13a0877d38 fix up deferred messages formatting 2025-10-28 16:49:14 -07:00
bicarus-dev 50691b79f1 troubleshooter: add cases for audio hook and dx9on12 (#408)
## Link to GitHub Issue, if one exists
#345

## Description of change
Add auto-troubleshooter messages for when audio hooks are disabled, and
when 9on12 is turned on by user.

## Testing
Manual verification
2025-10-28 16:29:49 -07:00
bicarus-dev ad229dabdb update build script (#407)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Create a "full" version of the archive with api and extra binaries. The
normal archive remains in place with just src and stubs.
2025-10-27 23:00:32 -07:00
bicarus-dev bdff33a420 overlay: fix font loading (#406)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Fix font loading - when the code was refactored in #286 I used the wrong
file extension for couple of them.
2025-10-20 00:53:28 -07:00
bicarus-dev 4b21821aa4 Introduce builds for Linux, split archive into release and extras (#405)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Add a "Linux" variant of spicecfg/spice/spice64.exe - currently these
are the same as Windows binaries but built without dependency on
WinSCard, which makes it easier to run on WINE.

Split dist archive into two, move api and extras into the new extras
zip.

## Testing
I only checked to see that Linux variants run fine on Windows, and
checked with dumpbin to confirm that the dependency on winscard DLL is
removed. No official support will be provided for Linux builds.
2025-10-16 16:19:10 -07:00
bicarus-dev 6b47b5db50 iidx: set CONNECT_CAMERA env var even when iidx module is not enabled (#404)
## Link to GitHub Issue, if one exists
Fixes #403 

## Description of change
Set CONNECT_CAMERA env var even when iidx module is not enabled, so that
camhook can work without -iidx being set with real IO

## Testing
tested with emulated i/o and real i/o by user (see linked issue)
2025-10-15 13:50:12 -07:00
kazakhstan-sila a10ca5236b add option to remove winscard dependency (#400)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Add CMake option to disable SCard functionality. Needed by some builds
of WINE, where distributor opted to not enable scard functionality for
whatever reason

## Testing
Building with `cmake -DWITH_SCARD=OFF` does not link against winscard
Building without this option at all links against winscard
2025-10-13 14:13:51 -07:00
bicarus-dev be2dab9a1a Image duplication for screen resize (#401)
## Link to GitHub Issue, if one exists
#399 

## Description of change
Add image duplication option to screen resize, allowing overflow images
to wrap around the other side.

## Testing
Tested with DDR, IIDX (windowed and full screen TDJ), SDVX (orientation
swap)
2025-10-12 20:34:45 -07:00
AllanCat 02711cdee1 Fixed an issue where ext (release_code) wasn't detected and replaced correctly when using user specified bootstrap.xml path. (#398)
## Link to GitHub Issue, if one exists
#0

## Description of change
The original launcher::detect_bootstrap_release_code() wasn't detecting
user specified bootstrap.xml path, and was causing issues for
patch_manager and other ext check spots prior to ea3 init (as ea3 does
proper path check itself).
I've added the user path check and proper xml parsing from
detect_gameversion().

## Testing
Tested with prop/bootstrap.xml presents.
Tested with prop/bootstrap.xml not presents and -b
/path/to/bootstrap.xml
2025-10-10 21:35:34 -07:00
sp2xdev c6b10402f4 remove changelog from binary 2025-10-06 19:24:36 -07:00
bicarus-dev 58ea6ce17e troubleshooter: add more detection (#397)
## Description of change
Detect and log troubleshooter messages for:

* (early) hook DLL load failure
* data_mods folder without ifs_hook.dll
* spice version (print out current version and add a link to github
download)

## Testing
2025-10-06 08:03:06 -07:00
bicarus-dev 8cc00c371a troubleshooter: address common issues in iidx and popn (#396)
## Description of change
iidx: 9on12 crashes iidx31+

popn: special message for createdevice failures (resolution issue)

## Testing
manually test both cases
2025-10-04 15:21:33 -07:00
bicarus-dev 8e2985d8d0 troubleshooter: properly fix deadlock (#395)
## Description of change
Finally figured out where the deadlock was coming from - it's because
the `dump_to_logger` was writing `SuperstepSound: Audio device is not
available` to the logger which calls back into the log hook, and then
emits another deferred message, trying to acquire the lock again on the
same stack.

## Testing
Tested the superstep sound failure case again.
2025-10-04 13:50:04 -07:00
bicarus-dev 8d3b15641f logger: more fixes to deferred logging (troubleshooter) (#394)
## Description of change
Various fixes to deferred logger -

* Rename to "auto troubleshooter"
* Fix potential deadlock
* Reword the error messages to fit in a narrower column

## Testing
tested all the error cases
2025-10-04 02:13:39 -07:00
bicarus-dev 033e9f926a logger: warn about log level being set too high (#392)
## Link to GitHub Issue, if one exists
n/a

## Description of change
If log level is anything but `misc` or `all`, complain using the
deferred logger.

## Testing
Tested legacy AVS (DDR X2) and newer games.
2025-10-03 19:16:59 -07:00
sp2xdev da58503b47 use lock_guard and not unique_lock unless unlocking is needed 2025-10-03 00:07:54 -07:00
bicarus-dev cffee2b7f8 logger: add mutex to deferred logger (#391)
## Link to GitHub Issue, if one exists
[#390 ](https://github.com/spice2x/spice2x.github.io/pull/390)

## Description of change
Just like the normal logger, deferred logging can be called from any
component at any time, so accessing the vector needs to be guarded.

## Testing
2025-10-02 23:38:11 -07:00
bicarus-dev 32801319fa Create a class for deferred error logging (#390)
## Link to GitHub Issue, if one exists
#388 

## Description of change
Instead of setting flags in `signal` and logging when we crash, create a
class for logging deferred semi-fatal messages, and dump them to the log
immediately before crashing or shutting down.

## Testing
Tested each failure case by injection.
2025-10-02 18:42:49 -07:00
s2 afbe013811 pcm: support 2024091200 version (#389)
## Link to GitHub Issue, if one exists
none

## Description of change
Supports PCM version 2024091200.

## Testing
1. After starting the PCM, touch card and auth.
2. Press the bill insert button.
3. Check account balance has increased.
2025-10-02 15:26:12 -07:00
sp2xdev 862e4717f6 point users to vcredist aio package 2025-09-30 22:29:09 -07:00
bicarus-dev d3fa27ae4a Detect D3D9 CreateDevice / CreateDeviceEx failures (#388)
## Link to GitHub Issue, if one exists
#345 

## Description of change
Show a block of warning text if the game crashes after CreateDevice(Ex)
fails.

## Testing
Tested by injecting invalid resolution into spicecfg.
2025-09-30 22:13:02 -07:00
llm96 b487cf2bcf Print missing DLLs on library load failure (#387)
## Description of change
When the game library fails to load, recursively iterate its import
table to narrow down the missing library.

If the dependency is a commonly missing one, give the user a hint on
where to find it.

## Testing
System with an AMD GPU and LDJ-010 IIDX:
```
[2025/10/01 00:32:41] M:dependencies: bm2dx.dll
[2025/10/01 00:32:41] M:dependencies:   |-- nvEncodeAPI64.dll
[2025/10/01 00:32:41] W:dependencies:   | |-- [!] NVIDIA Graphics Driver
[2025/10/01 00:32:41] W:dependencies:   | |--     For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.
[2025/10/01 00:32:41] F:libutils: DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:
```

Same system, but with SDVX:
```
[2025/10/01 00:33:53] M:dependencies: soundvoltex.dll
[2025/10/01 00:33:53] M:dependencies:   |-- nvcuda.dll
[2025/10/01 00:33:53] W:dependencies:   | |-- [!] NVIDIA Graphics Driver
[2025/10/01 00:33:53] W:dependencies:   | |--     For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.
[2025/10/01 00:33:53] M:dependencies:   |-- nvcuvid.dll
[2025/10/01 00:33:53] W:dependencies:   | |-- [!] NVIDIA Graphics Driver
[2025/10/01 00:33:53] W:dependencies:   | |--     For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.
[2025/10/01 00:33:53] F:libutils: DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:
```

Contrived example of a missing dependency of a dependency:
```
[2025/10/01 00:30:59] M:dependencies: bm2dx.dll
[2025/10/01 00:30:59] M:dependencies:   |-- libaio.dll
[2025/10/01 00:30:59] W:dependencies:   | |-- [!] The library could not be loaded. (126)
[2025/10/01 00:30:59] M:dependencies:   |-- libaio-iob.dll
[2025/10/01 00:30:59] M:dependencies:   | |-- libaio.dll
[2025/10/01 00:30:59] M:dependencies:   |-- libaio-iob2_video.dll
[2025/10/01 00:30:59] M:dependencies:   | |-- libaio.dll
[2025/10/01 00:30:59] M:dependencies:   | |-- libaio-iob.dll
[2025/10/01 00:30:59] F:libutils: DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:
```

Another example of a missing file, but with 32-bit IIDX 24:
```
[2025/10/01 00:42:13] M:dependencies: bm2dx.dll
[2025/10/01 00:42:13] M:dependencies:   |-- libafp-win32.dll
[2025/10/01 00:42:13] W:dependencies:   | |-- [!] The library could not be loaded. (126)
[2025/10/01 00:42:13] M:dependencies:   |-- libafputils-win32.dll
[2025/10/01 00:42:13] M:dependencies:   | |-- libafp-win32.dll
[2025/10/01 00:42:13] F:libutils: DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:
```

---------

Co-authored-by: aixxe <me@aixxe.net>
2025-09-30 22:12:08 -07:00
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
sp2xdev c0698a3872 update changelog 2025-09-21 19:44:47 -07:00
kazakhstan-sila 1ed3521091 patcher: add gitadora boot.dll to extra DLL list (#379)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Allow importing patches for `boot.dll`

## Testing
Observed patch for the new DLL being attempted to be imported in the
logs.
2025-09-21 12:51:04 -07:00
bicarus-dev 0dda920448 iidx, sdvx: show error text when subscreen fails to render (#378)
## Link to GitHub Issue, if one exists
#345 

## Description of change
For IIDX / SDVX, when the subscreen surface failed to capture, display
an error message, suggesting the user to patch the game as needed.

Prior to this change, the subscreen overlay just showed an invisible
window if this happened.

## Testing
Tested IIDX windowed / full screen, and voltex full screen.
2025-09-21 00:20:41 -07:00
bicarus-dev 5f7580b69e pc: add polaris chord button lights (#377)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Add lights output for the buttons lamp array. Only implemented the top
row of lights and not all of them, this is good enough.

## Testing
Tested with a Nostroller and also spiceremote.py.
2025-09-20 16:37:39 -07:00
sp2xdev 3ef1b3ecaa update changelog 2025-09-20 04:31:11 -07:00
bicarus-dev 931811da14 iidx,sdvx: detect SuperstepSound init failures and log a message upon crash (#376)
## Link to GitHub Issue, if one exists
#345 

## Description of change
If we see SuperstepSound failure during boot, remember it, and when the
game eventually crashes, log a series of warning messages to surface why
the game likely failed to launch.

## Testing
Tested both iidx and sdvx with an audio device set to not allow
exclusive mode.
2025-09-20 04:17:40 -07:00
bicarus-dev 7624ded512 pc: add option to translate absolute analog values to fader input (#375)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Add a new option that allows absolute position analog input, such as
SDVX controller knobs and IIDX turntables, to be bound as input for
Polaris Chord faders.

In practice this means turning a knob counter-clockwise results in fader
being held left (relative to velocity), and vice versa.

## Testing
Tested using FauceTwo and a mouse.
2025-09-20 03:40:18 -07:00
sp2xdev a5252939dd update iidx audio patch signature 2025-09-20 03:40:04 -07:00
GEEKiDoS 808ac0c557 Fix msvc compiler warnings (#374)
To be noticed I edited thirdparty header for fmt library (#373), idk if
it is acceptable
2025-09-18 21:57:38 -07:00
sp2xdev 4e138b244e add dsound.dll to custom DLL detection 2025-09-18 21:49:43 -07:00
sp2xdev 3fcd1bdbc9 fix option strings for force load 2025-09-18 15:59:06 -07:00
59 changed files with 1384 additions and 966 deletions
+86 -9
View File
@@ -80,6 +80,25 @@ if(MSVC)
# enable COMDAT folding for even smaller release builds
add_link_options("$<$<CONFIG:RELEASE,MINSIZEREL>:/OPT:ICF>")
# always use UTF-8 (fix 4819)
add_compile_options("/utf-8")
# spectre mitigation warning
add_compile_options("/wd5045")
# implicit type convert warnings
add_compile_options("/wd4244")
add_compile_options("/wd4267")
add_compile_options("/wd4305")
# unreferenced local variable
add_compile_options("/wd4101")
# warning in winbase.h??
add_compile_options("/wd5039")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# disable warnings about using non _s variants like strncpy
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
@@ -338,12 +357,12 @@ set(SOURCE_FILES ${SOURCE_FILES}
external/cardio/cardio_runner.cpp
# external misc
external/scard/scard.cpp
external/stackwalker/stackwalker.cpp
external/tinyxml2/tinyxml2.cpp
external/http-parser/http_parser.c
external/usbhidusage/usb-hid-usage.c
external/toojpeg/toojpeg.cpp
external/scard/scard.cpp
# games
games/game.cpp
@@ -591,6 +610,8 @@ set(SOURCE_FILES ${SOURCE_FILES}
util/lz77.cpp
util/tapeled.cpp
util/execexe.cpp
util/dependencies.cpp
util/deferlog.cpp
)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
@@ -601,8 +622,9 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOUR
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
add_executable(spicetools_spice ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_spice
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
target_link_libraries(spicetools_spice PUBLIC winscard)
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
@@ -616,8 +638,9 @@ endif()
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
add_executable(spicetools_spice_laa ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_spice_laa
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
target_link_libraries(spicetools_spice_laa PUBLIC winscard)
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
set_target_properties(spicetools_spice_laa PROPERTIES OUTPUT_NAME "spice_laa")
target_compile_definitions(spicetools_spice_laa PRIVATE SPICE32_LARGE_ADDRESS_AWARE=1)
@@ -626,6 +649,22 @@ IF(NOT MSVC)
set_target_properties(spicetools_spice_laa PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -Wl,--large-address-aware")
endif()
# spice_linux.exe
###########
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
add_executable(spicetools_spice_linux ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_spice_linux
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
set_target_properties(spicetools_spice_linux PROPERTIES PREFIX "")
set_target_properties(spicetools_spice_linux PROPERTIES OUTPUT_NAME "spice_linux")
target_compile_definitions(spicetools_spice_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
IF(NOT MSVC)
set_target_properties(spicetools_spice_linux PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
endif()
# spice64.exe
#############
@@ -634,9 +673,9 @@ add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
target_link_libraries(spicetools_spice64
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp mfuuid strmiids dxva2
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
target_link_libraries(spicetools_spice64 PUBLIC winscard)
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
@@ -645,6 +684,25 @@ IF(NOT MSVC)
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
endif()
# spice64_linux.exe
#############
set(RESOURCE_FILES build/manifest.manifest build/manifest64.rc build/icon.rc cfg/Win32D.rc)
add_executable(spicetools_spice64_linux ${SOURCE_FILES} ${RESOURCE_FILES})
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
target_link_libraries(spicetools_spice64_linux
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
set_target_properties(spicetools_spice64_linux PROPERTIES PREFIX "")
set_target_properties(spicetools_spice64_linux PROPERTIES OUTPUT_NAME "spice64_linux")
target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE64=1)
target_compile_definitions(spicetools_spice64_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
IF(NOT MSVC)
set_target_properties(spicetools_spice64_linux PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
endif()
# spicecfg.exe
##############
@@ -652,8 +710,9 @@ set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_cfg
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp strmiids
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
target_link_libraries(spicetools_cfg PUBLIC winscard)
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
@@ -662,6 +721,24 @@ if(NOT MSVC)
set_target_properties(spicetools_cfg PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
endif()
# spicecfg_linux.exe
##############
set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
add_executable(spicetools_cfg_linux WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
target_link_libraries(spicetools_cfg_linux
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
set_target_properties(spicetools_cfg_linux PROPERTIES PREFIX "")
set_target_properties(spicetools_cfg_linux PROPERTIES OUTPUT_NAME "spicecfg_linux")
target_compile_definitions(spicetools_cfg_linux PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
target_compile_definitions(spicetools_cfg_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
if(NOT MSVC)
set_target_properties(spicetools_cfg_linux PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
endif()
# stubs
#######
@@ -755,19 +832,19 @@ endif()
####################
# output config
set_target_properties(spicetools_cfg
set_target_properties(spicetools_cfg spicetools_cfg_linux
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
# output 32bit
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
# output 64bit
set_target_properties(spicetools_spice64 spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64
set_target_properties(spicetools_spice64 spicetools_spice64_linux spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
+1 -1
View File
@@ -373,7 +373,7 @@ void ICCADevice::update_card(int unit) {
bool kb_insert_press = false;
// eamio keypress
kb_insert_press |= eamuse_get_keypad_state((size_t) unit) & (1 << EAM_IO_INSERT);
kb_insert_press |= static_cast<bool>(eamuse_get_keypad_state((size_t) unit) & (1 << EAM_IO_INSERT));
// check for card
if (this->cards[unit] == nullptr && (eamuse_card_insert_consume(this->node_count, unit) || kb_insert_press)) {
+40 -7
View File
@@ -8,6 +8,8 @@
#include "external/robin_hood.h"
#include "launcher/logger.h"
#include "launcher/signal.h"
#include "util/deferlog.h"
#include "util/detour.h"
#include "util/fileutils.h"
#include "util/libutils.h"
@@ -1501,7 +1503,8 @@ namespace avs {
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
"\n"
, DLL_NAME, MODULE_PATH.string()) };
log_fatal("avs-ea3", "{}", info_str);
log_warning("avs-ea3", "{}", info_str);
log_fatal("avs-ea3", "Failed to find critical avs DLL on disk (avs2-core.dll OR {})", DLL_NAME);
}
}
@@ -1736,7 +1739,17 @@ namespace avs {
return;
}
static void create_dir(
static void avs_dir_err(const std::filesystem::path &src_path)
{
deferredlogs::defer_error_messages({
"AVS filesystem initialization failure was previously detected during boot!",
fmt::format(" ERROR: directory could not be created: {}", src_path.string().c_str()),
fmt::format(" if you see a crash, it may have been caused by bad <mounttable> contents in {}", avs::core::CFG_PATH.c_str()),
" fix the XML file and try again"
});
}
static void create_avs_dir(
const std::string_view &avs_path,
const std::string_view &src_path)
{
@@ -1745,6 +1758,7 @@ namespace avs {
auto real_path = std::filesystem::absolute(src_path, err);
if (err) {
avs_dir_err(real_path);
log_warning("avs-core", "failed to resolve '{}' path: {}", avs_path, err.message());
return;
}
@@ -1754,7 +1768,9 @@ namespace avs {
if (created) {
log_info("avs-core", "created '{}' at '{}'", avs_path, real_path.string());
}
if (err) {
avs_dir_err(real_path);
log_warning("avs-core", "failed to create '{}' folder at '{}': {}",
avs_path,
real_path.string(),
@@ -1815,7 +1831,7 @@ namespace avs {
return;
}
create_dir(avs_path, device_path);
create_avs_dir(avs_path, device_path);
}
static void create_avs_config_fs_table(
@@ -1870,7 +1886,7 @@ namespace avs {
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)));
}
@@ -1924,6 +1940,7 @@ namespace avs {
static const char *LOG_LEVELS[] = { "disable", "fatal", "warning", "info", "misc", "all" };
char current_log_level_buffer[32] { 0 };
uint32_t current_log_level = 0;
std::string log_level_as_str;
if (VERSION == AVSLEGACY || VERSION == AVS21360) {
auto level_node = property_search(config, config_node, "/log/level");
@@ -1939,6 +1956,7 @@ namespace avs {
{
if (current_log_level < std::size(LOG_LEVELS)) {
log_info("avs-core", "log level: {}", LOG_LEVELS[current_log_level]);
log_level_as_str = LOG_LEVELS[current_log_level];
} else {
log_fatal("avs-core", "log level ({}) is invalid!", current_log_level);
}
@@ -1958,7 +1976,7 @@ namespace avs {
level_node = property_node_create(config, config_node, NODE_TYPE_str, "/log/level",
LOG_LEVELS[current_log_level]);
} else {
log_fatal("avs-core", "log level ({}) is invalid!", current_log_level);
log_fatal("avs-core", "log level ({}) is invalid! *", current_log_level);
}
}
@@ -1971,12 +1989,27 @@ namespace avs {
if (property_node_refer(config, config_node, "/log/level",
NODE_TYPE_str, current_log_level_buffer, sizeof(current_log_level_buffer)) > 0)
{
log_info("avs-core", "log level: {}", current_log_level_buffer);
log_info("avs-core", "log level: {} *", current_log_level_buffer);
log_level_as_str = current_log_level_buffer;
} else {
log_warning("avs-core", "log level: unknown");
log_warning("avs-core", "log level: unknown *");
}
}
if (log_level_as_str == "disable" ||
log_level_as_str == "fatal" ||
log_level_as_str == "warning" ||
log_level_as_str == "info") {
deferredlogs::defer_error_messages({
fmt::format(
"log level is set to `{}` (either in avs-config.xml or using -loglevel)", log_level_as_str),
" this log file may have omitted important error messages from the game",
" if you are troubleshooting crashes or failures, it is recommended that you",
" set AVS Log Level (-loglevel) option to `all`",
});
}
// fix time offset
auto t_now = std::time(nullptr);
auto tm_now = *std::gmtime(&t_now);
+9 -1
View File
@@ -41,6 +41,7 @@ namespace avs {
int HTTP11 = -1;
int URL_SLASH = -1;
int PCB_TYPE = -1;
bool EA3_DEBUG_VERBOSE = false;
// handle
std::string VERSION_STR = "unknown";
@@ -149,7 +150,9 @@ namespace avs {
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
"\n"
, DLL_NAME, MODULE_PATH.string()) };
log_fatal("avs-ea3", "{}", info_str);
log_warning("avs-ea3", "{}", info_str);
log_fatal("avs-ea3", "Failed to find critical ea3 DLL on disk (avs2-ea3.dll OR {})", DLL_NAME);
}
}
@@ -412,6 +415,11 @@ namespace avs {
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
char pcbid_buffer[256] { 0 };
char accountid_buffer[256] { 0 };
+1
View File
@@ -28,6 +28,7 @@ namespace avs {
extern int HTTP11;
extern int URL_SLASH;
extern int PCB_TYPE;
extern bool EA3_DEBUG_VERBOSE;
// handle
extern std::string VERSION_STR;
+2 -1
View File
@@ -98,7 +98,7 @@ namespace avs {
// ddr gamemdx.dll user error
if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") {
log_fatal(
log_warning(
"ddr",
"BAD GAME DLL ERROR\n\n"
"!!! !!!\n"
@@ -107,6 +107,7 @@ namespace avs {
"!!! remove -exec argument and try again. !!!\n"
"!!! !!!\n"
);
log_fatal("ddr", "BAD GAME DLL ERROR (don't use -exec gamemdx.dll, that's the wrong DLL)");
}
// file not found on disk
-1
View File
@@ -2,7 +2,6 @@
#define IDC_STATIC -1
#define IDD_DIALOG1 129
#define IDR_CHANGELOG 130
#define IDR_LICENSES 131
#define IDR_PATCHES 132
#define IDR_README 133
+21 -8
View File
@@ -49,6 +49,7 @@ BUILDDIR_64_RELEASE="./cmake-build-release-64"
BUILDDIR_64_DEBUG="./cmake-build-debug-64"
DEBUG=0
OUTDIR="./bin/spice2x"
OUTDIR_EXTRAS="./bin/spice2x/extras"
# disabled UPX since it tends to falsely trigger malware detection
UPX_ENABLE=0
@@ -59,9 +60,10 @@ INCLUDE_SRC=1
DIST_ENABLE=1
DIST_FOLDER="./dist"
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
DIST_NAME_EXTRAS="spice2x-$(date +%y)-$(date +%m)-$(date +%d)-full.zip"
DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.'
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice spicetools_spice_laa spicetools_stubs_cpusbxpkm"
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64"
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_cfg_linux spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_cpusbxpkm"
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64 spicetools_spice64_linux"
# determine build type
BUILD_TYPE="Release"
@@ -179,11 +181,17 @@ fi
# copy to output directory
echo "Copy files to output directory..."
rm -rf ${OUTDIR}
mkdir -p ${OUTDIR}
mkdir -p ${OUTDIR}/stubs/32
mkdir -p ${OUTDIR}/stubs/64
mkdir -p ${OUTDIR}/extras/largeaddressaware
rm -rf ${OUTDIR_EXTRAS}
mkdir -p ${OUTDIR_EXTRAS}
mkdir -p ${OUTDIR_EXTRAS}/largeaddressaware
mkdir -p ${OUTDIR_EXTRAS}/linux
if false # ((DEBUG > 0))
then
# debug files
@@ -204,11 +212,14 @@ then
else
# release files
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
cp ${BUILDDIR_32}/spicetools/spicecfg_linux.exe ${OUTDIR_EXTRAS}/linux/spicecfg.exe 2>/dev/null
cp ${BUILDDIR_32}/spicetools/32/spice.exe ${OUTDIR} 2>/dev/null
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR}/extras/largeaddressaware/spice.exe 2>/dev/null
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR_EXTRAS}/largeaddressaware/spice.exe 2>/dev/null
cp ${BUILDDIR_32}/spicetools/32/spice_linux.exe ${OUTDIR_EXTRAS}/linux/spice.exe 2>/dev/null
#cp ${BUILDDIR_32}/spicetools/32/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
#cp ${BUILDDIR_32}/spicetools/32/kld.dll ${OUTDIR}/stubs/32 2>/dev/null
cp ${BUILDDIR_64}/spicetools/64/spice64.exe ${OUTDIR} 2>/dev/null
cp ${BUILDDIR_64}/spicetools/64/spice64_linux.exe ${OUTDIR_EXTRAS}/linux/spice64.exe 2>/dev/null
#cp ${BUILDDIR_64}/spicetools/64/kbt.dll ${OUTDIR}/stubs/64 2>/dev/null
#cp ${BUILDDIR_64}/spicetools/64/kld.dll ${OUTDIR}/stubs/64 2>/dev/null
cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
@@ -228,10 +239,10 @@ then
fi
# copy resources
rm -rf ${OUTDIR}/api
mkdir ${OUTDIR}/api
rm -rf ${OUTDIR_EXTRAS}/api
mkdir ${OUTDIR_EXTRAS}/api
find ./api/resources/python -name "__pycache__" -exec rm -rf {} +
cp -r ./api/resources/* ${OUTDIR}/api
cp -r ./api/resources/* ${OUTDIR_EXTRAS}/api
# build distribution archive
if ((DIST_ENABLE > 0))
@@ -240,7 +251,9 @@ then
mkdir -p ${DIST_FOLDER}
rm -rf ${DIST_FOLDER}/${DIST_NAME}
pushd ${OUTDIR}/.. > /dev/null
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME} . -z <<< "$DIST_COMMENT"
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME} spice2x -x "spice2x/extras/*" -z <<< "$DIST_COMMENT"
echo "Building extras..."
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME_EXTRAS} spice2x -z <<< "$DIST_COMMENT"
popd > /dev/null
fi
+1
View File
@@ -1,2 +1,3 @@
del /s /q .ccache
del /s /q dist
call build_docker.bat
-1
View File
@@ -9,7 +9,6 @@
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDR_CHANGELOG RCDATA "../changelog.txt"
IDR_LICENSES RCDATA "../licenses.txt"
IDR_PATCHES RCDATA "../build/patches.json"
IDR_README RCDATA "../readme.txt"
-1
View File
@@ -1,6 +1,5 @@
#pragma once
#define IDR_CHANGELOG 130
#define IDR_LICENSES 131
#define IDR_PATCHES 132
#define IDR_README 133
+5
View File
@@ -87,6 +87,10 @@ namespace cfg {
load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio);
int duplicate = 0;
load_int_value(doc, root + prefix + "duplicate", duplicate);
scene.duplicate = static_cast<cfg::ScreenDuplicateMode>(duplicate);
}
// windowed settings are always under game settings
@@ -201,6 +205,7 @@ namespace cfg {
rapidjson::Pointer(root + prefix + "scale_x").Set(doc, scene.scale_x);
rapidjson::Pointer(root + prefix + "scale_y").Set(doc, scene.scale_y);
rapidjson::Pointer(root + prefix + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio);
rapidjson::Pointer(root + prefix + "duplicate").Set(doc, scene.duplicate);
}
// windowed mode settings
+7
View File
@@ -14,12 +14,19 @@ namespace cfg {
ResizableFrame = 2
};
enum ScreenDuplicateMode {
None = 0,
CopyLeft = 1,
CopyRight = 2,
};
struct fullscreen_setting {
int offset_x = 0;
int offset_y = 0;
float scale_x = 1.0;
float scale_y = 1.0;
bool keep_aspect_ratio = true;
ScreenDuplicateMode duplicate = ScreenDuplicateMode::None;
};
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
-751
View File
@@ -1,751 +0,0 @@
09/18/2025 [spice2x]
Polaris Chord windowed mode fixes
UI tweaks
09/17/2025 [spice2x]
Polaris Chord I/O fixes, language shim
09/16/2025 [spice2x]
Add Polaris Chord support
Tweak ImGUI theme
08/21/2025 [spice2x]
DDR: check for common DLL errors
Supply default PCBID if absent
Rearrange options
08/17/2025 [spice2x]
DDR: fix codec registration failure when path contains spaces
08/11/2025 [spice2x]
SDVX: fix camera hook, remove -sdvxdisablecams
DDR: automatically register codecs in com folder on boot
06/03/2025 [spice2x]
Add libshare-pj.dll to Gitadora patch import
Detect ACIO init failures
05/31/2025 [spice2x]
IIDX: fix windowed subscreen not accepting mouse clicks when
overlay is active
IIDX: tape LED over API
Option to make command line args take precedence
UI tweaks
05/09/2025 [spice2x]
Check for window focus when processing input (-inputfocus)
More options for IIDX/SDVX windowed subscreen
SpiceCompanion screen mirroring quality options
Various LovePlus improvements and fixes:
Allow camera access
Full screen mode
Add printer options
Add stub for printer DLL (cpusbxpkm.dll)
Logging improvements for better troubleshooting
04/25/2025 [spice2x]
LargeAddressAware variant of spice.exe for Metal Gear
Save new JSON config files to %appdata%/spice2x
Various bug fixes
04/08/2025 [spice2x]
Ensure rawinput touch is default for all games (-wintouch to override)
Various overlay UI fixes and improvements, update ImGui library
Add missing lights in Museca
03/29/2025 [spice2x]
Add SDVX landscape mode, -forceresswap option
Fix bugs in image scaler
Configurator UI tweaks
03/25/2025 [spice2x]
Add Mahjong Fight Girl support
Add option for custom full screen resolution (-forceres)
03/24/2025 [spice2x]
Auto PIN entry
Multiple scenes for image resize
API: add resize function, lights.read can now filter lights by name
Fix DLL hooks not receiving command-line arguments
03/16/2025 [spice2x]
Fix clipboard copy function truncating last character of string
03/03/2025 [spice2x]
IIDX: add workaround for REVERB EX filter missing in Windows 11 update
02/25/2025 [spice2x]
Add -vsyncbuffer option for forcing double/triple buffering
02/22/2025 [spice2x]
Add -windowscale option for resizing DX9 backbuffer dimensions
01/26/2025 [spice2x]
Expanded main menu in overlay (default bind: esc key)
Nostalgia: touch and swipe gestures (-nostpoke)
Jubeat: detect root directory boot failure
Add "Any Direction" analog type for button binding
01/16/2025 [spice2x]
More MIDI improvements:
use v2_drum algorithm instead of v2 by default for drummania & FTT
threshold setting for CC when mapped as a button (hi-hat pedals)
sustain duration applied to CC OnOff controls (sustain pedals)
Nostalgia, Beatstream: fix EA card insertion issue
CCJ, QKS: translate some windowed mode settings to Unity engine
Fix DEBUG build
01/08/2025 [spice2x]
Better MIDI support; significant improvements for drums
Fix various UI bugs in Buttons / Analog tabs
Nostalgia: fix velocity handling for MIDI input
Show camera names in camera control overlay
Game exit dialog (default: Escape key)
Button layout help text in Buttons tab
12/31/2024 [spice2x]
Fix videos not playing in Unity-based games
Dump audio device info in wrapped WASAPI handler
Update DLL load failure message
12/30/2024 [spice2x]
Busou Shinki: Show Cursor option now properly shows cursor in game
IIDX: add IIDX NVENC Quality option (-iidxreccqp)
IIDX: always enable NVENC hook, not just when -iidx is set
IIDX: add help text to keypad overlay in TDJ mode
Busou Shinki, QKS, CCJ: Only show cursor by default if no touchscreen detected
Ignore invalid HID devices with bad device path
12/13/2024 [spice2x]
Improve error messages for DLL load failures
Load cardio module in spicecfg
12/06/2024 [spice2x]
Clean up seldom used features (VR, Lua scripting, layeredfs, KFControl)
New card scanner section in Cards tab
Add -scardfix option for converting NFC cards into E00401 format
Add system information logging, controlled by -sysdump option
11/20/2024 [spice2x]
DRS: add subscreen overlay window (dance floor tape LED display)
IIDX: TDJ cam selection options for users with 3+ cameras
(-iidxtdjcamhooktop /-iidxtdjcamhookfront)
IIDX/SDVX: move some options to Advanced tab
Update -nvprofile to set V-Sync settings as Application Controlled
10/29/2024 [spice2x]
(IIDX31+) apply signature patch to force WASAPI by default; use -iidxsounddevice to override
Fix SDVX EG song search when using Japanese touch keyboard (when OS is not ja-JP)
Nostalgia I/O improvements
Expose DDR Gold cabinet tape LEDs via Spice API
10/14/2024 [spice2x]
Apply patches earlier, on DLL load notification
SMX dedicab lights improvements
10/12/2024 [spice2x]
SMX dedicab lights support (requires forked SMX.dll - see Issue #228)
Option to show FPS overlay on top left (-fpsflip)
Allow TDJ camhook to load without -iidx (for cabs)
09/21/2024 [spice2x]
Add Inject Early DLL Hooks option (-z)
09/14/2024 [spice2x]
Add Patch Manager Config Path (-patchcfgpath) option
Vertical/horizontal flip for TDJ cam hook
Fix mouse button behavior when left/right buttons are swapped
08/24/2024 [spice2x]
Fix Patch Manager failing to import patches when modules path is Unicode
08/22/2024 [spice2x]
UI update for Card Manager in overlay
08/12/2024 [spice2x]
IIDX TDJ camera - bug fixes
Prevent users from accidentally enabling -cfg and -kfcontrol in spicecfg
08/07/2024 [spice2x]
IIDX TDJ camera improvements - draw modes (stretch/crop), bug fixes
08/06/2024 [spice2x]
IIDX TDJ camera improvements
Automatic cropping for 16:9 resolutions
Toggle to keep or override camera parameters
Fix Unicode path handling for config files
08/03/2024 [spice2x]
IIDX TDJ camera improvements
Camera control overlay (check Overlay tab)
Hardware acceleration for camera rendering
IIDX TDJ play record improvements
NVENC hooks have been added to fix crash on song start; -nod3d9devhook
is no longer required
07/29/2024 [spice2x]
Fix IIDX TDJ not launching in fullscreen with two monitors
07/28/2024 [spice2x]
Add more DLL support for -iidxtdjcamhook
Add -iidxtdjcamhookratio and -iidxtdjcamhookoffset
07/25/2024 [spice2x]
Add -iidxtdjcamhook option for webcam support in TDJ
07/17/2024 [spice2x]
Disable touch feedback indicators
Bug fixes
07/15/2024 [spice2x]
Fix touch and touch emulation in wintouch-based games (Nostalgia, BeatStream...)
Fix misaligned SpiceCompanion touches on windowed TDJ subscreen
Improvements to TDJ poke feature
07/13/2024 [spice2x]
Fix windowed TDJ subscreen not accepting mouse clicks after card in
Allow windowed TDJ/UFC subscreen to minimize, but not close
07/10/2024 [spice2x]
Better gfdm XG2 and XG3 support
IIDX TDJ windowed mode rendering improvements
IIDX TDJ subscreen poke feature
CardIO NumLock toggle option
Patch manager UI tweaks
07/06/2024 [spice2x]
Reliability improvements for config file saving
Experimental and incomplete support for gfdm XG3
Option to specify path for screen resize config
Reflec Beat: fix being unable to type into overlay
07/03/2024 [spice2x]
Fix SMX stage compatibility
Patch manager: log header in patches JSON, better error handling
06/26/2024 [spice2x]
Fix MDX-003 not retrieving patches from online source
06/22/2024 [spice2x]
Reliability & performance improvements for auto-card-insert
Update -sdvxnosub to prevent creation of subscreen in windowed mode
Bug fixes
06/20/2024 [spice2x]
Improve experience for windowed SDVX UFC (always launch subscreen window)
Add Delay option in analog binds
Fix pop'n soft-lock with auto card insert
Fix -graphics-single-adapter not working in Beatstream/Nostalgia
06/14/2024 [spice2x]
Improve experience for touch-enabled games in windowed mode (SpiceTouch)
06/08/2024 [spice2x]
Patch manager bug fixes
06/03/2024 [spice2x]
Fix patch status not being saved properly
Search tab for finding options
06/02/2024 [spice2x]
Fix BBC and Museca hang on boot when COM ports are present
Deprecate -iidxtdjw (use -iidxtdj and -w together instead)
05/31/2024 [spice2x]
Redesign patches tab
Bug fixes for patches.json parsing
05/29/2024 [spice2x]
Add support for "number" patch type
History for remote patch URLs
05/28/2024 [spice2x]
Update -iidxtdjw to hide useless second window
05/27/2024 [spice2x]
Fix -apiserial crashing when -apiserialbaud is not provided
Suppress "failed to acquire subscreen" error when not relevant
05/22/2024 [spice2x]
Add caution string to patches.json format
Paste from clipboard button for URL patches import
05/12/2024 [spice2x]
Disable URL patch importing in-game
UI tweaks for importing patches
05/05/2024 [spice2x]
UI tweaks for importing patches
Add aliases for arguments with -sp2x prefix
05/04/2024 [spice2x]
New patch JSON format, importing patches from URL
Add Process Efficiency Class option for hetero CPUs
04/29/2024 [spice2x]
Move -vr to be DANCERUSH only option
Fix being unable to type into overlay when -nolegacy is on
04/08/2024 [spice2x]
Fix Discord rich presence app IDs
03/31/2024 [spice2x]
Fix IC CARD UNIT ERROR in UFC when COM ports are present
03/24/2024 [spice2x]
Fix Ongaku Paradise crash on boot due to VFS redirection
Address all compiler warnings
03/17/2024 [spice2x]
SMX pad lights output
Fix DDR pad input for P4IO / BIO2
Option aliases for IIDX/SDVX subscreen disable
03/16/2024 [spice2x]
I/O for DDR white cabinet type (P4IO)
Remove background animation from configurator
Compiler updates
03/06/2024 [spice2x]
Lights output for DDR gold cabinet type
02/13/2024 [spice2x]
Fix lights not updating over API in configurator
CCJ mouse trackball improvements
Make IIDX/SDVX native touch the default when -sp2x-nod3d9devhook is on
Remove log spam in IIDX
02/02/2024 [spice2x]
Add missing NVCUDA stubs for cuStreamCreate and cuStreamDestroy_v2
02/01/2024 [spice2x]
QuizKnock STADIUM support
Busou Shinki analog joystick support
01/30/2024 [spice2x]
Add woofer lights to popn HD mode
Prevent crash when both -graphics-force-single-adapter and
-sp2x-nod3d9devhook are enabled
01/27/2024 [spice2x]
Add Disable D3D9 Device Hook option (-sp2x-nod3d9devhook)
01/20/2024 [spice2x]
Force Exit overlay hotkey
Improve Low Latency Audio to work with more games
Charge Machine I/O fixes
UI tweaks (API tab, Development tab)
01/07/2024 [spice2x]
Chase Chase Jokers improvements (trackball and vsync fix)
01/06/2024 [spice2x]
Chase Chase Jokers improvements (cmd line args, trackball sensitivity)
01/05/2024 [spice2x]
Chase Chase Jokers support
01/01/2024 [spice2x]
UI tweaks - menu bar in configurator window
IIDX: scan for SOUND_OUTPUT_DEVICE in binary and log message
Switch from -Ofast to -O2
Remove ImGui demo and debug files from release (reduced binary size)
12/30/2023 [spice2x]
Add NVAPI Block option (-sp2x-nonvapi)
SDVX: Auto Card Insert disables itself after a timeout to prevent soft lock
12/27/2023 [spice2x]
Prevent SDVX from dumping PATH variable to log
Stubs for NVIDIA DLLs (nvcuda.dll, nvcuvid.dll, nvEncodeAPI64.dll)
UI tweaks
12/25/2023 [spice2x]
Fix Lock Cursor option not updating capture area in windowed mode
Update TDJ rom file hooks
12/23/2023 [spice2x]
Remove the need for hex edits to fix note scroll speed in SDVX VM on NVIDIA
Improvements to -graphics-force-refresh
12/22/2023 [spice2x]
HID analog relative axis mode
Automatic process affinity fix for Gitadora
Fix -cfgpath option not working
Buttons tab UI fix for Bind Many
12/18/2023 [spice2x]
Fix Road Fighters 3D I/O error on boot
12/17/2023 [spice2x]
Integer multiplier / divisor for HID analog
(alternative to existing sensitivity option)
12/15/2023 [spice2x]
Add hooks to prevent display scaling changes when SDVX launches
12/12/2023 [spice2x]
Add support for keypad in SDVX UFC/VM mode
New DX9on12 flag with more options (-sp2x-dx9on12, replaces -9on12)
12/11/2023 [spice2x]
Fix crash at launch on AMD/Intel GPUs when nvapi DLL is present
12/09/2023 [spice2x]
Lights output for Gitadora
Lights output for DRS
Tape LED averaging algorithm option (-sp2x-tapeledalgo)
Fix occasional crash on shutdown
11/23/2023 [spice2x]
Low latency shared audio option (-sp2x-lowlatencysharedaudio)
Automatic dev/raw/* folder creation for popn19-21
Move overlay bindings to Overlay tab
11/17/2023 [spice2x]
Use E00401 prefix for card number generation
Volume API hooks to prevent audio volume change (enabled by default)
Small UI tweaks
11/15/2023 [spice2x]
Automatic card insert option (-sp2x-autocard)
Dump CPU features to log on startup
11/12/2023 [spice2x]
Fix crash in some games caused by linker changes in 2022
(Gitadora Exchain and older, Bone Eater, etc)
Add IIDX native touch option (-sp2x-iidxnativetouch)
Fix V-Sync issues with auto-screen-orientation
11/04/2023 [spice2x]
Option for NVIDIA GPU optimization (-sp2x-nvprofile)
SmartCard fixes (for -scardflip and -scardtoggle)
Small reorganization of options in configurator
10/30/2023 [spice2x]
Add touch input support for DRS
Add TDJ Windowed mode for IIDX (-sp2x-iidxtdjw)
Fix -iidxasio not working in some versions of IIDX
10/22/2023 [spice2x]
Add E-spec I/O emulation for IIDX 30+
Fix IIDX TDJ launching at 60Hz for some users
Add workaround for buggy ASIO drivers that lock up on close
Hide Insert Card overlay by default, add option to show it again
09/29/2023 [spice2x]
Fix subscreen not updating in certain versions of EG.
Detect long paths and log a warning message.
06/08/2023 [spice2x]
Improved touch support for Jubeat and Reflec Beat.
04/23/2023 [spice2x]
Update -iidxsounddevice to automatically pick a value (wasapi in most cases)
04/21/2023 [spice2x]
Fix spicecfg not launching in some specific cases
04/20/2023 [spice2x]
Update font for IIDX segment display
New option: auto show FPS window
04/16/2023 [spice2x]
New feature: window resize. Added new options to change window size and
position on launch. Screen Resize window (F11) also updated with new
controls
Screen Resize settings are now per-game
Misc bug fixes
04/09/2023 [spice2x]
Add IIDX LED ticker (segment display) as subscreen overlay for LDJ
Add I/O panel window for all games, special support for IIDX, DDR, GFDM
Add options to automatically show certain windows on game launch
04/03/2023 [spice2x]
Move/resize for IIDX/SDVX subscreen overlay window
New options to control subscreen overlay window
Turn common config mistakes into fatal error messages
Various bug fixes for touch handling
Revert "pop'n launching at desktop refresh rate" hack from 03/30/2023
03/30/2023 [spice2x]
New option: IIDX Force Definition Type HD (720p)
New option: process priority
Fix pop'n launching at desktop refresh rate
Lower logger thread priority to reduce stutters
Misc bug fixes
03/25/2023 [spice2x]
Screen Resize UI update (F11)
FPS UI update (F12)
New option: processor affinity
Misc bug fixes
03/20/2023 [spice2x]
ASIO device override for SDVX (experimental)
Fix subscreen overlay for SDVX in Valkyrie mode using BI2X I/O
Update text for touch and audio config options
UI tweaks and minor bug fixes
03/17/2023 [spice2x]
Disable UPX (file sizes will be larger)
Fix regression from 2022 that prevented early patches
from being loaded properly (such as audio hex edits)
New option: HID lighting brightness
New option: display auto-rotate direction
New option: custom sleep duration
03/15/2023 [spice2x]
Improve IIDX TT+/- handling (allow alternate key bind)
Fix SpiceCompanion touch targets for TDJ FHD
Config UI tweaks
03/13/2023 [spice2x]
Fix TDJ FHD launching at wrong refresh rate
New IIDX/SDVX options for TT/knob sensitivity when using digital input
03/12/2023 [spice2x]
Fix mouse input for SDVX EG subscreen overlay
New unified layout for Options tab
Allow multiple DLLs in Inject Hook field
03/11/2023 [spice2x]
Beginning of spice2x fork, based on another fork
Ensure TDJ mode runs at 1080p@120Hz for newer games
Fix IIDX subscreen overlay in FHD mode
Gracefully deal with bad ea3-config.xml
04/02/2022 - Add lua scripting
Add button edit dialog
Add button debounce/invert settings
Add bind many function
Misc bug fixes
12/28/2021 - Add DirectX 9On12 wrapper option
Add analog deadzone settings
Fix SSL handshaking failed issue
Misc bug fixes
12/19/2021 - Force single graphics adapter option
Performance improvements
Misc bug fixes
10/12/2021 - Ongaku Paradise support
Fixed memory leak in Windows 8+ touch handler
Fix Gitadora two channel fix for Nextage
Fix Charge Machine touch window position
IIDX 19 support
04/02/2021 - Charge Machine support
Fix "unsupported fs type" endless loop
Misc bug fixes
03/01/2021 - Add DDR HD speaker lights
Automatic /dev/nvram and /dev/raw creation for AVS 2.17 and later
Fix FlexASIO crash introduced in previous release
Fix overlay crash from ImGui navigation button handling
Fix AVS configuration reading with binary files
Add AVS VFS drive remapping for E: and F:
Improve XP compatibility
Force dummy audio when using ASIO backend
Misc bug fixes
12/30/2020 - Metal Gear Arcade lights and fixes
Misc bug fixes
12/11/2020 - Fix patch manager crashing on invalid address
Automatic /dev/nvram and /dev/raw creation for AVS 2.16 and prior
Analog sensitivity improvements
Locale improvements
Misc bug fixes
10/27/2020 - Screen Capture support
IIDX TDJ support
Updated patches
Misc bug fixes
10/13/2020 - Configurator patches tab
KFControl fix cursor wrap
Screen resize window
Misc bug fixes
10/03/2020 - Add KFControl
Misc bug fixes
09/27/2020 - Reflec limelight & colette (LBR) support
LovePlus lights support
Fix module loading when spice(64).exe is outside contents
Ignore touchpad HID devices in touchscreen detection
Keypad bindings
SSL support
Analog knob preview
06/15/2020 - QMA physical keyboard support
Misc bug fixes
05/19/2020 - Alternate audio backends for exclusive-mode applications
Fix screenshot handler crash in KMA and LMA
MessageBox hooks (stops fullscreen windows from losing focus)
04/25/2020 - pop'n music 19 & 20 support
DDR X2 support
pop'n & HPM HDMI fix
Misc additions, fixes
03/13/2020 - Misc bug fixes and improvements
03/10/2020 - Winning Eleven support
03/04/2020 - Tenkaichi Shogikai support
Otoca D'or support
Misc bug fixes
02/29/2020 - MIDI hotplugging / overlay
Misc bug fixes
02/04/2020 - Configurator options tab
Overlay button bindings
Card generator
Misc bug fixes
01/22/2020 - Audio improvements
SDVX print overwrite option
PNM HD/SD options
Window icons
Misc improvements
01/11/2020 - New Config Utility (F4)
Audio Hooks
Misc bug fixes
01/03/2020 - DANCERUSH STARDOM support
Chinese SDVX support
Nostalgia OP2 support
LayeredFS now complete
Misc bug fixes
11/26/2019 - LayeredFS integration
Misc bug fixes
11/17/2019 - Screenshots (PrtScr Key)
DLL Architecture detection
SCard Felica support
Improve MIDI performance
Fix bt5api error handling
Fix XP support
11/05/2019 - Gitadora XG3 support
Guitar motor support
Gitadora cabinet setting
DDR HD->SD light support
ESP8266/NodeMCU API support
Misc bug fixes
10/13/2019 - Serial API support
Fullscreen monitor setting
Misc bug fixes
09/30/2019 - Fixed verbose D3D9 logging
MiniMaid support
EA-Dev functions
Metal Gear bug fixes
09/26/2019 - Steel Chronicle support
ACIO buffer view/editor
Misc bug fixes
09/21/2019 - IIDX Effector View
Performance improvements
PCBID now hidden in log file
Misc bug fixes
09/16/2019 - Introducing SpiceOverlay
- Virtual Keypads/Cards
- Patch Manager
- FPS/Log/Control Windows
Pop'n Music fancy window mode
Optional app-config.xml
Misc improvements
Misc bug fixes
09/09/2019 - DDR BIO2 support
NVIDIA Optimus support
Reflec Beat faster loading
Performance improvements
Misc bug fixes
08/24/2019 - Automatic G-Sync disable
Fixed Scotto inverted keypad
Fixed SDVX Gen1 input drops
Performance improvements
08/19/2019 - Scotto support
Mahjong Fight Club support
FutureTomTom Kinect fix
Fixed AVS heap size defaults
Fixed signal hook crash
Fixed early boot logging
08/14/2019 - HELLO! Pop'n Music lights
Improve performance
08/13/2019 - Add -cfgpath option
Misc additions/fixes
08/10/2019 - HELLO! Pop'n Music support
LovePlus support
Discord Rich Presence support
API shutdown/reboot
Add -nolegacy option
Colored logging
07/31/2019 - QMA windowed mode fix
QMA network check fix
Logging improvements
07/22/2019 - DDR SD mode reader fix
Misc bugs fixed with ACIO
Beatstream lights/mouse
Beatstream -ea support
07/19/2019 - FutureTomTom support
Reflec Beat lights
Dance Evolution lights
Nostalgia lights
SuperExit on ALT-F4
07/16/2019 - Hook DLLs load earlier
Heap size argument alias
API restart function
SmartEA cmd line option
Reader keypad support
Initial MFC support
Misc bug fixes
06/22/2019 - Touchpad button binding fix
MIDI buttons/analogs support
Misc bug fixes
05/18/2019 - API WebSocket support
05/16/2019 - Device Hotplugging
USB-Stick card inserts
Cursor capture fix
EA server fix for old AVS
05/07/2019 - Reflec 1 support
Gitadora custom PCBID
Touchscreen improvements
Touchscreen support on XP
Higher RB input polling rate
L/R-Shift/Control support
04/13/2019 - DDR SD Mode lights
Sextet (LIT Board) support
PIUIO hardware support
Windowed mode improvements
03/14/2019 - IIDX API module
EA server maintenance toggle
SDVX BI2A support
02/19/2019 - Network API server
Run outside of modules dir
Misc bug fixes
01/27/2019 - Jubeat Knit support
Quiz Magic Academy support
Museca/Jubeat lights
Smartcard NumLock toggle
01/11/2019 - Open Source!
Jubeat Copious support
Bishi Bashi Channel support
PacDrive/PocketVoltex support
KBT/KLD now are optional
Stacktraces, quiet crash
Huge code refactoring
Stability improvements/fixes
11/03/2018 - IIDX 25 (io, cams, light)
IIDX effector bindings
HID lighting output support
Button Multibinding
HID readers e.g. zyp's cardio
Bug fixes as usual
08/17/2018 - DDR X3, Nostalgia, Network
06/25/2018 - HID smartcard readers
06/10/2018 - DDR support
06/07/2018 - Gitadora/HID/EA bug fixes
05/18/2018 - Gitadora and MIDI devices
05/07/2018 - Support for hat switches
04/21/2018 - Card path configuration
04/09/2018 - HID/Analog/RawInput support
03/13/2018 - SDVX printer, felica, BT5API
01/23/2018 - MUSECA analog slowdown, fixes
01/21/2018 - Many fixed bugs/crashes
11/15/2017 - Fixed the MUSECA sound issue
11/14/2017 - Added MUSECA, Pop'n Music
Wavepass reader support
09/11/2017 - Added Road Fighters 3D
08/29/2017 - Custom modules path,
UAC admin manifest, netfix
08/28/2017 - Bug fixes
08/21/2017 - 64bit builds, beatstream
More command line options
07/28/2017 - Fixed I/O for IIDX and SDVX
07/26/2017 - Configuration Tool, Jubeat
Touch module, more options
06/01/2017 - Added DEA support
05/31/2017 - Public release
+4
View File
@@ -1527,8 +1527,10 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
return arg;
}
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
// The type template parameter is there to avoid an ODR violation when using
// a fallback formatter in one translation unit and an implicit conversion in
@@ -1544,7 +1546,9 @@ FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> {
return arg;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
template <bool IS_PACKED, typename Context, type, typename T,
FMT_ENABLE_IF(!IS_PACKED)>
+3
View File
@@ -23,6 +23,7 @@
* Modified version.
*/
#ifndef NO_SCARD
#include "scard.h"
#include <windows.h>
@@ -409,3 +410,5 @@ void scard_threadstart() {
void scard_fini() {
should_exit = true;
}
#endif
+1 -1
View File
@@ -14,7 +14,7 @@ namespace games::ccj {
bool MOUSE_TRACKBALL_USE_TOGGLE = false;
uint8_t TRACKBALL_SENSITIVITY = 10;
static HANDLE fakeHandle = (HANDLE)0xDEADBEEF;
static HANDLE fakeHandle = (HANDLE)0xDEADBEEFull;
static HWND hWnd = nullptr;
static WNDPROC wndProc = nullptr;
static std::thread *tbThread = nullptr;
+3 -1
View File
@@ -125,7 +125,7 @@ namespace games::ddr {
void DDRGame::pre_attach() {
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) {
log_fatal(
log_warning(
"ddr",
"BAD MODEL NAME ERROR\n\n\n"
"!!! model name set to TDX, this is WRONG and will break your game !!!\n"
@@ -136,6 +136,8 @@ namespace games::ddr {
"!!! !!!\n"
"!!! model name set to TDX, this is WRONG and will break your game !!!\n\n\n"
);
log_fatal("ddr", "BAD MODEL NAME ERROR - TDX specified, should be MDX instead");
}
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::DEST[0] == 'U') {
+54 -7
View File
@@ -8,6 +8,7 @@
#include "games/iidx/legacy_camera.h"
#include "hooks/audio/audio.h"
#include "hooks/avshook.h"
#include "hooks/cfgmgr32hook.h"
#include "hooks/devicehook.h"
@@ -22,11 +23,13 @@
#include "misc/wintouchemu.h"
#include "misc/eamuse.h"
#include "util/detour.h"
#include "util/deferlog.h"
#include "util/fileutils.h"
#include "util/libutils.h"
#include "util/memutils.h"
#include "util/sigscan.h"
#include "util/utils.h"
#include "launcher/signal.h"
#include "external/robin_hood.h"
@@ -232,6 +235,9 @@ namespace games::iidx {
} else if (data.find(" W:touch: missing trigger:") != 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;
} else {
return false;
}
@@ -372,7 +378,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
RegCloseKey_orig = detour::iat_try(
@@ -402,10 +412,6 @@ namespace games::iidx {
// 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()) {
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
}
@@ -422,7 +428,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"
@@ -440,6 +446,8 @@ 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");
}
}
@@ -762,26 +770,30 @@ namespace games::iidx {
0);
// attempt to detect ASIO support
// <=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)
if (!has_SOUND_OUTPUT_DEVICE && !has_XONAR_SOUND_CARD) {
// iidx 25-26
log_info("iidx", "This game only uses WASAPI audio engine");
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") {
intptr_t result = replace_pattern(
avs::game::DLL_INSTANCE,
"FF5008E8????ECFF83780803740D",
"FF5008E8??????FF83780803740D",
"??????BB00000000EB169090????",
0, 0);
@@ -796,6 +808,41 @@ 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
// 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
+38 -15
View File
@@ -85,12 +85,19 @@ namespace games::iidx {
&m_pwszSymbolicLink,
&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());
// Create the media source object.
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
m_pSource->AddRef();
@@ -98,13 +105,22 @@ namespace games::iidx {
// Create an attribute store to hold initialization settings.
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);
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);
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
// if (SUCCEEDED(hr)) {
@@ -120,11 +136,18 @@ namespace games::iidx {
pAttributes,
&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);
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
InitCameraControl();
@@ -134,7 +157,7 @@ namespace games::iidx {
m_initialized = true;
log_misc("iidx:camhook", "[{}] Initialized", m_name);
} 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);
LeaveCriticalSection(&m_critsec);
@@ -165,7 +188,7 @@ namespace games::iidx {
if (FAILED(hr)) {
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;
}
@@ -584,7 +607,7 @@ namespace games::iidx {
* Return values:
* S_OK: this is a "better" media type than the existing one
* 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 hr = S_OK;
@@ -595,13 +618,13 @@ namespace games::iidx {
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
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;
}
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
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;
}
@@ -619,7 +642,7 @@ namespace games::iidx {
(UINT32*)&frameRate.Denominator
);
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;
}
double frameRateValue = frameRate.Numerator / frameRate.Denominator;
@@ -696,7 +719,7 @@ namespace games::iidx {
if (SUCCEEDED(hr)) {
log_misc("iidx:camhook", "[{}] Created texture", m_name);
} 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;
}
@@ -785,7 +808,7 @@ namespace games::iidx {
FlushDrawCommands();
if (FAILED(hr)) {
log_warning("iidx:camhook", "Error in DrawSample {}", hr);
log_warning("iidx:camhook", "Error in DrawSample {:#x}", (ULONG)hr);
}
SafeRelease(&pCameraSurf);
LeaveCriticalSection(&m_critsec);
+5 -1
View File
@@ -169,7 +169,7 @@ namespace games::jb {
const auto current_path = std::filesystem::current_path();
log_misc("jubeat", "current working directory: {}", current_path.string());
if (current_path.parent_path() == current_path.root_path()) {
log_fatal(
log_warning(
"jubeat",
"\n\nInvalid path error; jubeat cannot run from a directory in the drive root\n"
"The game will overflow the stack and silently fail to boot\n\n"
@@ -179,6 +179,10 @@ namespace games::jb {
"To fix this, create a new directory and move ALL game files there.\n\n"
"Your current working directory: {}\n",
current_path.string());
log_fatal(
"jubeat",
"Invalid path error; jubeat cannot run from a directory in the drive root");
}
}
}
+24
View File
@@ -288,6 +288,21 @@ namespace games::mfc {
MFCGame::MFCGame() : Game("Mahjong Fight Club") {
}
static bool spam_remover(void *user, const std::string &data, logger::Style style, std::string &out) {
if (data.empty() || data[0] != '[') {
return false;
}
if (data.find("W:mutex: lock: mid 00000000 != AVS_DTYPE_MUTEX") != std::string::npos) {
out = "";
return true;
}
if (data.find("W:mutex: unlock: mid 00000000 != AVS_DTYPE_MUTEX") != std::string::npos) {
out = "";
return true;
}
return false;
}
void MFCGame::attach() {
Game::attach();
@@ -308,6 +323,13 @@ namespace games::mfc {
auto allinone_module = libutils::try_module("allinone.dll");
auto system_module = libutils::try_module("system.dll");
// Mahjong Fight Club - 2025?
// they removed allinone.dll and moved i/o into system.dll
if (allinone_module == nullptr) {
log_misc("mfc", "using system.dll instead of allinone.dll for i/o hooks");
allinone_module = system_module;
}
// network fix
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
@@ -378,5 +400,7 @@ namespace games::mfc {
detour::inline_hook((void *) mouse_utl_step, libutils::try_proc(
allinone_module, "?mouse_utl_step@@YAXXZ"));
}
logger::hook_add(spam_remover, nullptr);
}
}
+1 -1
View File
@@ -94,7 +94,7 @@ namespace games::otoca {
bool kb_insert_press = false;
// eamio keypress
kb_insert_press |= eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT);
kb_insert_press |= static_cast<bool>(eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT));
// check for card
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
+163 -4
View File
@@ -7,8 +7,68 @@
#include "games/io.h"
#include "io.h"
#include "util/tapeled.h"
#include "pc.h"
#include "util/utils.h"
namespace games::pc {
bool PC_KNOB_MODE = false;
constexpr float RELATIVE_DECAY = 0.02f;
struct FADER_RELATIVE {
// ranges from 0.f to 1.f
float previous_raw = 0.5f;
// ranges from -1.f to +1.f
float effective_value = 0.f;
};
FADER_RELATIVE fader_l_relative;
FADER_RELATIVE fader_r_relative;
float calculate_analog_raw_delta(float old_value, float new_value) {
// assumed that values are between 0.f and 1.f
float delta = 0.f;
if ((old_value < 0.25f) && (0.75f < new_value)) {
// wrapped around: going left
delta = -((1.f - new_value) + old_value);
} else if ((new_value < 0.25f) && (0.75f < old_value)) {
// wrapped around: going right
delta = (1.f - old_value) + new_value;
} else {
delta = new_value - old_value;
}
return delta;
}
float apply_decay(float val) {
// return to center over time
if (RELATIVE_DECAY < val) {
return val - RELATIVE_DECAY;
} else if (val < -RELATIVE_DECAY) {
return val + RELATIVE_DECAY;
} else {
return 0.f;
}
}
float get_fader_knob_mode_value(float raw_analog, FADER_RELATIVE &fader) {
// add new value...
const float delta = calculate_analog_raw_delta(fader.previous_raw, raw_analog);
fader.effective_value += (delta * 20.f);
fader.previous_raw = raw_analog;
// capture the result after adding new input value
fader.effective_value = CLAMP(fader.effective_value, -1.f, 1.f);
const float result = fader.effective_value;
// post-process for next iteration: apply decay (return to center over time)
fader.effective_value = apply_decay(fader.effective_value);
return result;
}
/*
* class definitions
@@ -270,7 +330,13 @@ namespace games::pc {
// FADER-L
float val = 0.f;
if (analogs[Analogs::FaderL].isSet()) {
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2;
if (PC_KNOB_MODE) {
val = get_fader_knob_mode_value(
GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]),
fader_l_relative);
} else {
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2;
}
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]) &&
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) {
@@ -289,7 +355,13 @@ namespace games::pc {
// FADER-R
val = 0.f;
if (analogs[Analogs::FaderR].isSet()) {
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2;
if (PC_KNOB_MODE) {
val = get_fader_knob_mode_value(
GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]),
fader_r_relative);
} else {
val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2;
}
}
if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]) &&
GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) {
@@ -343,6 +415,19 @@ namespace games::pc {
}
}
struct PolarisChordLight {
int data_index;
games::pc::Lights::pc_lights_t light;
PolarisChordLight(
int data_index, games::pc::Lights::pc_lights_t light) :
data_index(data_index), light(light) {}
};
static void set_led_value(games::pc::Lights::pc_lights_t light, uint8_t value) {
auto &lights = games::pc::get_lights();
GameAPI::Lights::writeLight(RI_MGR, lights.at(light), value / 255.f);
}
void __fastcall aioIob2Bi2xAC1_SetTapeLedDataPart(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_TapeLedCh,
uint32_t i_Offset, uint8_t *i_pData,
uint32_t i_cntTapeLed, bool i_bReverse) {
@@ -350,8 +435,82 @@ namespace games::pc {
return aioIob2Bi2xAC1_SetTapeLedDataPart_orig(i_pNodeCtl, i_TapeLedCh, i_Offset, i_pData, i_cntTapeLed, i_bReverse);
}
// TODO implement tape led
// there are >200 lights in total, adding each one separately probably isn't the best idea...
// log_info(
// "pc",
// "lamp [{}] [{}] = {},{},{}, cnt={}",
// i_TapeLedCh,
// i_Offset,
// i_pData[0], i_pData[1], i_pData[2],
// i_cntTapeLed);
// [channel 0]
// these are button lamps; there are 12 buttons (columns) with this layout:
//
// 0 5 8 11 14 16 | 18 20 22 25 28 31
// 1 6 9 12 15 17 | 19 21 23 26 29 32
// 2 7 10 13 | 24 27 30 33
// 3 | 34
// 4 | 35
//
// 36 RGB lamps * 3 = 108 LEDs
// each value ranges from [0, 255]
// (we only care about the top row)
static PolarisChordLight button_lights_mapping[] = {
{(0 * 3) + 0, games::pc::Lights::pc_lights_t::Button1_R},
{(0 * 3) + 1, games::pc::Lights::pc_lights_t::Button1_G},
{(0 * 3) + 2, games::pc::Lights::pc_lights_t::Button1_B},
{(5 * 3) + 0, games::pc::Lights::pc_lights_t::Button2_R},
{(5 * 3) + 1, games::pc::Lights::pc_lights_t::Button2_G},
{(5 * 3) + 2, games::pc::Lights::pc_lights_t::Button2_B},
{(8 * 3) + 0, games::pc::Lights::pc_lights_t::Button3_R},
{(8 * 3) + 1, games::pc::Lights::pc_lights_t::Button3_G},
{(8 * 3) + 2, games::pc::Lights::pc_lights_t::Button3_B},
{(11 * 3) + 0, games::pc::Lights::pc_lights_t::Button4_R},
{(11 * 3) + 1, games::pc::Lights::pc_lights_t::Button4_G},
{(11 * 3) + 2, games::pc::Lights::pc_lights_t::Button4_B},
{(14 * 3) + 0, games::pc::Lights::pc_lights_t::Button5_R},
{(14 * 3) + 1, games::pc::Lights::pc_lights_t::Button5_G},
{(14 * 3) + 2, games::pc::Lights::pc_lights_t::Button5_B},
{(16 * 3) + 0, games::pc::Lights::pc_lights_t::Button6_R},
{(16 * 3) + 1, games::pc::Lights::pc_lights_t::Button6_G},
{(16 * 3) + 2, games::pc::Lights::pc_lights_t::Button6_B},
{(18 * 3) + 0, games::pc::Lights::pc_lights_t::Button7_R},
{(18 * 3) + 1, games::pc::Lights::pc_lights_t::Button7_G},
{(18 * 3) + 2, games::pc::Lights::pc_lights_t::Button7_B},
{(20 * 3) + 0, games::pc::Lights::pc_lights_t::Button8_R},
{(20 * 3) + 1, games::pc::Lights::pc_lights_t::Button8_G},
{(20 * 3) + 2, games::pc::Lights::pc_lights_t::Button8_B},
{(22 * 3) + 0, games::pc::Lights::pc_lights_t::Button9_R},
{(22 * 3) + 1, games::pc::Lights::pc_lights_t::Button9_G},
{(22 * 3) + 2, games::pc::Lights::pc_lights_t::Button9_B},
{(25 * 3) + 0, games::pc::Lights::pc_lights_t::Button10_R},
{(25 * 3) + 1, games::pc::Lights::pc_lights_t::Button10_G},
{(25 * 3) + 2, games::pc::Lights::pc_lights_t::Button10_B},
{(28 * 3) + 0, games::pc::Lights::pc_lights_t::Button11_R},
{(28 * 3) + 1, games::pc::Lights::pc_lights_t::Button11_G},
{(28 * 3) + 2, games::pc::Lights::pc_lights_t::Button11_B},
{(31 * 3) + 0, games::pc::Lights::pc_lights_t::Button12_R},
{(31 * 3) + 1, games::pc::Lights::pc_lights_t::Button12_G},
{(31 * 3) + 2, games::pc::Lights::pc_lights_t::Button12_B},
};
if (i_TapeLedCh == 0 && i_Offset == 0 && i_cntTapeLed == 108) {
for (const auto &map : button_lights_mapping) {
set_led_value(map.light, i_pData[map.data_index]);
}
}
}
void __fastcall aioIob2Bi2x_SetTapeLedDataGroup(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_bfGroup) {
+49 -1
View File
@@ -71,7 +71,55 @@ std::vector<Light> &games::pc::get_lights() {
&lights,
"IC Reader R",
"IC Reader G",
"IC Reader B"
"IC Reader B",
"Button 1 R",
"Button 1 G",
"Button 1 B",
"Button 2 R",
"Button 2 G",
"Button 2 B",
"Button 3 R",
"Button 3 G",
"Button 3 B",
"Button 4 R",
"Button 4 G",
"Button 4 B",
"Button 5 R",
"Button 5 G",
"Button 5 B",
"Button 6 R",
"Button 6 G",
"Button 6 B",
"Button 7 R",
"Button 7 G",
"Button 7 B",
"Button 8 R",
"Button 8 G",
"Button 8 B",
"Button 9 R",
"Button 9 G",
"Button 9 B",
"Button 10 R",
"Button 10 G",
"Button 10 B",
"Button 11 R",
"Button 11 G",
"Button 11 B",
"Button 12 R",
"Button 12 G",
"Button 12 B"
);
}
+49
View File
@@ -41,6 +41,55 @@ namespace games::pc {
IC_READER_R,
IC_READER_G,
IC_READER_B,
Button1_R,
Button1_G,
Button1_B,
Button2_R,
Button2_G,
Button2_B,
Button3_R,
Button3_G,
Button3_B,
Button4_R,
Button4_G,
Button4_B,
Button5_R,
Button5_G,
Button5_B,
Button6_R,
Button6_G,
Button6_B,
Button7_R,
Button7_G,
Button7_B,
Button8_R,
Button8_G,
Button8_B,
Button9_R,
Button9_G,
Button9_B,
Button10_R,
Button10_G,
Button10_B,
Button11_R,
Button11_G,
Button11_B,
Button12_R,
Button12_G,
Button12_B
} pc_lights_t;
}
+1
View File
@@ -5,6 +5,7 @@
namespace games::pc {
extern std::string PC_INJECT_ARGS;
extern bool PC_NO_IO;
extern bool PC_KNOB_MODE;
class PCGame : public games::Game {
public:
+17 -1
View File
@@ -14,6 +14,7 @@ namespace games::pcm {
static double BILL_DELAY = 2.0;
static int bill_kind = 0;
static int accept_bill_kind = 0;
static int __cdecl BillVali_GetEscrowBillKind() {
return bill_kind;
@@ -74,6 +75,12 @@ namespace games::pcm {
BILL_IN_TIME = get_performance_seconds();
} else if ((BILL_IN_TIME != 0) && ((BILL_IN_TIME + BILL_DELAY) <= get_performance_seconds())) {
BILL_IN_TIME = 0;
if (accept_bill_kind != 0 && accept_bill_kind != bill_kind) {
bill_kind = 0;
return 0;
}
switch (bill_kind) {
case 1:
return 1;
@@ -98,7 +105,8 @@ namespace games::pcm {
return true;
}
static bool __cdecl BillVali_SetAcceptBill(int) {
static bool __cdecl BillVali_SetAcceptBill(int a1) {
accept_bill_kind = a1;
return true;
}
@@ -148,5 +156,13 @@ namespace games::pcm {
system, "?GetEscrowBillKind@GsBillVali@@SAHXZ"));
detour::inline_hook(BillVali_SetAcceptBill, libutils::try_proc(
system, "?SetAcceptBill@GsBillVali@@SA_NH@Z"));
// NOTE: for 2024091200 or newer
detour::inline_hook(BillVali_ReceiveBill, libutils::try_proc(
system, "?ReceiveBill@GsBillVali@@SA_NXZ"));
detour::inline_hook(BillVali_GetEscrowBillKind, libutils::try_proc(
system, "?GetEscrowBillKind@GsBillVali@@SA?AW4E_BILLKIND@@XZ"));
detour::inline_hook(BillVali_SetAcceptBill, libutils::try_proc(
system, "?SetAcceptBill@GsBillVali@@SA_NW4E_BILLKIND@@@Z"));
}
}
+19 -1
View File
@@ -13,6 +13,7 @@
#include "hooks/sleephook.h"
#include "hooks/winuser.h"
#include "touch/touch.h"
#include "util/deferlog.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/sigscan.h"
@@ -24,6 +25,7 @@
#include "io.h"
#include "acioemu/handle.h"
#include "cfg/configurator.h"
#include "launcher/signal.h"
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
@@ -209,6 +211,19 @@ namespace games::sdvx {
out = "";
return true;
}
if (data.find("SuperstepSound: Audio device is not available") != std::string::npos) {
deferredlogs::defer_error_messages(deferredlogs::SUPERSTEP_SOUND_ERROR_MESSAGE);
return false;
}
if (data.find("W:ea3-pos: ea3_report_posev: no such node:") != std::string::npos) {
deferredlogs::defer_error_messages({
"bad prop\\ea3-config.xml detected by game",
std::string(" ") + data,
" this will most likely cause Server Busy errors in certain conditions",
" follow the FAQ to fix your ea3-config.xml and try again"
});
return false;
}
return false;
}
@@ -262,7 +277,7 @@ namespace games::sdvx {
AUTO_INSERT_CARD_COOLDOWN = 15.f;
// check bad model name
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("UFC")) {
log_fatal(
log_warning(
"sdvx",
"BAD MODEL NAME ERROR\n\n\n"
"!!! model name set to UFC, this is WRONG and will break your game !!!\n"
@@ -272,6 +287,9 @@ namespace games::sdvx {
"!!! !!!\n"
"!!! model name set to UFC, this is WRONG and will break your game !!!\n\n\n"
);
log_fatal(
"sdvx",
"BAD MODEL NAME ERROR - model name set to UFC, must be KFC instead");
}
}
@@ -19,12 +19,14 @@
#include "hooks/graphics/graphics.h"
#include "launcher/launcher.h"
#include "launcher/options.h"
#include "launcher/signal.h"
#include "launcher/shutdown.h"
#include "misc/clipboard.h"
#include "misc/eamuse.h"
#include "misc/wintouchemu.h"
#include "overlay/overlay.h"
#include "util/detour.h"
#include "util/deferlog.h"
#include "util/flags_helper.h"
#include "util/libutils.h"
#include "util/logging.h"
@@ -203,15 +205,50 @@ static std::string presentation_interval2s(UINT presentation_interval) {
static void update_backbuffer_dimensions(D3DPRESENT_PARAMETERS *params);
static void log_create_device_failure(HRESULT hresult) {
// only print once since some games will try CreateDevice multiple times on failure
static std::once_flag printed;
std::call_once(printed, [hresult]() {
// special case for popn
if (avs::game::is_model("M39")) {
deferredlogs::defer_error_messages({
fmt::format("D3D9 CreateDevice/CreateDeviceEx failed with {:#x}!", (UINT)hresult),
" possible popn music HD mode resolution issue",
" popn HD mode launches at 1360x768 (and NOT 1366x768) which is often",
" unsupported by many monitors; here are some possible workarounds:",
" * enable GPU resolution scaling in your GPU settings",
" * use Force Full Screen Resolution option, combined with image scaling (F11)",
" * run in windowed mode",
" * run in SD mode"
});
} else {
deferredlogs::defer_error_messages({
fmt::format("D3D9 CreateDevice/CreateDeviceEx failed with {:#x}!", (UINT)hresult),
" this is a common graphics / monitor issue",
" * double check any graphics options you configured in spicecfg",
" * double check that your monitor supports the resolution + refresh rate",
" combination that the game requires",
" * enable GPU-side resolution scaling in your GPU options as needed",
" * if you have three or more monitors, try unplugging them down to one or two,",
" or enable -graphics-force-single-adapter option",
" * failing all that, see if enabling windowed mode helps"
});
}
});
}
static bool is_dx9_on_12_enabled() {
bool result = false;
switch (GRAPHICS_9_ON_12_STATE) {
case DX9ON12_FORCE_OFF:
log_info("graphics::d3d9", "DirectX 9on12: forced OFF by user (-dx9on12)");
return false;
result = false;
break;
case DX9ON12_FORCE_ON:
log_info("graphics::d3d9", "DirectX 9on12: forced ON by user (-9on12 or -dx9on12)");
return true;
result = true;
break;
case DX9ON12_AUTO:
default:
@@ -219,14 +256,33 @@ static bool is_dx9_on_12_enabled() {
log_info(
"graphics::d3d9",
"DirectX 9on12: enabled automatically for current game (tip: use -dx9on12 to force on or off)");
return true;
result = true;
} else {
log_info(
"graphics::d3d9",
"DirectX 9on12: disabled by default, using DX9 (tip: use -dx9on12 to force on or off)");
return false;
result = false;
}
break;
}
if (GRAPHICS_9_ON_12_STATE == DX9ON12_FORCE_ON) {
if (avs::game::is_model("LDJ") && avs::game::is_ext(2023091500, MAXINT)) {
deferredlogs::defer_error_messages({
"dx9on12 was force enabled by user (-dx9on12)",
" IIDX31+ is known to be incompatible with DX 9on12, leading to blank screen or crashes",
" try again with -dx9on12 option set to default value"
});
} else {
deferredlogs::defer_error_messages({
"dx9on12 was force enabled by user (-dx9on12)",
" not very game is compatible with this, and can lead to crashes",
" try without force enabling this if you are seeing issues"
});
}
}
return result;
}
static IDirect3D9 *WINAPI Direct3DCreate9_hook(UINT SDKVersion) {
@@ -775,6 +831,7 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDevice(
// log error
log_info("graphics::d3d9", "IDirect3D9::CreateDevice failed, hr={}", FMT_HRESULT(ret));
log_create_device_failure(ret);
} else if (!D3D9_DEVICE_HOOK_DISABLE) {
graphics_hook_window(hFocusWindow, pPresentationParameters);
@@ -994,6 +1051,8 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDeviceEx(
// log error
log_warning("graphics::d3d9", "CreateDeviceEx failed, hr={}", FMT_HRESULT(result));
log_create_device_failure(result);
} else if (!D3D9_DEVICE_HOOK_DISABLE) {
graphics_hook_window(hFocusWindow, pPresentationParameters);
@@ -733,6 +733,16 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
const int rectTop = param.BackBufferHeight;
const int w = param.BackBufferWidth;
const int h = param.BackBufferHeight;
if (cfg::SCREENRESIZE->enable_screen_resize) {
RECT rect {
0,
0,
(LONG)topSurface_width,
(LONG)topSurface_height,
};
pReal->ColorFill(topSurface, &rect, D3DCOLOR_XRGB(0, 0, 0));
}
D3DLOCKED_RECT rect;
HRESULT hr;
@@ -750,6 +760,7 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
(LONG)(rectLeft + w),
(LONG)(rectTop + h),
};
if (GRAPHICS_FS_ORIENTATION_SWAP) {
originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2);
originRect.top = (topSurface_height / 2) - (GRAPHICS_FS_ORIGINAL_HEIGHT / 2);
@@ -757,6 +768,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
originRect.bottom = originRect.top + GRAPHICS_FS_ORIGINAL_HEIGHT;
}
bool duplicate = false;
RECT originRect2 = originRect;
if (cfg::SCREENRESIZE->enable_screen_resize) {
auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene];
if (scene.duplicate == cfg::ScreenDuplicateMode::CopyLeft) {
duplicate = true;
originRect2.right = originRect.left;
originRect2.left = (LONG)(originRect2.left - (originRect.right - originRect.left));
} else if (scene.duplicate == cfg::ScreenDuplicateMode::CopyRight) {
duplicate = true;
originRect2.left = originRect.right;
originRect2.right = (LONG)(originRect2.left + (originRect.right - originRect.left));
}
}
// log_misc(
// "graphics::d3d9", "originRect: {} {} {} {}",
// originRect.left, originRect.top, originRect.right, originRect.bottom);
@@ -768,9 +794,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
if (hr != D3D_OK) {
log_warning(
"graphics::d3d9",
"SurfaceHook - StretchRect backbuffer failed, rect: {} {} {} {}",
"SurfaceHook - StretchRect backbuffer failed for main image, rect: {} {} {} {}",
originRect.left, originRect.top, originRect.right, originRect.bottom);
}
if (duplicate) {
hr = pReal->StretchRect(
backbuffer, nullptr,
topSurface, &originRect2,
D3DTEXF_LINEAR);
if (hr != D3D_OK) {
log_warning(
"graphics::d3d9",
"SurfaceHook - StretchRect backbuffer failed for the duplicate, rect: {} {} {} {}",
originRect2.left, originRect2.top, originRect2.right, originRect2.bottom);
}
}
topSurface->UnlockRect();
// phase 2 - viewport calculation - do the actual zoom / offset math
+26
View File
@@ -8,6 +8,7 @@
#include <ntstatus.h>
#include "avs/game.h"
#include "games/iidx/iidx.h"
#include "util/detour.h"
#include "util/logging.h"
#include "util/utils.h"
@@ -22,6 +23,7 @@ static decltype(GetLocaleInfoEx) *GetLocaleInfoEx_orig = nullptr;
#ifdef SPICE64
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
static decltype(IsDBCSLeadByte) *IsDBCSLeadByte_orig = nullptr;
#endif
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
@@ -162,6 +164,17 @@ static int WINAPI GetLocaleInfoEx_hook (
return GetLocaleInfoEx_orig(lpLocaleName, LCType, lpLCData, cchData);
}
#ifdef SPICE64
static BOOL WINAPI IsDBCSLeadByte_hook (
BYTE TestChar
)
{
return IsDBCSLeadByteEx(CODEPAGE_SHIFT_JIS, TestChar);
}
#endif
void hooks::lang::early_init() {
log_info("hooks::lang", "early initialization");
@@ -189,6 +202,19 @@ void hooks::lang::early_init() {
GetLocaleInfoEx_hook,
&GetLocaleInfoEx_orig);
}
#ifdef SPICE64
// for TDJ subscreen search keyboard
if (avs::game::is_model("LDJ") && games::iidx::TDJ_MODE) {
log_info("hooks::lang", "hooking IsDBCSLeadByte");
detour::trampoline_try(
"kernel32.dll",
"IsDBCSLeadByte",
IsDBCSLeadByte_hook,
&IsDBCSLeadByte_orig);
}
#endif
}
void hooks::lang::init() {
+4
View File
@@ -141,13 +141,17 @@ static ULONG WINAPI GetAdaptersInfo_hook(PIP_ADAPTER_INFO pAdapterInfo, PULONG p
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
#ifdef __clang__
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCDFAInspection"
#endif
// cast to sockaddr_in
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
#ifdef __clang__
#pragma clang diagnostic pop
#endif
// override bind to allow all hosts
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
+92 -30
View File
@@ -20,7 +20,9 @@
#include "cfg/screen_resize.h"
#include "easrv/easrv.h"
#include "external/cardio/cardio_runner.h"
#ifndef NO_SCARD
#include "external/scard/scard.h"
#endif
#include "games/game.h"
#include "games/io.h"
#include "games/bbc/bbc.h"
@@ -97,6 +99,7 @@
#include "touch/touch.h"
#include "util/cpuutils.h"
#include "util/crypt.h"
#include "util/deferlog.h"
#include "util/fileutils.h"
#include "util/libutils.h"
#include "util/logging.h"
@@ -262,7 +265,8 @@ int main_implementation(int argc, char *argv[]) {
// detect model used to load option overrides
auto options_version = launcher::detect_gameversion(
LAUNCHER_OPTIONS->at(launcher::Options::PathToEa3Config).value
LAUNCHER_OPTIONS->at(launcher::Options::PathToEa3Config).value,
LAUNCHER_OPTIONS->at(launcher::Options::PathToBootstrap).value
);
if (!options_version.model.empty() && options_version.model.size() < 4) {
if (options_version.dest.size() == 1) {
@@ -295,22 +299,6 @@ int main_implementation(int argc, char *argv[]) {
cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config;
cfg_run = true;
}
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
options[launcher::Options::ServiceURL].is_active() &&
!cfg::CONFIGURATOR_STANDALONE) {
log_fatal(
"launcher",
"BAD EAMUSE SETTINGS ERROR\n\n\n"
"-------------------------------------------------------------------\n"
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"A service URL is set **AND** E-Amusement emulation is enabled.\n"
"Either remove the service URL, or disable E-Amusement emulation.\n"
"Otherwise you may experience problems logging in.\n"
"-------------------------------------------------------------------\n\n\n"
);
}
if (options[launcher::Options::EAmusementEmulation].value_bool()) {
avs::ea3::URL_SLASH = 1;
easrv_port = 8080;
@@ -365,6 +353,9 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::VerboseAVSLogging].value_bool()) {
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()) {
GRAPHICS_ADJUST_ORIENTATION =
(graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32();
@@ -475,6 +466,9 @@ int main_implementation(int argc, char *argv[]) {
// Disable legacy behaviour to avoid conflict
games::iidx::DISABLE_CAMS = true;
}
if (games::iidx::DISABLE_CAMS) {
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
}
@@ -812,6 +806,7 @@ int main_implementation(int argc, char *argv[]) {
for (auto &sextet : options[launcher::Options::SextetStreamPort].values_text()) {
sextet_devices.emplace_back(sextet);
}
#ifndef NO_SCARD
if (options[launcher::Options::HIDSmartCard].value_bool()) {
WINSCARD_CONFIG.cardinfo_callback = eamuse_scard_callback;
scard_threadstart();
@@ -831,6 +826,7 @@ int main_implementation(int argc, char *argv[]) {
WINSCARD_CONFIG.add_padding_to_felica = true;
}
}
#endif
if (options[launcher::Options::CardIOHIDReaderOrderFlip].value_bool()) {
CARDIO_RUNNER_FLIP = true;
}
@@ -934,6 +930,11 @@ int main_implementation(int argc, char *argv[]) {
}
if (options[launcher::Options::DisableAudioHooks].value_bool()) {
hooks::audio::ENABLED = false;
deferredlogs::defer_error_messages({
"audio hooks are forcibly disabled by user (-audiohookdisable)",
" having hooks disabled means some required audio fixes are not being applied",
" if you have audio-related crashes, you should try again after clearing this option"
});
}
if (options[launcher::Options::spice2x_DisableVolumeHook].value_bool()) {
hooks::audio::VOLUME_HOOK_ENABLED = false;
@@ -1112,6 +1113,9 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::PCNoIO].is_active()) {
games::pc::PC_NO_IO = options[launcher::Options::PCNoIO].value_bool();
}
if (options[launcher::Options::PCKnobMode].value_bool()) {
games::pc::PC_KNOB_MODE = true;
}
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
rawinput::ENABLE_SMX_STAGE = true;
}
@@ -1193,15 +1197,28 @@ int main_implementation(int argc, char *argv[]) {
}
// log
#ifdef SPICE64
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
#elif SPICE32_LARGE_ADDRESS_AWARE
log_info("launcher", "SpiceTools Bootstrap (x32) (Large Address Aware) (spice2x)");
#ifndef SPICE_LINUX
#ifdef SPICE64
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
#elif SPICE32_LARGE_ADDRESS_AWARE
log_info("launcher", "SpiceTools Bootstrap (x32 - Large Address Aware) (spice2x)");
#else
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
#endif
#else
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
#ifdef SPICE64
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x) for Linux");
#else
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x) for Linux");
#endif
#endif
log_info("launcher", "{}", VERSION_STRING);
// note: distribution of modified version of this software without providing source is GPLv3 license violation.
log_info("launcher", "spice2x is free & open source; if you paid money for it, you got scammed");
log_info("launcher", "visit https://spice2x.github.io to download the latest version for free");
// log command line arguments
std::ostringstream arguments;
for (auto &root_option : options) {
@@ -1245,18 +1262,19 @@ int main_implementation(int argc, char *argv[]) {
for (const auto &option : options) {
if (option.conflicting && option.get_definition().type != OptionType::Bool) {
conflicts += 1;
const auto& value = option.get_definition().sensitive ? "*****" : option.value;
if (launcher::USE_CMD_OVERRIDE) {
log_warning(
"launcher",
"multiple values for -{}, command line args take precedence: {}",
option.get_definition().name,
option.value);
value);
} else {
log_warning(
"launcher",
"multiple values for -{}, spicecfg values take precedence: {}",
option.get_definition().name,
option.value);
value);
}
}
}
@@ -1285,6 +1303,25 @@ int main_implementation(int argc, char *argv[]) {
);
}
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
options[launcher::Options::ServiceURL].is_active() &&
!cfg::CONFIGURATOR_STANDALONE) {
log_warning(
"launcher",
"BAD EAMUSE SETTINGS ERROR\n\n\n"
"-------------------------------------------------------------------\n"
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"A service URL is set **AND** E-Amusement emulation is enabled.\n"
"Either remove the service URL, or disable E-Amusement emulation.\n"
"Otherwise you may experience problems logging in.\n"
"-------------------------------------------------------------------\n\n\n"
);
log_fatal(
"launcher",
"BAD EAMUSE SETTINGS ERROR: both -ea and -url are set");
}
if (options[launcher::Options::FullscreenResolution].is_active()) {
std::pair<uint32_t, uint32_t> result;
if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) {
@@ -1369,7 +1406,11 @@ int main_implementation(int argc, char *argv[]) {
log_info("launcher", "loading early hook DLL {}", hook);
HMODULE module;
if (!(module = libutils::try_library(hook))) {
log_warning("launcher", "failed to load early hook {}", hook);
log_warning("launcher", "failed to load early hook {}: {}", hook, get_last_error_string());
deferredlogs::defer_error_messages({
fmt::format("failed to load early hook {}:", hook),
fmt::format(" {}", get_last_error_string())
});
}
}
@@ -1636,6 +1677,14 @@ int main_implementation(int argc, char *argv[]) {
attach_io = true;
attach_mfc = true;
break;
// Mahjong Fight Club - 2025?
// they removed allinone.dll and moved i/o into system.dll
} else if (check_dll("system.dll") && fileutils::file_exists("data/mfc.ini")) {
avs::game::DLL_NAME = "system.dll";
attach_io = true;
attach_mfc = true;
break;
}
// FutureTomTom
@@ -1780,7 +1829,7 @@ int main_implementation(int argc, char *argv[]) {
// usage error
if (!cfg::CONFIGURATOR_STANDALONE
&& (!CHECK_DLL_IGNORE_ARCH)) {
log_fatal(
log_warning(
"launcher",
"module auto detection failed!\n\n"
"This usually means one of the following:\n\n"
@@ -1788,6 +1837,8 @@ int main_implementation(int argc, char *argv[]) {
" 2. XML files in prop directory are malformed or missing, or\n"
" 3. You passed in invalid options (usually, path overrides like -exec)\n\n"
);
log_fatal("launcher", "module auto detection failed, see log.txt for troubleshooting");
}
break;
@@ -1964,6 +2015,7 @@ int main_implementation(int argc, char *argv[]) {
libutils::warn_if_dll_exists("nvcuvid.dll");
libutils::warn_if_dll_exists("nvEncodeAPI64.dll");
libutils::warn_if_dll_exists("msvcr100.dll");
libutils::warn_if_dll_exists("dsound.dll");
// complain loudly & early about dll load ordering issue
libutils::check_duplicate_dlls();
@@ -2148,7 +2200,11 @@ int main_implementation(int argc, char *argv[]) {
log_info("launcher", "loading hook DLL {}", hook);
HMODULE module;
if (!(module = libutils::try_library(hook))) {
log_warning("launcher", "failed to load hook {}", hook);
log_warning("launcher", "failed to load hook {}: {}", hook, get_last_error_string());
deferredlogs::defer_error_messages({
fmt::format("failed to load hook {}:", hook),
fmt::format(" {}", get_last_error_string())
});
} else {
bt5api_hook(module);
}
@@ -2157,9 +2213,13 @@ int main_implementation(int argc, char *argv[]) {
// layeredfs
if (fileutils::dir_exists("data_mods") &&
GetModuleHandleA("ifs_hook.dll") == nullptr) {
log_warning("launcher", "data_mods directory was found, but ifs_hook.dll is not present; your mods will not load");
log_warning("launcher", "to fix this, download ifs_layeredfs and add it as a DLL hook (-k)");
log_warning("launcher", "https://github.com/mon/ifs_layeredfs");
log_warning("launcher", "data_mods directory found, but ifs_hook.dll is not present; mods will not load");
deferredlogs::defer_error_messages({
"data_mods directory was found, but ifs_hook.dll is not present",
" your mods will not load",
" to fix this, download ifs_layeredfs and add it as a DLL hook (-k)",
" https://github.com/mon/ifs_layeredfs"
});
}
// apply patches
@@ -2294,8 +2354,10 @@ int main_implementation(int argc, char *argv[]) {
// debug hook
debughook::detach();
#ifndef NO_SCARD
// scard
scard_fini();
#endif
// stop reader thread in case it was running
stop_reader_thread();
+73 -24
View File
@@ -6,6 +6,12 @@
#include <fstream>
#ifdef NO_SCARD
#define WITH_SCARD 0
#else
#define WITH_SCARD 1
#endif
static const std::vector<std::string> CATEGORY_ORDER_API = {
"SpiceCompanion and API",
"API (Serial)",
@@ -359,7 +365,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.name = "r",
.desc = "Set custom SOFTID override",
.type = OptionType::Text,
.category = "Network (Development)",
.category = "Development",
.sensitive = true,
},
{
@@ -554,10 +560,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options",
},
{
.title = "IIDX BIO2 Firmware",
.title = "IIDX BIO2 Firmware Update",
.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,
.hidden = true,
.game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)",
},
@@ -1049,7 +1056,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
},
{
// LoadCCJModule
.title = "Force Load Chase Chase Jokers",
.title = "Force Load Chase Chase Jokers Module",
.name = "ccj",
.desc = "manually enable Chase Chase Jokers module",
.type = OptionType::Bool,
@@ -1058,7 +1065,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
},
{
// LoadQKSModule
.title = "Force Load QuizKnock STADIUM",
.title = "Force Load QuizKnock STADIUM Module",
.name = "qks",
.desc = "manually enable QuizKnock STADIUM module",
.type = OptionType::Bool,
@@ -1067,7 +1074,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
},
{
// LoadMFGModule
.title = "Force Load Mahjong Fight Girl",
.title = "Force Load Mahjong Fight Girl Module",
.name = "mfg",
.desc = "manually enable Mahjong Fight Girl module",
.type = OptionType::Bool,
@@ -1076,7 +1083,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
},
{
// LoadPCModule
.title = "Force Load Polaris Chord",
.title = "Force Load Polaris Chord Module",
.name = "pc",
.desc = "manually enable Polaris Chord module",
.type = OptionType::Bool,
@@ -1085,7 +1092,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
},
{
// LoadMusecaModule
.title = "Force Load Museca",
.title = "Force Load Museca Module",
.name = "museca",
.desc = "manually enable Museca module",
.type = OptionType::Bool,
@@ -1135,11 +1142,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Path Overrides",
},
{
.title = "Intel SDE Folder",
.title = "Intel SDE",
.name = "sde",
.desc = "Path to Intel SDE kit path for automatic attaching",
.type = OptionType::Text,
.category = "Path Overrides",
.category = "Development",
},
{
.title = "ea3-config.xml Override",
@@ -1384,21 +1391,27 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.name = "scard",
.desc = "Detects and uses HID smart card readers for card input. Developed for ACR122U reader",
.type = OptionType::Bool,
.hidden = !WITH_SCARD,
.category = "NFC Card Readers",
.disabled = !WITH_SCARD,
},
{
.title = "HID SmartCard Order Flip",
.name = "scardflip",
.desc = "Flips the order of detection for P1/P2",
.type = OptionType::Bool,
.hidden = !WITH_SCARD,
.category = "NFC Card Readers",
.disabled = !WITH_SCARD,
},
{
.title = "HID SmartCard Order Toggle",
.name = "scardtoggle",
.desc = "Toggles reader between P1/P2 using the NumLock key state",
.type = OptionType::Bool,
.hidden = !WITH_SCARD,
.category = "NFC Card Readers",
.disabled = !WITH_SCARD,
},
{
// HIDSmartCardIdConvert
@@ -1412,12 +1425,14 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
"For example, abcd56780123 is converted to e00401abcd567801 on card in. This results in different card numbers so "
"be careful when connecting to servers!",
.type = OptionType::Enum,
.hidden = !WITH_SCARD,
.category = "NFC Card Readers",
.elements = {
{"legacy", "Use cards as-is"},
{"fix", "Fix bad cards only"},
{"all", "Force all cards"},
},
.disabled = !WITH_SCARD,
},
{
// SextetStreamPort
@@ -1544,10 +1559,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.title = "Spice Audio Hook Backend",
.name = "audiobackend",
.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,
.category = "Audio",
.elements = {{"asio", "ASIO"}, {"waveout", "waveOut"}},
.elements = {
{"asio", "ASIO"},
{"waveout", "broken, do not use"}
},
},
{
.title = "Spice Audio Hook ASIO Driver ID",
@@ -1672,6 +1690,16 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.type = OptionType::Bool,
.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",
.name = "nocolor",
@@ -1806,6 +1834,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options (Advanced)"
},
{
// PCArgs
.title = "PC Arguments Override",
.name = "pcargs",
.desc = "Command line arguments passed to the game.",
@@ -1815,6 +1844,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options (Advanced)",
},
{
// PCNoIO
.title = "PC Disable IO Emulation",
.name = "pcnoio",
.desc = "Disables BI2X hooks for PC",
@@ -1823,6 +1853,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.game_name = "Polaris Chord",
.category = "Game Options (Advanced)"
},
{
// PCKnobMode
.title = "PC Fader Knobs Mode",
.name = "pcknobs",
.desc = "Allows SDVX knobs and IIDX turntables to be bound as Polaris Chord faders",
.type = OptionType::Bool,
.game_name = "Polaris Chord",
.category = "Game Options",
},
{
// spice2x_LightsOverallBrightness
.title = "Lights Brightness Adjustment",
@@ -2364,7 +2403,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.type = OptionType::Bool,
.category = "Development",
.disabled = true,
},
}
};
const std::vector<std::string> &launcher::get_categories(Options::OptionsCategory category) {
@@ -2445,7 +2484,7 @@ std::unique_ptr<std::vector<Option>> launcher::parse_options(int argc, char *arg
} else {
// validate it is an integer
try {
std::stoull(argv[i], nullptr, 16);
auto _ = std::stoull(argv[i], nullptr, 16);
} catch (const std::exception &ex) {
log_fatal("options", "parameter for -{} is not a hex number: {}", alias, argv[i]);
}
@@ -2583,8 +2622,19 @@ std::vector<Option> launcher::merge_options(
return merged;
}
std::string launcher::detect_bootstrap_release_code() {
std::string bootstrap_path = "prop/bootstrap.xml";
std::string launcher::detect_bootstrap_release_code(const std::string& bootstrap_user) {
std::string bootstrap_path;
if (!bootstrap_user.empty()) {
bootstrap_path = bootstrap_user;
} else if (fileutils::file_exists("prop/bootstrap.xml")) {
bootstrap_path = "prop/bootstrap.xml";
}
if (bootstrap_path.empty()) {
log_warning("options", "unable to detect bootstrap.xml file");
return "";
}
// load XML
tinyxml2::XMLDocument bootstrap;
@@ -2607,7 +2657,7 @@ std::string launcher::detect_bootstrap_release_code() {
return "";
}
static launcher::GameVersion detect_gameversion_ident() {
static launcher::GameVersion detect_gameversion_ident(const std::string& bootstrap_user) {
// detect ea3-ident path
std::string ident_path;
@@ -2653,7 +2703,7 @@ static launcher::GameVersion detect_gameversion_ident() {
auto node_ext = node_soft->FirstChildElement("ext");
if (node_ext) {
version.ext = node_ext->GetText();
auto bootstrap_ext = launcher::detect_bootstrap_release_code();
auto bootstrap_ext = launcher::detect_bootstrap_release_code(bootstrap_user);
if (version.ext.size() != 10 && bootstrap_ext.size() == 10) {
version.ext = bootstrap_ext;
} else if (bootstrap_ext.size() == 10) {
@@ -2689,8 +2739,7 @@ static launcher::GameVersion detect_gameversion_ident() {
return launcher::GameVersion();
}
launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user) {
launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user, const std::string& bootstrap_user) {
// detect ea3-config path
std::string ea3_path;
if (!ea3_user.empty()) {
@@ -2704,7 +2753,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
}
if (ea3_path.empty()) {
log_warning("options", "unable to detect EA3 configuration file");
return detect_gameversion_ident();
return detect_gameversion_ident(bootstrap_user);
}
// load XML
@@ -2744,7 +2793,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
if (ea3_config.Parse(xml_str.c_str()) != tinyxml2::XML_SUCCESS) {
// if we still failed, give up
log_warning("options", "unable to parse fixed xml");
return detect_gameversion_ident();
return detect_gameversion_ident(bootstrap_user);
}
}
@@ -2775,7 +2824,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
auto node_ext = node_soft->FirstChildElement("ext");
if (node_ext) {
version.ext = node_ext->GetText();
auto bootstrap_ext = launcher::detect_bootstrap_release_code();
auto bootstrap_ext = launcher::detect_bootstrap_release_code(bootstrap_user);
if (version.ext.size() != 10 && bootstrap_ext.size() == 10) {
version.ext = bootstrap_ext;
} else if (bootstrap_ext.size() == 10) {
@@ -2808,5 +2857,5 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
// error
log_warning("options", "unable to find /ea3/soft/model in {}", ea3_path);
return detect_gameversion_ident();
return detect_gameversion_ident(bootstrap_user);
}
+4 -2
View File
@@ -188,6 +188,7 @@ namespace launcher {
DebugCreateFile,
VerboseGraphicsLogging,
VerboseAVSLogging,
AllowEA3Verbose,
DisableColoredOutput,
DisableACPHook,
DisableSignalHandling,
@@ -205,6 +206,7 @@ namespace launcher {
MFGNoIO,
PCArgs,
PCNoIO,
PCKnobMode,
spice2x_LightsOverallBrightness,
spice2x_WindowBorder,
spice2x_WindowSize,
@@ -277,6 +279,6 @@ namespace launcher {
std::string ext;
};
std::string detect_bootstrap_release_code();
GameVersion detect_gameversion(const std::string& ea3_user);
std::string detect_bootstrap_release_code(const std::string& bootstrap_user);
GameVersion detect_gameversion(const std::string& ea3_user, const std::string& bootstrap_user);
}
+4
View File
@@ -7,6 +7,7 @@
#include "easrv/easrv.h"
#include "rawinput/rawinput.h"
#include "hooks/audio/audio.h"
#include "util/deferlog.h"
#include "util/logging.h"
#include "launcher.h"
@@ -21,6 +22,9 @@ namespace launcher {
// therefore, subsystems need to be guarded against multiple unload attempts
log_info("launcher", "stopping subsystems");
// before shutting down logger, dump any deferred log messages
deferredlogs::dump_to_logger();
// flush/stop logger
logger::stop();
+29 -10
View File
@@ -1,7 +1,7 @@
#include "signal.h"
#include <future>
#include <exception>
#include <string>
#include <windows.h>
#include <dbghelp.h>
@@ -10,6 +10,7 @@
#include "external/stackwalker/stackwalker.h"
#include "hooks/libraryhook.h"
#include "launcher/shutdown.h"
#include "util/deferlog.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
@@ -98,19 +99,34 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
// print signal
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
switch (ExceptionRecord->ExceptionCode) {
case EXCEPTION_ILLEGAL_INSTRUCTION:
deferredlogs::defer_error_messages({
"illegal instruction exception:",
" 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;
}
// check ACIO init failures
if (acio::IO_INIT_IN_PROGRESS) {
log_warning(
"signal",
"exception raised during ACIO init, this usually happens when a third party application interferes with hooks");
log_warning(
"signal",
" please check for the following, disable them, and try launching the game again:");
log_warning(
"signal",
" RivaTuner Statistics Server (RTSS), MSI Afterburner, kernel mode anti-cheat");
deferredlogs::defer_error_messages({
"exception raised during ACIO init, this usually happens when ",
" a third party application interferes with hooks",
" please check for the following, disable them, and try launching the game again:",
" * RivaTuner Statistics Server (RTSS)",
" * MSI Afterburner",
" * kernel mode anti-cheat"
});
}
// dump deferred logs BEFORE stack trace since some errors cause stack trace logic to hang
// (e.g., ACIO init hang due to RTSS)
deferredlogs::dump_to_logger(true);
// walk the exception chain
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
while (record_cause != nullptr) {
@@ -159,6 +175,9 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
log_warning("signal", "minidump creation function not available, skipping");
}
// this will stall all UI threads for this process
show_popup_for_crash();
log_fatal("signal", "end");
}
+3 -1
View File
@@ -1,12 +1,14 @@
#pragma once
#include <string>
#include <cstdint>
namespace launcher::signal {
// settings
extern bool DISABLE;
extern bool USE_VEH_WORKAROUND;
//void print_stacktrace();
void attach();
void init();
}
+1 -1
View File
@@ -162,7 +162,7 @@ static void __cdecl cardunit_update() {
bool kb_insert_press = false;
// eamio keypress
kb_insert_press |= eamuse_get_keypad_state(unit) & (1 << EAM_IO_INSERT);
kb_insert_press |= static_cast<bool>(eamuse_get_keypad_state(unit) & (1 << EAM_IO_INSERT));
// update card inserts
if (eamuse_card_insert_consume((int) EXTDEV_CARDUNIT_COUNT, unit) ||
+4 -3
View File
@@ -270,13 +270,14 @@ void overlay::SpiceOverlay::init() {
ImFontConfig config {};
config.MergeMode = true;
log_misc("overlay", "loading fonts, failures are not fatal");
add_font("simsun.ttc", &config, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesCyrillic());
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesCyrillic());
add_font("meiryu.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
add_font("meiryo.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
add_font("gulim.ttc", &config, io.Fonts->GetGlyphRangesKorean());
add_font("cordia.ttc", &config, io.Fonts->GetGlyphRangesThai());
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesVietnamese());
add_font("cordia.ttf", &config, io.Fonts->GetGlyphRangesThai());
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesVietnamese());
// add special font
if (avs::game::is_model("LDJ")) {
+30 -33
View File
@@ -556,9 +556,16 @@ namespace overlay::windows {
}
// disclaimer
// note: distribution of modified version of this software without providing source is GPLv3 license violation.
ImGui::TextColored(
ImVec4(1, 0.5f, 0.5f, 1.f),
"Do NOT stream or upload game data anywhere public! Support arcades when you can. Thanks.");
"spice2x is free & open source; if you paid money for it, you got scammed.");
if (cfg::CONFIGURATOR_STANDALONE) {
ImGui::SameLine();
if (ImGui::TextLink(PROJECT_URL)) {
launch_shell(PROJECT_URL);
}
}
}
void Config::build_buttons(const std::string &name, std::vector<Button> *buttons, int min, int max) {
@@ -2633,17 +2640,16 @@ namespace overlay::windows {
// check hidden option
if (!this->options_show_hidden && option.value.empty()) {
// skip hidden entries
if (definition.hidden) {
continue;
}
// check for game exclusivity
if (!definition.game_name.empty()) {
if (definition.game_name != this->games_selected_name) {
continue;
}
}
// check for game exclusivity
if (!definition.game_name.empty()) {
if (definition.game_name != this->games_selected_name) {
continue;
}
}
@@ -2905,26 +2911,28 @@ namespace overlay::windows {
}
void Config::build_about() {
#ifndef SPICE_LINUX
ImGui::TextUnformatted(std::string(
"spice2x (a fork of SpiceTools)\r\n"
"=========================\r\n" +
to_string(VERSION_STRING)).c_str());
#else
ImGui::TextUnformatted(std::string(
"spice2x (a fork of SpiceTools) for Linux\r\n"
"=========================\r\n" +
to_string(VERSION_STRING)).c_str());
#endif
ImGui::TextUnformatted("");
if (ImGui::Button(PROJECT_URL)) {
if (ImGui::TextLink(PROJECT_URL)) {
launch_shell(PROJECT_URL);
}
ImGui::TextUnformatted("");
ImGui::TextUnformatted(std::string(
resutil::load_file_string_crlf(IDR_README) +
"\r\n" +
"Changelog (Highlights):\r\n" +
resutil::load_file_string_crlf(IDR_CHANGELOG)).c_str());
}
void Config::build_licenses() {
ImGui::TextUnformatted(resutil::load_file_string_crlf(IDR_README).c_str());
ImGui::TextUnformatted("");
ImGui::TextUnformatted("");
ImGui::TextUnformatted("Licenses:");
ImGui::TextUnformatted(resutil::load_file_string_crlf(IDR_LICENSES).c_str());
}
@@ -2977,7 +2985,7 @@ namespace overlay::windows {
void Config::build_menu(int *game_selected) {
bool about_popup = false;
bool licenses_popup = false;
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.14f, 0.14f, 0.14f, 1.0f));
if (ImGui::BeginMenuBar()) {
// [spice2x]
@@ -2987,9 +2995,6 @@ namespace overlay::windows {
if (ImGui::MenuItem("spice2x.github.io")) {
launch_shell(PROJECT_URL);
}
if (ImGui::MenuItem("Licenses")) {
licenses_popup = true;
}
if (ImGui::MenuItem("About")) {
about_popup = true;
}
@@ -3041,13 +3046,12 @@ namespace overlay::windows {
ImGui::EndMenuBar();
}
ImGui::PopStyleColor(); // ImGuiCol_PopupBg
// workaround for popups triggered by menu, see https://github.com/ocornut/imgui/issues/331
if (about_popup) {
ImGui::OpenPopup("About##topbarpopup");
}
if (licenses_popup) {
ImGui::OpenPopup("Licenses##topbarpopup");
}
// draw popups
{
@@ -3066,13 +3070,6 @@ namespace overlay::windows {
this->build_about();
ImGui::EndPopup();
}
ImGui::SetNextWindowSize(popup_size, ImGuiCond_Appearing);
ImGui::SetNextWindowPos(popup_pos, ImGuiCond_Appearing);
bool unused_open3 = true;
if (ImGui::BeginPopupModal("Licenses##topbarpopup", &unused_open3)) {
this->build_licenses();
ImGui::EndPopup();
}
}
}
}
-1
View File
@@ -93,7 +93,6 @@ namespace overlay::windows {
void build_options(
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr);
void build_about();
void build_licenses();
void build_launcher();
void launch_shell(LPCSTR app, LPCSTR file=nullptr);
-22
View File
@@ -70,7 +70,6 @@ namespace overlay::windows {
raw_input_view();
touch_view();
lcd_view();
about_view();
ddr_timing_view();
iidx_effectors_view();
}
@@ -788,27 +787,6 @@ namespace overlay::windows {
}
}
void Control::about_view() {
if (ImGui::CollapsingHeader("About")) {
if (ImGui::TreeNode("Changelog")) {
ImGui::Separator();
if (ImGui::BeginChild("changelog", ImVec2(400, 400))) {
ImGui::TextUnformatted(resutil::load_file_string(IDR_CHANGELOG).c_str());
}
ImGui::EndChild();
}
if (ImGui::TreeNode("Licenses")) {
ImGui::Separator();
if (ImGui::BeginChild("changelog", ImVec2(400, 400), false,
ImGuiWindowFlags_HorizontalScrollbar
| ImGuiWindowFlags_AlwaysHorizontalScrollbar)) {
ImGui::TextUnformatted(resutil::load_file_string(IDR_LICENSES).c_str());
}
ImGui::EndChild();
}
}
}
void Control::ddr_timing_view() {
if (avs::game::is_model("MDX") && ImGui::CollapsingHeader("DDR Timing")) {
@@ -4,6 +4,7 @@
#include <fmt/format.h>
#include "avs/game.h"
#include "games/io.h"
#include "cfg/screen_resize.h"
#include "hooks/graphics/backends/d3d9/d3d9_backend.h"
@@ -88,13 +89,32 @@ namespace overlay::windows {
void GenericSubScreen::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {}
void GenericSubScreen::build_content() {
this->flags |= ImGuiWindowFlags_NoBackground;
if (this->disabled_message.has_value()) {
this->flags &= ~ImGuiWindowFlags_NoBackground;
ImGui::TextColored(YELLOW, "%s", this->disabled_message.value().c_str());
return;
}
this->draw_texture();
if (!this->texture) {
this->flags &= ~ImGuiWindowFlags_NoBackground;
ImGui::TextColored(YELLOW, "Failed to acquire surface texture for subscreen.");
if (avs::game::is_model("LDJ")) {
ImGui::TextColored(
YELLOW,
"Ensure that you are using the correct DLL type, \n"
"or patch the DLL to properly enable TDJ mode.");
} else if (avs::game::is_model("KFC")) {
ImGui::TextColored(
YELLOW,
"Ensure that you did not accidentally enable a patch \n"
"that turns off subscreen rendering.");
}
}
#if OVERLAYDBG
if (this->status_message.has_value()) {
log_warning("sub::overlay", "{}", this->status_message.value().c_str());
+1 -1
View File
@@ -14,7 +14,7 @@ namespace overlay::windows {
if (GRAPHICS_IIDX_WSUB) {
this->disabled_message =
"Close this overlay and use the second window.\n"
"Or, turn on -iidxnosub to use the overlay instead.";
"If you don't see the window, double check your DLL type and apply TDJ I/O patches as needed.";
this->draws_window = false;
}
@@ -80,7 +80,7 @@ namespace overlay::windows {
{"arkmmd.dll", {"gamemmd.dll"}},
{"arkklp.dll", {"lpac.dll"}},
{"arknck.dll", {"weac.dll"}},
{"gdxg.dll", {"game.dll", "libshare-pj.dll"}}
{"gdxg.dll", {"game.dll", "libshare-pj.dll", "boot.dll"}}
};
static size_t url_recent_idx = -1;
@@ -55,6 +55,7 @@ namespace overlay::windows {
scene.offset_y = 0;
scene.scale_x = 1.f;
scene.scale_y = 1.f;
scene.duplicate = cfg::ScreenDuplicateMode::None;
}
cfg::SCREENRESIZE->enable_window_resize = false;
@@ -149,6 +150,17 @@ namespace overlay::windows {
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
}
static const char* dupe_items[] = { "None", "Copy Left", "Copy Right" };
ImGui::Combo(
"Duplicate",
reinterpret_cast<int *>(&scene.duplicate),
dupe_items,
ARRAYSIZE(dupe_items));
ImGui::SameLine();
ImGui::HelpMarker(
"Show an identical copy of the image on the left or right, allowing you to achieve "
"wrap-around effect when an offset is set.");
ImGui::EndDisabled();
}
+1
View File
@@ -3,6 +3,7 @@ developers when you can. Sources should be included, have fun!
spice2x fork maintainers:
* sp2xdev team
* the lab
SpiceTools original contributors:
* cube, felix, dinsfire, nolm, s2, crazyredmachine (jotaro44), mon, nibs
+75
View File
@@ -0,0 +1,75 @@
#include <mutex>
#include <atomic>
#include "build/defs.h"
#include "deferlog.h"
#include "util/logging.h"
namespace deferredlogs {
const std::initializer_list<std::string> SUPERSTEP_SOUND_ERROR_MESSAGE = {
"audio initialization error was previously detected during boot!",
" this crash is most likely related to audio init failure",
" * check if the default audio device has changed",
" * fix your audio device settings (e.g., sample rate)",
" * double check your spice audio options and patches"
};
std::mutex deferred_errors_mutex;
std::vector<std::vector<std::string>> deferred_errors;
void defer_error_messages(std::initializer_list<std::string> messages) {
std::lock_guard<std::mutex> lock(deferred_errors_mutex);
deferred_errors.emplace_back(messages);
}
void dump_to_logger(bool is_crash) {
static std::once_flag printed;
std::call_once(printed, [is_crash]() {
// move to a local vector under lock first
// this is to avoid holding a lock while emitting to the logger, which may deadlock
// due to recursive calls (e.g., via log hooks used for failure detection which then
// again calls into defer_error_messages), and std::mutex cannot be acquired recursively
std::vector<std::vector<std::string>> errors;
{
std::lock_guard<std::mutex> lock(deferred_errors_mutex);
if (deferred_errors.empty() && !is_crash) {
return;
}
errors = std::move(deferred_errors);
}
std::string msg;
msg += "\n\n";
msg += "/-------------------------- spice2x auto-troubleshooter -----------------------\\\n";
msg += "\n";
msg += " spice2x version: " + to_string(VERSION_STRING_CFG) + "\n";
msg += "\n";
if (is_crash) {
msg += " the game has crashed\n";
msg += " share this entire log file with someone for troubleshooting (log.txt)\n";
msg += " spice will also attempt to create a minidump (minidump.dmp)\n";
msg += "\n";
}
for (auto messages : errors) {
for (auto message : messages) {
msg += " " + message + "\n";
}
msg += "\n";
}
msg += " unsure what to do next?\n";
msg += " * update to the latest version:\n";
msg += " https://github.com/spice2x/spice2x.github.io/releases/latest\n";
msg += " * check the FAQ:\n";
msg += " https://github.com/spice2x/spice2x.github.io/wiki/Known-issues\n";
msg += "\n";
msg += "\\------------------------- spice2x auto-troubleshooter ------------------------/\n";
log_warning("troubleshooter", "{}", msg);
});
}
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <string>
#include <vector>
#include <initializer_list>
namespace deferredlogs {
// some shared error messages
extern const std::initializer_list<std::string> SUPERSTEP_SOUND_ERROR_MESSAGE;
void defer_error_messages(std::initializer_list<std::string> messages);
void dump_to_logger(bool is_crash=false);
}
+151
View File
@@ -0,0 +1,151 @@
#include <set>
#include "logging.h"
#include "libutils.h"
#include "scope_guard.h"
#include "dependencies.h"
using loader_hint = std::tuple<std::string, std::string, std::string>;
namespace {
// list of commonly missing dependencies and tips on where to get them
std::vector<loader_hint> hints = {
{
"msvcr100.dll",
"Visual Studio 2010 (VC++ 10.0) SP1 Redistributable",
"Download and install VisualCppRedist_AIO_x86_x64.exe from https://github.com/abbodi1406/vcredist/releases/latest",
},
{
"d3dx9_43.dll",
"DirectX End-User Runtimes",
"Download and install from https://www.microsoft.com/en-us/download/details.aspx?id=35"
},
{
"nvEncodeAPI64.dll",
"NVIDIA Graphics Driver",
"For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.",
},
{
"nvcuda.dll",
"NVIDIA Graphics Driver",
"For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.",
},
{
"nvcuvid.dll",
"NVIDIA Graphics Driver",
"For non-NVIDIA GPUs, copy the stub file from the spice2x release .zip.",
},
{
"cpusbxpkm.dll",
"LovePlus Printer DLL",
"Copy the stub file from the spice2x release .zip.",
},
};
std::set<std::wstring> failed = {};
auto read_imports(const std::filesystem::path& path) -> std::vector<std::filesystem::path> {
auto result = std::vector<std::filesystem::path> {};
auto const file = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (file == INVALID_HANDLE_VALUE) {
return result;
}
auto const file_ = scope_guard { [file] { CloseHandle(file); } };
auto const mapping = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (!mapping) {
return result;
}
auto const mapping_ = scope_guard { [mapping] { CloseHandle(mapping); } };
auto const view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
if (!view) {
return result;
}
auto const view_ = scope_guard { [view] { UnmapViewOfFile(view); } };
auto const dos = static_cast<PIMAGE_DOS_HEADER>(view);
if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
return result;
}
auto const base = static_cast<std::uint8_t*>(view);
auto const nt = reinterpret_cast<PIMAGE_NT_HEADERS>(base + dos->e_lfanew);
if (nt->Signature != IMAGE_NT_SIGNATURE) {
return result;
}
auto const imports = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (imports.VirtualAddress == 0) {
return result;
}
auto desc = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(base + libutils::rva2offset(nt, imports.VirtualAddress));
while (desc->Name != 0) {
auto const filename = reinterpret_cast<char*>(base + libutils::rva2offset(nt, desc->Name));
auto entry_path = path.parent_path().append(filename);
// try to use library in the same directory if one exists
// otherwise, assume system library and use filename only
if (!std::filesystem::exists(entry_path)) {
entry_path = filename;
}
result.emplace_back(entry_path);
desc++;
}
return result;
}
}
namespace dependencies {
auto walk(const std::filesystem::path& path, const std::string& prefix) -> bool {
// try to load the library -- skip walking if it loads successfully
if (auto const module = LoadLibraryW(path.c_str())) {
FreeLibrary(module);
return true;
}
auto const error = GetLastError();
auto const filename = path.filename().string();
log_misc("dependencies", "{}{}", prefix + (prefix.empty() ? "": "|-- "), filename);
if (failed.contains(path)) {
return false;
}
failed.insert(path);
auto const dependencies = read_imports(path);
auto const next_prefix = prefix + (prefix.empty() ? " ": "| ");
if (!dependencies.empty()) {
for (auto const& item : dependencies) {
walk(item, next_prefix);
}
return false;
}
for (auto const& [dll, name, hint] : hints) {
if (_stricmp(dll.c_str(), filename.c_str()) != 0) {
continue;
}
log_warning("dependencies", "{}|-- [!] {}", next_prefix, name.c_str());
log_warning("dependencies", "{}|-- {}", next_prefix, hint.c_str());
return false;
}
log_warning("dependencies", "{}|-- [!] The library could not be loaded. ({})", next_prefix, error);
return false;
}
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <string>
#include <filesystem>
namespace dependencies {
auto walk(const std::filesystem::path& path, const std::string& prefix = "") -> bool;
}
+4
View File
@@ -106,8 +106,10 @@ bool detour::inline_restore(void *address, char *data) {
#endif
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCDFAInspection"
#endif
static void *pe_offset(void *ptr, size_t offset) {
if (offset == 0) {
@@ -282,7 +284,9 @@ void **detour::iat_find_proc(const char *iid_name, void *proc, HMODULE module) {
return nullptr;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
void *detour::iat_try(const char *function, void *new_func, HMODULE module, const char *iid_name) {
+15 -14
View File
@@ -8,6 +8,7 @@
#include "utils.h"
#include "peb.h"
#include "util/fileutils.h"
#include "util/dependencies.h"
std::filesystem::path libutils::module_file_name(HMODULE module) {
std::wstring buf;
@@ -29,22 +30,21 @@ std::filesystem::path libutils::module_file_name(HMODULE module) {
static inline void load_library_fail(const std::string &file_name, bool fatal) {
std::string info_str { fmt::format(
"\n\nPlease check if {} exists and the permissions are fine.\n"
"\n"
"* If the problem still persists, try installing things on this list:\n"
" https://github.com/spice2x/spice2x.github.io/wiki/DLL-Dependencies \n"
"\n"
"* Still have problems after installing from above and rebooting PC?\n"
" Avoid manually specifying DLL path (-exec) and module directory (-modules); let spice2x auto-detect unless you have a good reason not to\n"
" Ensure you do NOT have multiple copies of the game DLLs (e.g., in contents and in contents\\modules)\n"
" Certain games require specific NVIDIA DLLs when running with AMD/Intel GPUs (hint: look inside stub directory for DLLs)\n"
"\n"
"* (For advanced users) if none of the above helps, find the missing dependency using:\n"
" https://github.com/lucasg/Dependencies (recommended for most) \n"
" http://www.dependencywalker.com/ (for old OS) \n"
"DLL failed to load - this is a common error. Please carefully read ALL of the following steps for a fix:\n"
" 1. Confirm if the file ({}) exists on the disk and check the file permissions.\n"
" 2. Follow this link and install DLL prerequisites on this list:\n"
" https://github.com/spice2x/spice2x.github.io/wiki/DLL-Dependencies \n"
" 3. 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"
" b. 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"
" 4. (For advanced users) if none of the above helps, find the missing dependency using:\n"
" a. https://github.com/lucasg/Dependencies (recommended for most) \n"
" b. http://www.dependencywalker.com/ (for old OS) \n"
, file_name) };
if (fatal) {
log_fatal("libutils", "{}", info_str);
log_warning("libutils", "{}", info_str);
log_fatal("libutils", "DLL failed to load: {}, see log.txt for troubleshooting", file_name);
} else {
log_warning("libutils", "{}", info_str);
}
@@ -67,6 +67,7 @@ HMODULE libutils::load_library(const std::filesystem::path &path, bool fatal) {
if (!module) {
log_warning("libutils", "'{}' couldn't be loaded: {}", path.string(), get_last_error_string());
dependencies::walk(path);
load_library_fail(path.filename().string(), fatal);
}
+69
View File
@@ -1,4 +1,10 @@
#include <atomic>
#include <chrono>
#include <future>
#include "logging.h"
#include "build/defs.h"
#include "hooks/graphics/graphics.h"
std::string_view log_get_datetime() {
return log_get_datetime(time(nullptr));
@@ -12,3 +18,66 @@ std::string_view log_get_datetime(std::time_t now) {
return buf;
}
static void show_popup(const std::string text) {
static std::once_flag shown;
std::call_once(shown, [text]() {
// minimize all windows
// only needed because in multi-monitor full screen games, MessageBox fails to show above the game
for (auto &hwnd : GRAPHICS_WINDOWS) {
ShowWindow(hwnd, SW_FORCEMINIMIZE);
}
// schedule a worker to terminate the game in 30 seconds in case user can't dismiss UI
std::atomic_bool cancel_popup = false;
auto worker = std::async(std::launch::async, [&cancel_popup]{
for (int ms = 300; ms > 0; ms--) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (cancel_popup) {
return;
}
}
launcher::stop_subsystems();
launcher::kill();
std::terminate();
});
// MessageBox will block until user presses OK
const std::string title = "spice2x (" + to_string(VERSION_STRING_CFG) + ")";
MessageBox(
nullptr,
text.c_str(),
title.c_str(),
MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);
// cancel the worker since the user acknowledged the popup
cancel_popup = true;
});
}
void show_popup_for_crash() {
std::string text;
text += "Game has crashed.\n\n";
text += "Check log.txt and look for error messages near the end of file.\n\n";
text += "Unsure what to do next?\n";
text += " * update spice2x to the latest version\n";
text += " * check the FAQ on spice2x github wiki\n";
text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n";
text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds.";
show_popup(text);
}
void show_popup_for_fatal_error(std::string message) {
std::string text;
text += "A fatal error was encountered. For details, check log.txt.\n\n";
text += "----------------------------------------------------------\n";
text += message;
text += "----------------------------------------------------------\n\n";
text += "Unsure what to do next?\n";
text += " * update spice2x to the latest version\n";
text += " * check the FAQ on spice2x github wiki\n";
text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n";
text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds.";
show_popup(text);
}
+10 -2
View File
@@ -71,20 +71,28 @@ struct fmt::formatter<fmt_hresult> {
}
};
void show_popup_for_crash();
void show_popup_for_fatal_error(std::string message);
// misc log
#define LOG_FORMAT(level, module, fmt_str, ...) fmt::format(FMT_COMPILE("{}" fmt_str "\n"), \
fmt_log { std::time(nullptr), level, module }, ## __VA_ARGS__)
#define LOG_FORMAT_POPUP(module, fmt_str, ...) fmt::format(FMT_COMPILE("{}: " fmt_str "\n"), module, ## __VA_ARGS__)
#define log_misc(module, format_str, ...) logger::push( \
LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY)
#define log_info(module, format_str, ...) logger::push( \
LOG_FORMAT("I", module, format_str, ## __VA_ARGS__), logger::Style::DEFAULT)
#define log_warning(module, format_str, ...) logger::push( \
LOG_FORMAT("W", module, format_str, ## __VA_ARGS__), logger::Style::YELLOW)
#define log_fatal(module, format_str, ...) { \
logger::push(LOG_FORMAT("F", module, format_str, ## __VA_ARGS__), logger::Style::RED); \
logger::push(LOG_FORMAT("F", "spice", "encountered a fatal error, you can close the window or press ctrl + c"), logger::Style::RED); \
show_popup_for_fatal_error(LOG_FORMAT_POPUP(module, format_str, ## __VA_ARGS__)); \
launcher::stop_subsystems(); \
Sleep(10000); \
launcher::kill(); \
std::terminate(); \
} ((void) 0 )
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <functional>
class scope_guard {
private:
std::function<void()> f;
public:
explicit scope_guard(std::function<void()>&& f) : f(std::move(f)) {}
~scope_guard() {
f();
}
scope_guard(const scope_guard&) = delete;
scope_guard& operator=(const scope_guard&) = delete;
scope_guard(scope_guard&&) = delete;
scope_guard& operator=(scope_guard&&) = delete;
};
+8 -2
View File
@@ -283,7 +283,8 @@ static inline std::string get_last_error_string() {
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
nullptr,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
@@ -292,7 +293,12 @@ static inline std::string get_last_error_string() {
nullptr);
// return as string
std::string message(messageBuffer, size);
std::string message;
if (size == 0) {
message = fmt::format("(Win32 error {})", error);
} else {
message = fmt::format("{}(Win32 error {})", messageBuffer, error);
}
LocalFree(messageBuffer);
return message;