Compare commits

...

29 Commits

Author SHA1 Message Date
bicarus-dev 61c97ccaab net: ignore -ea if -url is set (#430)
## Link to GitHub Issue, if one exists
#345 

## Description of change
Ignore -ea if -url is provided

## Testing
2025-12-01 16:04:32 -08:00
bicarus-dev 12d6a88c60 iidx: turn off camera access by default (#428)
## Link to GitHub Issue, if one exists
For #345 
Similar idea as https://github.com/spice2x/spice2x.github.io/pull/350

## Description of change
Disable camera access by default by setting `CONNECT_CAMERA` environment
var to 0 before launching. This was one of those "required" things
people clicked on, but now it's done automatically to reduce friction
for new users.

On cab setups (i.e., running without -iidx module), cameras will remain
on, unless user overrides it.

On franken setups (partial I/O) - user will need to specify what they
want via the new option, we can't guess correctly.

## Testing
2025-11-30 16:13:34 -08:00
bicarus-dev 984b41a1ae cfg: fix combo boxes (#429)
## Link to GitHub Issue, if one exists
n/a

## Description of change
Combo boxes for options were not highlighting the currently selected
item. Also, when there were no description provided for an option, it
was still showing the empty `()` in the selected value.

## Testing
2025-11-30 01:59:25 -08:00
duel0213 d06b8bd731 mfc: fix 2025 version touch (#426)
## Link to GitHub Issue, if one exists
n/a

## Description of change
HG cabinet uses wintouch and it requires TOUCHEVENTF_PRIMARY flag in
order to accept touch inputs.
Added wintouchemu on game hook and TOUCHEVENTF_PRIMARY flag on
wintouchemu.
 
## Testing
The game boots into test menu, touch now works. (tested in I/O TEST ->
TOUCH PANEL CHECK with '-s' flag)
TDJ subscreen overlay and nostalgia seems works fine regardless added
TOUCHEVENTF_PRIMARY flag but more testing required.
2025-11-25 17:14:07 -08:00
bicarus-dev 0dad96b876 check for standalone cfg for fatal options 2025-11-23 09:36:38 -08:00
bicarus-dev def296095b reword log message to avoid confusion 2025-11-22 16:45:27 -08:00
bicarus-dev 750b1fea80 patches: disable patches tab for unity games (#425)
## Description of change
To redirect confused users why no one is developing a remote patch
server for PolCho

## Testing
checked spicecfg in working vs non-working games
2025-11-17 19:16:19 -08:00
aixxe 4c87078807 Refactor IIDX camhook texture replacement (#424)
## Link to GitHub Issue, if one exists
Fixes #393 

## Description of change
- Fixes compatibility with IIDX 33
- Adjusts the pattern scan for "hook A" to be compatible with IIDX 27
- Refactors texture replacement to use Camera::CCameraManager2, removing
the need for a second hook

Related: https://github.com/aixxe/2dxcamhook/compare/0.4.0.0...0.5.0.0

## Testing
Booted with `-iidxcamhook` on IIDX 27, 28, 29, 30, 31, 32 & 33
Confirmed both cameras were visible in I/O test, music select settings &
gameplay
2025-11-17 01:21:39 -08:00
bicarus-dev 052698afa3 rawinput: use UTF-8 for device descriptor (#422)
## Link to GitHub Issue, if one exists
n/a

## Description of change
For HID device descriptor, use the "W" version of Windows API, and make
sure UTF-8 is being used throughout since that's the only format IMGUI
supports.

Before this change, non-Latin characters would have shown up as `HID ???
?????` for a mouse, for example.

Due to the way ImGui loads fonts, only the following languages are
supported:

* Simplified Chinese
* Cyrillic
* Japanese
* Korean
* Thai
* Vietnamese

## Testing
Tested various combination of Windows UI language and non-Unicode
language.
2025-11-16 00:08:30 -08:00
bicarus-dev 9e2b04d5db troubleshooter: update link for vcredist (#423)
## Description of change
RIP abbodi1406
2025-11-16 00:07:36 -08:00
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
41 changed files with 716 additions and 202 deletions
+65 -9
View File
@@ -357,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
@@ -622,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")
@@ -637,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)
@@ -647,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
#############
@@ -655,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)
@@ -666,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
##############
@@ -673,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)
@@ -683,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
#######
@@ -776,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"
+2 -1
View File
@@ -1503,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);
}
}
+3 -1
View File
@@ -150,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);
}
}
+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
+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
+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;
+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
+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') {
+72 -70
View File
@@ -22,35 +22,31 @@
static std::filesystem::path dll_path;
static HMODULE iidx_module;
static uintptr_t addr_hook_a = 0;
static uintptr_t addr_hook_b = 0;
static uintptr_t addr_textures = 0;
static uintptr_t addr_camera_manager = 0;
static uintptr_t addr_device_offset = 0;
static uintptr_t addr_afp_texture_offset = 0;
typedef void **(__fastcall *camera_hook_a_t)(PBYTE);
typedef LPDIRECT3DTEXTURE9 (*camera_hook_b_t)(void*, int);
static camera_hook_a_t camera_hook_a_orig = nullptr;
static camera_hook_b_t camera_hook_b_orig = nullptr;
auto static hook_a_init = std::once_flag {};
static LPDIRECT3DDEVICE9EX device;
static LPDIRECT3DTEXTURE9 *texture_a = nullptr;
static LPDIRECT3DTEXTURE9 *texture_b = nullptr;
static LPDIRECT3DTEXTURE9 *camera_texture_a = nullptr;
static LPDIRECT3DTEXTURE9 *camera_texture_b = nullptr;
static LPDIRECT3DTEXTURE9 *preview_texture_a = nullptr;
static LPDIRECT3DTEXTURE9 *preview_texture_b = nullptr;
struct PredefinedHook {
std::string pe_identifier;
uintptr_t hook_a;
uintptr_t hook_b;
uintptr_t hook_textures;
uintptr_t hook_camera_manager;
uintptr_t hook_device_offset;
uintptr_t hook_afp_texture_offset;
};
PredefinedHook g_predefinedHooks[] =
{
// 27 003
{ "5f713b52_6d4090", 0x005971b0, 0x005fb2c0, 0x04e49898, 0x000000d0 },
// 27 010
{ "5f713946_7f52b0", 0x006b89e0, 0x0071c950, 0x04fd08b8, 0x000000d0 },
};
PredefinedHook g_predefinedHooks[] = {};
const DWORD g_predefinedHooksLength = ARRAYSIZE(g_predefinedHooks);
@@ -75,8 +71,8 @@ namespace games::iidx {
if (sscanf(
s.c_str(),
"%i,%i,%i,%i",
(int*)&addr_hook_a, (int*)&addr_hook_b, (int*)&addr_textures, (int*)&addr_device_offset) == 4) {
"%i,%i,%i,%i,%i",
(int*)&addr_hook_a, (int*)&addr_textures, (int*)&addr_camera_manager, (int*)&addr_device_offset, (int*)&addr_afp_texture_offset) == 5) {
return true;
@@ -101,8 +97,8 @@ namespace games::iidx {
// there are three different ways we try to hook the camera entry points
// 1) user-provided override via cmd line
// 2) predefined offsets using PE header matching (needed for iidx27 and few others)
// 3) signature match (should work for most iidx28-31)
// 2) predefined offsets using PE header matching
// 3) signature match (should work for most iidx27-33)
// method 1: user provided
if (TDJ_CAMERA_OVERRIDE.has_value() && parse_cmd_params()) {
@@ -117,10 +113,11 @@ namespace games::iidx {
for (DWORD i = 0; i < g_predefinedHooksLength; i++) {
if (pe.compare(g_predefinedHooks[i].pe_identifier) == 0) {
log_misc("iidx:camhook", "Found predefined addresses");
addr_hook_a = g_predefinedHooks[i].hook_a;
addr_hook_b = g_predefinedHooks[i].hook_b;
addr_textures = g_predefinedHooks[i].hook_textures;
addr_device_offset = g_predefinedHooks[i].hook_device_offset;
addr_hook_a = g_predefinedHooks[i].hook_a;
addr_textures = g_predefinedHooks[i].hook_textures;
addr_camera_manager = g_predefinedHooks[i].hook_camera_manager;
addr_device_offset = g_predefinedHooks[i].hook_device_offset;
addr_afp_texture_offset = g_predefinedHooks[i].hook_afp_texture_offset;
return TRUE;
}
}
@@ -131,8 +128,8 @@ namespace games::iidx {
// --- addr_hook_a ---
uint8_t *addr_hook_a_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"488BC4565741564883EC5048C740D8FEFFFFFF",
"XXXXXXXXXXXXXXXXXXX",
"E800000000488B8F0000000048894D",
"X????XXX????XXX",
0, 0));
if (addr_hook_a_ptr == nullptr) {
@@ -141,24 +138,10 @@ namespace games::iidx {
return FALSE;
}
addr_hook_a = (uint64_t) (addr_hook_a_ptr - (uint8_t*) iidx_module);
// addr_hook_b
uint8_t* addr_hook_b_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"E8000000004885C07439E8",
"X????XXXXXX",
0, 0));
if (addr_hook_b_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_hook_b");
return FALSE;
}
// displace with the content of wildcard bytes
int32_t disp_b = *((int32_t *) (addr_hook_b_ptr + 1));
int32_t disp_a = *((int32_t *) (addr_hook_a_ptr + 1));
addr_hook_b = (addr_hook_b_ptr - (uint8_t*) iidx_module) + disp_b + 5;
addr_hook_a = (addr_hook_a_ptr - (uint8_t*) iidx_module) + disp_a + 5;
// --- addr_textures ---
uint8_t* addr_textures_ptr = reinterpret_cast<uint8_t *>(find_pattern(
@@ -194,6 +177,28 @@ namespace games::iidx {
addr_textures = (addr_textures_ptr - (uint8_t*) iidx_module) + disp_textures + 7;
// --- addr_camera_manager ---
uint8_t *addr_camera_manager_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"E80000000033FF488B58",
"X????XXXXX",
0, 0));
if (addr_camera_manager_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_get_camera_manager");
return FALSE;
}
// displace with the content of wildcard bytes
int32_t disp_camera_manager = *((int32_t *) (addr_camera_manager_ptr + 1));
addr_camera_manager_ptr = addr_camera_manager_ptr + disp_camera_manager + 5;
// once more to get the final address
disp_camera_manager = *((int32_t *) (addr_camera_manager_ptr + 3));
addr_camera_manager = (addr_camera_manager_ptr - (uint8_t*) iidx_module) + disp_camera_manager + 7;
// addr_device_offset
search_from = (addr_hook_a_ptr - (uint8_t*) iidx_module);
uint8_t *addr_device_ptr = reinterpret_cast<uint8_t *>(find_pattern_from(
@@ -201,39 +206,47 @@ namespace games::iidx {
"488B89",
"XXX",
3, 0, search_from));
addr_device_offset = *addr_device_ptr;
if (addr_textures_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_textures (part 3)");
if (addr_device_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_device_ptr");
return FALSE;
}
addr_device_offset = *addr_device_ptr;
// --- addr_afp_texture_offset ---
uint8_t *addr_afp_texture_ptr = reinterpret_cast<uint8_t *>(find_pattern(
iidx_module,
"488B41004885C07400488D5424",
"XXX?XXXX?XXXX",
0, 0));
if (addr_afp_texture_ptr == nullptr) {
log_warning("iidx:camhook", "failed to find hook: addr_afp_texture_offset");
return FALSE;
}
addr_afp_texture_offset = *(addr_afp_texture_ptr + 3);
return TRUE;
}
static void **__fastcall camera_hook_a(PBYTE a1) {
std::call_once(hook_a_init, [&]{
device = *reinterpret_cast<LPDIRECT3DDEVICE9EX*>(a1 + addr_device_offset);
auto const textures = *reinterpret_cast<LPDIRECT3DTEXTURE9**>((uint8_t*)iidx_module + addr_textures);
auto const preview = *reinterpret_cast<LPDIRECT3DTEXTURE9**>((uint8_t*)iidx_module + addr_textures);
auto const manager = reinterpret_cast<Camera::CCameraManager2*>((uint8_t*)iidx_module + addr_camera_manager);
texture_a = textures;
texture_b = textures + 2;
camera_texture_a = manager->cameras->a->d3d9_texture(addr_afp_texture_offset);
camera_texture_b = manager->cameras->b->d3d9_texture(addr_afp_texture_offset);
preview_texture_a = preview;
preview_texture_b = preview + 2;
init_local_camera();
});
return camera_hook_a_orig(a1);
}
static LPDIRECT3DTEXTURE9 camera_hook_b(void* a1, int idx) {
if (idx == 0 && top_camera) {
return top_camera->GetTexture();
}
if (idx == 1 && front_camera) {
return front_camera->GetTexture();
}
return camera_hook_b_orig(a1, idx);
}
bool create_hooks() {
auto *hook_a_ptr = reinterpret_cast<uint16_t *>(
reinterpret_cast<intptr_t>(iidx_module) + addr_hook_a);
@@ -246,17 +259,6 @@ namespace games::iidx {
return FALSE;
}
auto *hook_b_ptr = reinterpret_cast<uint16_t *>(
reinterpret_cast<intptr_t>(iidx_module) + addr_hook_b);
if (!detour::trampoline(
reinterpret_cast<camera_hook_b_t>(hook_b_ptr),
camera_hook_b,
&camera_hook_b_orig)) {
log_warning("iidx:camhook", "failed to trampoline hook_b");
return FALSE;
}
return TRUE;
}
@@ -443,7 +445,7 @@ namespace games::iidx {
}
IIDXLocalCamera* add_top_camera(IMFActivate* pActivate) {
auto top_camera = new IIDXLocalCamera("top", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, texture_a);
auto top_camera = new IIDXLocalCamera("top", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, camera_texture_a, preview_texture_a);
if (top_camera->m_initialized) {
LOCAL_CAMERA_LIST.push_back(top_camera);
} else {
@@ -454,7 +456,7 @@ namespace games::iidx {
}
IIDXLocalCamera* add_front_camera(IMFActivate* pActivate) {
auto front_camera = new IIDXLocalCamera("front", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, texture_b);
auto front_camera = new IIDXLocalCamera("front", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, camera_texture_b, preview_texture_b);
if (front_camera->m_initialized) {
LOCAL_CAMERA_LIST.push_back(front_camera);
} else {
@@ -469,8 +471,8 @@ namespace games::iidx {
if (result) {
log_misc(
"iidx:camhook",
"found hooks:\n hook_a 0x{:x}\n hook_b 0x{:x}\n textures 0x{:x}\n device_offset 0x{:x}",
addr_hook_a, addr_hook_b, addr_textures, addr_device_offset);
"found hooks:\n hook_a 0x{:x}\n textures 0x{:x}\n camera_manager 0x{:x}\n device_offset 0x{:x}\n afp_texture_offset 0x{:x}",
addr_hook_a, addr_textures, addr_camera_manager, addr_device_offset, addr_afp_texture_offset);
result = create_hooks();
if (result) {
init_mf_library();
+25 -21
View File
@@ -53,7 +53,7 @@ namespace games::iidx {
// settings
bool FLIP_CAMS = false;
bool DISABLE_CAMS = false;
std::optional<bool> DISABLE_CAMS;
bool TDJ_CAMERA = false;
bool TDJ_CAMERA_PREFER_16_9 = true;
bool TDJ_MODE = false;
@@ -334,11 +334,6 @@ namespace games::iidx {
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook_title_ends("beatmania IIDX", "main", avs::game::DLL_INSTANCE);
}
// prevent crash on TDJ mode without correct DLL
if (!GetModuleHandle("nvcuda.dll")) {
DISABLE_CAMS = true;
}
}
// insert BI2X hooks
@@ -399,37 +394,44 @@ namespace games::iidx {
"RegQueryValueExA", RegQueryValueExA_hook, avs::game::DLL_INSTANCE);
// check if cam hook should be enabled
if (!DISABLE_CAMS) {
if (!DISABLE_CAMS.has_value()) {
log_fatal("iidx", "assertion failure - DISABLE_CAMS not set during attach");
}
if (!DISABLE_CAMS.value()) {
init_legacy_camera_hook(FLIP_CAMS);
}
// init cfgmgr32 hooks
cfgmgr32hook_init(avs::game::DLL_INSTANCE);
// report common errors on iidx31 and above
if (avs::game::is_ext(2023091500, MAXINT) && GRAPHICS_9_ON_12_STATE == DX9ON12_FORCE_ON) {
deferredlogs::defer_error_messages({
"common incompatibility with DX 9on12 + IIDX 31 and above",
" IIDX31+ is known to be incompatible with DX 9on12, leading to blank screen or crashes"
});
}
}
void IIDXGame::pre_attach() {
Game::pre_attach();
auto options = games::get_options(eamuse_get_game());
// environment variables must be set before the DLL is loaded as the VC++ runtime copies all
// environment variables at startup
if (DISABLE_CAMS) {
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
if (SCREEN_MODE.has_value()) {
log_misc("iidx", "SCREEN_MODE env var set to {}", SCREEN_MODE.value().c_str());
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
}
// check for cab camera access for the second time (first time was in launcher.cpp)
// this time, we are inside -iidx module hook, which means the user is likely NOT on a cab
// therefore, start with cams OFF by default, and allow user to forcibly override to ON
if (!games::iidx::DISABLE_CAMS.has_value()) {
games::iidx::DISABLE_CAMS = true;
if (options->at(launcher::Options::IIDXCabCamAccess).is_active() &&
options->at(launcher::Options::IIDXCabCamAccess).value_text() == "on") {
games::iidx::DISABLE_CAMS = false;
}
if (games::iidx::DISABLE_CAMS.value()) {
log_misc("iidx", "CONNECT_CAMERA env var set to 0");
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
}
// windowed subscreen, enabled by default, unless turned off by user
auto options = games::get_options(eamuse_get_game());
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool()) {
GRAPHICS_IIDX_WSUB = true;
}
@@ -440,7 +442,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"
@@ -458,6 +460,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");
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ namespace games::iidx {
// settings
extern bool FLIP_CAMS;
extern bool DISABLE_CAMS;
extern std::optional<bool> DISABLE_CAMS;
extern bool TDJ_CAMERA;
extern bool TDJ_CAMERA_PREFER_16_9;
extern std::optional<std::string> TDJ_CAMERA_OVERRIDE;
+2
View File
@@ -213,6 +213,8 @@ namespace games::iidx {
}
void init_legacy_camera_hook(bool flip_cams) {
log_info("iidx::cam", "initializing legacy camera hook");
should_flip_cams = flip_cams;
// camera media framework hook
+10 -5
View File
@@ -46,14 +46,17 @@ namespace games::iidx {
IMFActivate *pActivate,
IDirect3DDeviceManager9 *pD3DManager,
LPDIRECT3DDEVICE9EX device,
LPDIRECT3DTEXTURE9 *texture_target
LPDIRECT3DTEXTURE9 *camera_texture_target,
LPDIRECT3DTEXTURE9 *preview_texture_target
):
m_nRefCount(1),
m_name(name),
m_prefer_16_by_9(prefer_16_by_9),
m_device(device),
m_texture_target(texture_target),
m_texture_original(*texture_target)
m_camera_texture_target(camera_texture_target),
m_preview_texture_target(preview_texture_target),
m_camera_texture_original(*camera_texture_target),
m_preview_texture_original(*preview_texture_target)
{
InitializeCriticalSection(&m_critsec);
@@ -691,7 +694,8 @@ namespace games::iidx {
if (FAILED(hr)) { goto done; }
// Make the game use this new texture as camera stream source
*m_texture_target = m_texture;
*m_camera_texture_target = m_texture;
*m_preview_texture_target = m_texture;
m_active = TRUE;
// Create texture for colour conversion
@@ -860,7 +864,8 @@ namespace games::iidx {
ULONG uCount = InterlockedDecrement(&m_nRefCount);
*m_texture_target = m_texture_original;
*m_camera_texture_target = m_camera_texture_original;
*m_preview_texture_target = m_preview_texture_original;
for (size_t i = 0; i < m_mediaTypeInfos.size(); i++) {
SafeRelease(&(m_mediaTypeInfos.at(i).p_mediaType));
+27 -5
View File
@@ -66,6 +66,25 @@ extern std::string CAMERA_CONTROL_LABELS[];
extern std::string DRAW_MODE_LABELS[];
namespace games::iidx {
namespace Camera {
struct PlayVideoCamera {
IDirect3DTexture9** d3d9_texture(const uintptr_t offset) {
auto const afp_texture = *reinterpret_cast<uint8_t**>
(reinterpret_cast<uint8_t*>(this) + offset);
return reinterpret_cast<IDirect3DTexture9**>(afp_texture + 0x8);
}
};
struct CCameraManager2 {
using camera_pointers = struct {
PlayVideoCamera* a;
PlayVideoCamera* b;
};
void* vftbl;
camera_pointers* cameras;
};
}
class IIDXLocalCamera {
protected:
virtual ~IIDXLocalCamera() {};
@@ -98,8 +117,9 @@ namespace games::iidx {
// DirectX9 DeviceEx
LPDIRECT3DDEVICE9EX m_device;
// Address to hook camera texture onto the game
LPDIRECT3DTEXTURE9 *m_texture_target = nullptr;
// Address to hook camera textures onto the game
LPDIRECT3DTEXTURE9 *m_camera_texture_target = nullptr;
LPDIRECT3DTEXTURE9 *m_preview_texture_target = nullptr;
// Target texture (to be shown in the game)
LPDIRECT3DTEXTURE9 m_texture = nullptr;
@@ -117,8 +137,9 @@ namespace games::iidx {
LPDIRECT3DTEXTURE9 m_transformResultTexture = nullptr;
IDirect3DSurface9 *m_pTransformResultSurf = nullptr;
// Storing original texture for clean up
LPDIRECT3DTEXTURE9 m_texture_original = nullptr;
// Storing original textures for clean up
LPDIRECT3DTEXTURE9 m_camera_texture_original = nullptr;
LPDIRECT3DTEXTURE9 m_preview_texture_original = nullptr;
IAMCameraControl *m_pCameraControl = nullptr;
@@ -154,7 +175,8 @@ namespace games::iidx {
IMFActivate *pActivate,
IDirect3DDeviceManager9 *pD3DManager,
LPDIRECT3DDEVICE9EX device,
LPDIRECT3DTEXTURE9 *texture_target
LPDIRECT3DTEXTURE9 *camera_texture_target,
LPDIRECT3DTEXTURE9 *preview_texture_target
);
LPDIRECT3DTEXTURE9 GetTexture();
ULONG Release();
+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");
}
}
}
+35 -2
View File
@@ -4,6 +4,7 @@
#include "avs/game.h"
#include "hooks/graphics/graphics.h"
#include "misc/eamuse.h"
#include "misc/wintouchemu.h"
#include "touch/touch.h"
#include "util/detour.h"
#include "util/libutils.h"
@@ -32,6 +33,8 @@ namespace games::mfc {
static uint8_t CARD_TYPE = 0;
static uint8_t CARD_UID[8];
bool HG_MODE = false;
typedef int (__cdecl *inifile_param_num_t)(const char *, int *);
static inifile_param_num_t inifile_param_num_real;
@@ -50,8 +53,10 @@ namespace games::mfc {
static void __cdecl touch_init(int width, int height) {
log_info("mfc", "call touch_init(width: {}, height: {})", width, height);
// attach touch module
if (!TOUCH_ATTACHED) {
if (HG_MODE) {
wintouchemu::ADD_TOUCH_FLAG_PRIMARY = true;
wintouchemu::hook("MFC9", avs::game::DLL_INSTANCE);
} else if (!TOUCH_ATTACHED) { // attach touch module
// store touch size specification
TOUCH_MAX_X = width;
@@ -288,6 +293,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 +328,17 @@ 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;
if (avs::game::SPEC[0] == 'F') {
HG_MODE = true;
}
}
// network fix
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
@@ -378,5 +409,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);
}
}
+2
View File
@@ -4,6 +4,8 @@
namespace games::mfc {
extern bool HG_MODE;
struct joystick_state {
bool up = false;
bool down = false;
+15 -3
View File
@@ -106,8 +106,8 @@ namespace games::sdvx {
if (ENABLE_COM_PORT_SCAN_HOOK &&
lpSubKey != nullptr && phkResult != nullptr &&
_stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) {
log_info("sdvx::io", "failing HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
return 2; //ERROR_FILE_NOT_FOUND
log_info("sdvx::io", "hook access to HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
return 2; // ERROR_FILE_NOT_FOUND
}
return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult);
@@ -215,6 +215,15 @@ namespace games::sdvx {
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;
}
@@ -268,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"
@@ -278,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");
}
}
@@ -15,6 +15,7 @@
#include "cfg/screen_resize.h"
#include "games/iidx/iidx.h"
#include "games/sdvx/sdvx.h"
#include "games/mfc/mfc.h"
#include "games/io.h"
#include "hooks/graphics/graphics.h"
#include "launcher/launcher.h"
@@ -238,14 +239,17 @@ static void log_create_device_failure(HRESULT hresult) {
}
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:
@@ -253,14 +257,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) {
@@ -1338,6 +1361,11 @@ void graphics_d3d9_on_present(
graphics_d3d9_ldj_on_present(wrapped_device);
}
const bool is_mfc = avs::game::is_model("KK9") && games::mfc::HG_MODE;
if (is_mfc) {
wintouchemu::update();
}
// check screenshot key
static bool trigger_last = false;
auto buttons = games::get_buttons_overlay(eamuse_get_game());
@@ -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() {
+70 -26
View File
@@ -3,6 +3,7 @@
#include <memory>
#include <vector>
#include <assert.h>
#include <shlwapi.h>
#include <cfg/configurator.h>
@@ -20,7 +21,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"
@@ -263,7 +266,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) {
@@ -297,25 +301,13 @@ int main_implementation(int argc, char *argv[]) {
cfg_run = true;
}
// -ea, but ignored if -url is set
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()) {
!options[launcher::Options::ServiceURL].is_active()) {
avs::ea3::URL_SLASH = 1;
easrv_port = 8080;
}
if (options[launcher::Options::SmartEAmusement].value_bool()) {
easrv_smart = true;
}
@@ -471,14 +463,26 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::IIDXCameraOrderFlip].value_bool()) {
games::iidx::FLIP_CAMS = true;
}
// IIDX CONNECT_CAMERA logic here for cases where user is running without -iidx module
// for now, we assume that user may be running on a cab
// (games::iidx::DISABLE_CAMS starts out as false unless user overrides)
// we will check again in IIDX module with a different default
assert(!games::iidx::DISABLE_CAMS.has_value());
if (options[launcher::Options::IIDXDisableCameras].value_bool()) {
games::iidx::DISABLE_CAMS = true;
}
if (options[launcher::Options::IIDXCabCamAccess].is_active() &&
options[launcher::Options::IIDXCabCamAccess].value_text() == "off") {
games::iidx::DISABLE_CAMS = true;
}
if (options[launcher::Options::IIDXCamHook].value_bool()) {
games::iidx::TDJ_CAMERA = true;
// Disable legacy behaviour to avoid conflict
games::iidx::DISABLE_CAMS = true;
}
// CONNECT_CAMERA env var will be set once logging is enabled
if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
}
@@ -816,6 +820,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();
@@ -835,6 +840,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;
}
@@ -938,6 +944,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;
@@ -1200,15 +1211,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) {
@@ -1252,18 +1276,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);
}
}
}
@@ -1303,7 +1328,7 @@ int main_implementation(int argc, char *argv[]) {
// SDVXFullscreenLandscape disabled due to it messing with in-game camera angle
// FullscreenOrientationFlip continues to live on, however.
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool()) {
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
log_fatal("launcher", "-sdvxlandscape removed due to a camera bug in SDVX!");
}
// if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
@@ -1318,8 +1343,15 @@ int main_implementation(int argc, char *argv[]) {
GRAPHICS_FS_ORIENTATION_SWAP = true;
}
if (games::iidx::DISABLE_CAMS.has_value() &&
games::iidx::DISABLE_CAMS.value() &&
!cfg::CONFIGURATOR_STANDALONE) {
log_misc("launcher", "CONNECT_CAMERA env var set to 0");
SetEnvironmentVariable("CONNECT_CAMERA", "0");
}
// deleted options
if (options[launcher::Options::OpenKFControl].value_bool()) {
if (options[launcher::Options::OpenKFControl].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version.");
}
if (options[launcher::Options::VREnable].value_bool()) {
@@ -1647,6 +1679,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
@@ -1791,7 +1831,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"
@@ -1799,6 +1839,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;
@@ -2314,8 +2356,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();
+55 -14
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)",
@@ -450,13 +456,30 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options (Advanced)",
},
{
.title = "IIDX Disable Cameras",
// IIDXDisableCameras
.title = "IIDX Disable Cameras (DEPRECATED - no longer needed)",
.name = "iidxdisablecams",
.desc = "Disables cameras",
.type = OptionType::Bool,
.hidden = true,
.game_name = "Beatmania IIDX",
.category = "Game Options",
},
{
// IIDXCabCamAccess
.title = "IIDX Use Official AC Cams",
.name = "iidxcabcams",
.desc = "For IIDX25+, allow direct access to cameras from real arcade cabinets. "
"Only turn this on if you have OFFICIAL arcade cameras connected to the correct USB ports. Default: auto",
.type = OptionType::Enum,
.game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)",
.elements = {
{"auto", ""},
{"off", ""},
{"on", ""}
},
},
{
// IIDXCamHook
.title = "IIDX Cam Hook",
@@ -491,10 +514,10 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.display_name = "iidxcamhookoffset",
.aliases = "iidxcamhookoffset",
.desc = "Override DLL offsets for camera hook; "
"format: 4 hex values separated by commas "
"(offset_hook_a, offset_hook_b, offset_textures, offset_d3d_device)",
"format: 5 hex values separated by commas "
"(offset_hook_a, offset_textures, offset_camera_manager, offset_d3d_device, offset_afp_texture)",
.type = OptionType::Text,
.setting_name = "0x5817a0,0x5ea3b0,0x6fffbd8,0xe0",
.setting_name = "0x5817a0,0x6fffbd8,0xbbae40,0xe0,0x30",
.game_name = "Beatmania IIDX",
.category = "Game Options (Advanced)",
},
@@ -1385,21 +1408,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
@@ -1413,12 +1442,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
@@ -2608,8 +2639,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;
@@ -2632,7 +2674,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;
@@ -2678,7 +2720,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) {
@@ -2714,8 +2756,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()) {
@@ -2729,7 +2770,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
@@ -2769,7 +2810,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);
}
}
@@ -2800,7 +2841,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) {
@@ -2833,5 +2874,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);
}
+3 -2
View File
@@ -55,6 +55,7 @@ namespace launcher {
LoadIIDXModule,
IIDXCameraOrderFlip,
IIDXDisableCameras,
IIDXCabCamAccess,
IIDXCamHook,
IIDXCamHookRatio,
IIDXCamHookOverride,
@@ -279,6 +280,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
@@ -1,5 +1,6 @@
#include "signal.h"
#include <future>
#include <exception>
#include <windows.h>
@@ -174,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");
}
+25
View File
@@ -34,6 +34,7 @@ namespace wintouchemu {
bool FORCE = false;
bool INJECT_MOUSE_AS_WM_TOUCH = false;
bool LOG_FPS = false;
bool ADD_TOUCH_FLAG_PRIMARY = false;
static inline bool is_emu_enabled() {
return FORCE || !is_touch_available("wintouchemu::is_emu_enabled") || GRAPHICS_SHOW_CURSOR;
@@ -187,16 +188,28 @@ namespace wintouchemu {
switch (touch_event->type) {
case TOUCH_DOWN:
if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
}
break;
case TOUCH_MOVE:
if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
}
break;
case TOUCH_UP:
// don't check valid so that this touch ID can be released
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_UP;
break;
}
@@ -238,16 +251,28 @@ namespace wintouchemu {
switch (mouse_state.touch_event) {
case TOUCHEVENTF_DOWN:
if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
}
break;
case TOUCHEVENTF_MOVE:
if (valid) {
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
}
break;
case TOUCHEVENTF_UP:
// don't check valid so that this touch ID can be released
if (ADD_TOUCH_FLAG_PRIMARY) {
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
}
touch_input->dwFlags |= TOUCHEVENTF_UP;
break;
}
+1
View File
@@ -8,6 +8,7 @@ namespace wintouchemu {
extern bool FORCE;
extern bool INJECT_MOUSE_AS_WM_TOUCH;
extern bool LOG_FPS;
extern bool ADD_TOUCH_FLAG_PRIMARY;
void hook(const char *window_title, HMODULE module = nullptr, int delay_in_s=0);
void hook_title_ends(
+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")) {
+25 -4
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) {
@@ -2821,7 +2828,10 @@ namespace overlay::windows {
std::string current_item = option.value_text();
for (auto &element : definition.elements) {
if (element.first == current_item) {
current_item += fmt::format(" ({})", element.second);
if (!element.second.empty()) {
current_item += fmt::format(" ({})", element.second);
}
break;
}
}
if (current_item.empty()) {
@@ -2829,11 +2839,12 @@ namespace overlay::windows {
}
if (ImGui::BeginCombo("##combo", current_item.c_str(), 0)) {
for (auto &element : definition.elements) {
bool selected = current_item == element.first;
std::string label = element.first;
if (!element.second.empty()) {
label += fmt::format(" ({})", element.second);
}
bool selected = current_item == label;
if (ImGui::Selectable(label.c_str(), selected)) {
this->options_dirty = true;
option.value = element.first;
@@ -2904,13 +2915,20 @@ 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);
}
@@ -2971,6 +2989,7 @@ namespace overlay::windows {
void Config::build_menu(int *game_selected) {
bool about_popup = false;
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.14f, 0.14f, 0.14f, 1.0f));
if (ImGui::BeginMenuBar()) {
// [spice2x]
@@ -3031,6 +3050,8 @@ 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");
@@ -288,6 +288,12 @@ namespace overlay::windows {
this->reload_local_patches();
}
if (avs::game::DLL_NAME == "kamunity.dll") {
ImGui::TextColored(ImVec4(1.f, 0.f, 0.f, 1.f), "Patches are not supported for Unity-based games.");
ImGui::TextColored(ImVec4(1.f, 0.f, 0.f, 1.f), "Instead, look for downloads of pre-patched DLLs.");
return;
}
// game code info
std::string identifiers;
identifiers += avs::game::get_identifier() + "\n\n";
@@ -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();
}
+11 -13
View File
@@ -347,40 +347,38 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
if (hid_handle != INVALID_HANDLE_VALUE) {
// check manufacturer string
std::wstring man_ws;
std::string man_ws;
wchar_t man_str_buffer[256] {};
if (HidD_GetManufacturerString(hid_handle, man_str_buffer, sizeof(man_str_buffer))) {
man_ws = std::wstring(man_str_buffer);
man_ws = wchar_to_u8(man_str_buffer);
}
// get product string
std::wstring prod_ws;
std::string prod_ws;
wchar_t prod_str_buffer[256] {};
if (HidD_GetProductString(hid_handle, prod_str_buffer, sizeof(prod_str_buffer))) {
prod_ws = std::wstring(prod_str_buffer);
prod_ws = wchar_to_u8(prod_str_buffer);
}
// For Bluetooth LE HID devices (e.g., newer Xbox controllers) HidD_GetProductString
// and HidD_GetManufacturerString will return blank strings.
// https://docs.microsoft.com/en-us/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html
if (man_ws.empty() && prod_ws.empty()) {
prod_ws = s2ws(device_description);
prod_ws = device_description;
}
// build desc string
std::wstring desc_ws;
std::string desc_ws;
if (string_begins_with(prod_ws, man_ws)) {
desc_ws = prod_ws;
} else {
desc_ws = man_ws;
if (!man_ws.empty() && !prod_ws.empty()) {
desc_ws += L" ";
desc_ws += " ";
}
desc_ws += prod_ws;
}
// convert to normal string
new_device.desc = ws2s(desc_ws);
new_device.desc = desc_ws;
// get attributes
if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
@@ -1148,7 +1146,7 @@ std::string rawinput::RawInputManager::rawinput_get_device_description(const raw
// get property
DWORD desc_size = 0;
if (SetupDiGetDeviceRegistryProperty(
if (SetupDiGetDeviceRegistryPropertyW(
devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, nullptr, 0, &desc_size))
{
continue;
@@ -1160,14 +1158,14 @@ std::string rawinput::RawInputManager::rawinput_get_device_description(const raw
// allocate buffer
auto desc_data = std::make_unique<BYTE[]>(desc_size);
if (!SetupDiGetDeviceRegistryProperty(
if (!SetupDiGetDeviceRegistryPropertyW(
devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, desc_data.get(), desc_size, nullptr))
{
continue;
}
// kthxbye
device_description = std::string(reinterpret_cast<char *>(desc_data.get()));
device_description = wchar_to_u8(reinterpret_cast<PWCHAR>(desc_data.get()));
}
}
}
+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
+4 -2
View File
@@ -49,8 +49,10 @@ namespace deferredlogs {
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 += " * 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 += " minidump should only be shared with people you trust as it may contain\n";
msg += " sensitive data (PCBID, card ID, etc)\n";
msg += "\n";
}
+1 -1
View File
@@ -12,7 +12,7 @@ namespace {
{
"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",
"Download and install from https://github.com/spice2x/spice2x.github.io/wiki/Visual-Cpp-Redistributable-Runtimes",
},
{
"d3dx9_43.dll",
+2 -1
View File
@@ -43,7 +43,8 @@ static inline void load_library_fail(const std::string &file_name, bool fatal) {
" 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);
}
+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 )
+10
View File
@@ -339,4 +339,14 @@ static inline bool parse_width_height(const std::string wh, std::pair<uint32_t,
} else {
return false;
}
}
static inline std::string wchar_to_u8(const wchar_t* wstr) {
int size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
if (size <= 1) {
return "";
}
std::string out(size - 1, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), size - 1, nullptr, nullptr);
return out;
}