mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5641e06a19 | |||
| 88ec6dbcee | |||
| 1b614c94a7 | |||
| 37c5913f69 | |||
| 2eca668593 | |||
| aec1da9d16 | |||
| 548b441f1f | |||
| 98bc285d98 | |||
| 553c180bee | |||
| 537252440e | |||
| 13a0877d38 | |||
| 50691b79f1 | |||
| ad229dabdb | |||
| bdff33a420 | |||
| 4b21821aa4 | |||
| 6b47b5db50 | |||
| a10ca5236b | |||
| be2dab9a1a | |||
| 02711cdee1 | |||
| c6b10402f4 | |||
| 58ea6ce17e | |||
| 8cc00c371a | |||
| 8e2985d8d0 | |||
| 8d3b15641f | |||
| 033e9f926a | |||
| da58503b47 | |||
| cffee2b7f8 | |||
| 32801319fa | |||
| afbe013811 | |||
| 862e4717f6 | |||
| d3fa27ae4a | |||
| b487cf2bcf | |||
| 0fc3aa5818 | |||
| 276874f882 | |||
| 1fdd270480 | |||
| 07cb6048a0 | |||
| 61d79f76b2 | |||
| 7335d07e30 | |||
| 9f99b71112 | |||
| 5c3921a99c | |||
| 9fc397b8bc | |||
| ddc8061268 | |||
| c0698a3872 | |||
| 1ed3521091 | |||
| 0dda920448 | |||
| 5f7580b69e | |||
| 3ef1b3ecaa | |||
| 931811da14 | |||
| 7624ded512 | |||
| a5252939dd | |||
| 808ac0c557 | |||
| 4e138b244e | |||
| 3fcd1bdbc9 | |||
| f857e63d5d | |||
| b462c838f6 | |||
| 4d658bf273 | |||
| 67721c416b | |||
| 0b5f7787be | |||
| a554c8f923 | |||
| 6592191624 | |||
| 164592b16d | |||
| 81f879e7ff | |||
| 1af8b3de61 | |||
| c33fef606f | |||
| a9fc6ef1b2 | |||
| d530bfcd65 | |||
| c96f4330d2 | |||
| 26a2a0f481 | |||
| 11b9790e6c | |||
| 1dfcf8c087 | |||
| 5c7ad0d51e | |||
| 587ae86341 | |||
| 926f2ef2a0 | |||
| d262e02f8c | |||
| f6b63473a0 | |||
| 1ad45edd6e | |||
| e79de3b117 | |||
| f783a5a1cd | |||
| 7848d5c237 | |||
| cec735a81b | |||
| 753702e32e | |||
| 7bd7503951 | |||
| d0c38956bf | |||
| 77bca2baee | |||
| 46e8c8a5a5 | |||
| 4d58e5d080 | |||
| 168084d672 | |||
| 740ed90d95 | |||
| 61c17f15b4 | |||
| 99035f312f | |||
| aafc916bb6 | |||
| c5eb1e999b | |||
| 7c15452c1e | |||
| 4bc849ccdb | |||
| 58481a035b | |||
| 66b3de8e5c | |||
| 257afe0cd3 | |||
| aafea3b1c1 | |||
| 346a159157 | |||
| 54028d8cbb | |||
| 621b702ed4 | |||
| 26ea8a1b92 | |||
| 6e7bf99af8 | |||
| df9d9d8673 | |||
| b3cee1dfcc | |||
| f40c382903 | |||
| e4cfb808bf | |||
| 61d14a16e8 | |||
| 521e87ea41 | |||
| 2b735ffd55 | |||
| 4f72b0a98b | |||
| 474f5f5203 | |||
| 205cf29aff | |||
| bf9074a76e | |||
| 44e1edb50c | |||
| 41d0dce6e9 | |||
| 598422b701 | |||
| b58a1ccfcc | |||
| 60efd643d1 | |||
| 0596eeb6fe | |||
| 3d5c64feb7 |
@@ -13,6 +13,11 @@ jobs:
|
|||||||
working-directory: ./src/spice2x
|
working-directory: ./src/spice2x
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set ccache environment variables
|
||||||
|
run: |
|
||||||
|
echo "CCACHE_DIR=${{ github.workspace }}/src/spice2x/.ccache" >> $GITHUB_ENV
|
||||||
|
- name: Install ccache
|
||||||
|
uses: hendrikmuhs/ccache-action@v1.2
|
||||||
- name: Calculate commit SHA
|
- name: Calculate commit SHA
|
||||||
id: vars
|
id: vars
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+8
-4
@@ -30,12 +30,11 @@ Do not change the names of options, buttons binds, analogs, etc - since they are
|
|||||||
* All currently supported games / versions must continue to work.
|
* All currently supported games / versions must continue to work.
|
||||||
* Backwards compatibility must be preserved, unless there is a really good reason to break it. This includes (but not limited to): global/local config files, command line parameters, game patches, device interop (e.g., card readers), and SpiceAPI / Companion interop.
|
* Backwards compatibility must be preserved, unless there is a really good reason to break it. This includes (but not limited to): global/local config files, command line parameters, game patches, device interop (e.g., card readers), and SpiceAPI / Companion interop.
|
||||||
* Reasonable level of compatibility with the last release of original spicetools is expected. The stated goal of spice2x is to be a drop-in replacement for spicetools.
|
* Reasonable level of compatibility with the last release of original spicetools is expected. The stated goal of spice2x is to be a drop-in replacement for spicetools.
|
||||||
* Simply put, if someone has an existing install of spicetools/spice2x, copying over new version of spice2x should not result in different behavior or loss of functionality.
|
* Simply put, if someone has an existing install of spicetools/spice2x, copying over new version of spice2x should not result in vastly different behavior or major loss of functionality.
|
||||||
* Make sure you compile with the included Docker script and ensure you do not introduce **any** new compiler warnings or build breaks. The Docker script is the standard build environment, your custom Linux build environment or MSVC can be used during development, but you must validate the final build using Docker.
|
* Make sure you compile with the included Docker script and ensure you do not introduce **any** new compiler warnings or build breaks. The Docker script is the standard build environment, your custom Linux build environment or MSVC can be used during development, but you must validate the final build using Docker.
|
||||||
* Do not submit snippets of code as a "patch". Exceptions can be made for trivial changes (correct a typo, fix a single line of code...), but otherwise, a successfully compiled & fully tested patch file is required when submitting for review.
|
|
||||||
* Do not make code changes in unrelated areas; i.e., do not run code linters and auto-formatters for parts of the code that you didn't modify.
|
* Do not make code changes in unrelated areas; i.e., do not run code linters and auto-formatters for parts of the code that you didn't modify.
|
||||||
* Try to submit smaller chunks of code, instead one gigantic patch. For example, don't submit a patch for "Improve feature XYZ"; instead, submit "Change how A works to prepare for feature XYZ" "Refactor B for feature XYZ" "Add feature B to enable feature XYZ".
|
* Try to submit smaller chunks of code, instead one gigantic patch. For example, don't submit a patch for "Improve feature XYZ"; instead, submit "Change how A works to prepare for feature XYZ" "Refactor B for feature XYZ" "Add feature B to enable feature XYZ".
|
||||||
* Write to the log for anything useful - it helps immensely with debugging post-mortem. At the same time though, avoid spamming the log for something trivial.
|
* Write to the log for anything useful - it helps immensely with troubleshooting and debugging. At the same time though, avoid spamming the log for something trivial.
|
||||||
|
|
||||||
### UI text
|
### UI text
|
||||||
spice2x has a global audience; majority of the user base do not speak English as their first language.
|
spice2x has a global audience; majority of the user base do not speak English as their first language.
|
||||||
@@ -44,7 +43,7 @@ Use simple English, avoid colloquialism, and use concise language, even if it's
|
|||||||
|
|
||||||
### Using OS APIs
|
### Using OS APIs
|
||||||
|
|
||||||
Avoid making permanent changes to user's OS configuration. For example, spice should not make a call to set power profile to Maximum Performance, or switch default audio device. Making the reverse call to restore settings on game shutdown is **not** good enough; there is no guarantee that spice will gracefully shutdown, since games (or spice) can crash. This is to avoid inadvertently putting user's PC into a bad state, which can be seen as malware-like behavior.
|
Avoid making permanent changes to user's OS configuration. For example, spice must not make a call to set power profile to Maximum Performance, or switch default audio device. Making the reverse call to restore settings on game shutdown is **not** good enough; there is no guarantee that spice will gracefully shutdown, since games (or spice) can crash. This is to avoid inadvertently putting user's PC into a bad state, which can be seen as malware-like behavior.
|
||||||
|
|
||||||
Watch out for legacy OS compatibility. Currently, the minimum support floor is Windows 7. If you use any Windows API, make sure it's supported in Windows 7. If you need to use API that is not present in Windows 7, you must not directly link against it, otherwise spice will fail to launch on older OSes. Take a look at Windows 8 touch code (win8.cpp) for examples on how to discover OS APIs via pointers.
|
Watch out for legacy OS compatibility. Currently, the minimum support floor is Windows 7. If you use any Windows API, make sure it's supported in Windows 7. If you need to use API that is not present in Windows 7, you must not directly link against it, otherwise spice will fail to launch on older OSes. Take a look at Windows 8 touch code (win8.cpp) for examples on how to discover OS APIs via pointers.
|
||||||
|
|
||||||
@@ -87,4 +86,9 @@ if (conditional)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Please give [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) a read. A few things to point out in spice codebase:
|
||||||
|
* We don't use GSL.
|
||||||
|
* Don't throw exceptions.
|
||||||
|
* Stick to smart pointers. For interfacing with C Win32 API and raw buffers, use `unique_plain_ptr`.
|
||||||
|
* Writing in C is also completely acceptable.
|
||||||
* Other than that, there are no strict rules for code formatting, but please attempt to emulate the style around the code you are modifying.
|
* Other than that, there are no strict rules for code formatting, but please attempt to emulate the style around the code you are modifying.
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ please do not ask for these, as it will never happen here.
|
|||||||
|
|
||||||
Rules for filing a new issue or adding comments to existing issues in the tracker:
|
Rules for filing a new issue or adding comments to existing issues in the tracker:
|
||||||
|
|
||||||
|
* Low effort submissions will be simply deleted, and repeated attempts will get you banned.
|
||||||
* Check the [known issues](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) page first before reporting a new issue. If you have some new information or workarounds for a known issue, you can file a documentation bug as well.
|
* Check the [known issues](https://github.com/spice2x/spice2x.github.io/wiki/Known-issues) page first before reporting a new issue. If you have some new information or workarounds for a known issue, you can file a documentation bug as well.
|
||||||
* Use the search function and see if there is an existing issue.
|
* Use the search function and see if there is an existing issue.
|
||||||
* This is not the place to obtain a guide or receive basic troubleshooting.
|
* This is not the place to obtain a guide or receive basic troubleshooting.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
> * Please do note that this is a GPL v3.0 open source project.
|
> * Please do note that this is a GPL v3.0 open source project.
|
||||||
> * Please read the [CONTRIBUTING](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md) guide.
|
> * Please read the [CONTRIBUTING](https://github.com/spice2x/spice2x.github.io/blob/main/CONTRIBUTING.md) guide.
|
||||||
> * Maintainers reserve the right to reject or modify your submission without reason.
|
> * Maintainers reserve the right to reject or modify your submission without reason.
|
||||||
|
> * No new compiler warnings must be introduced. Check the CI build results.
|
||||||
>
|
>
|
||||||
> Feel free to remove this section after you have read it.
|
> Feel free to remove this section after you have read it.
|
||||||
|
|
||||||
@@ -12,8 +13,5 @@
|
|||||||
## Description of change
|
## Description of change
|
||||||
*what does this code do?*
|
*what does this code do?*
|
||||||
|
|
||||||
## Compiling
|
|
||||||
*you must be able to compile with the included Docker script with zero compiler warnings*
|
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
*how was the code tested?*
|
*how was the code tested?*
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ bin/**
|
|||||||
dist/**
|
dist/**
|
||||||
docker/**
|
docker/**
|
||||||
cmake-build*
|
cmake-build*
|
||||||
|
.ccache/**
|
||||||
@@ -17,3 +17,10 @@ bin/*
|
|||||||
dist/*
|
dist/*
|
||||||
|
|
||||||
external/cv2pdb/*
|
external/cv2pdb/*
|
||||||
|
|
||||||
|
.ccache/*
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
.vs
|
||||||
|
out
|
||||||
|
CMakeSettings.json
|
||||||
|
|||||||
+119
-14
@@ -80,6 +80,25 @@ if(MSVC)
|
|||||||
|
|
||||||
# enable COMDAT folding for even smaller release builds
|
# enable COMDAT folding for even smaller release builds
|
||||||
add_link_options("$<$<CONFIG:RELEASE,MINSIZEREL>:/OPT:ICF>")
|
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")
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
# disable warnings about using non _s variants like strncpy
|
# disable warnings about using non _s variants like strncpy
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
@@ -124,8 +143,8 @@ else()
|
|||||||
# https://github.com/msys2/MINGW-packages/pull/6880
|
# https://github.com/msys2/MINGW-packages/pull/6880
|
||||||
# some games crash if some DLLS load above 4GB VA, so manually set base address to standard 32-bit VA,
|
# some games crash if some DLLS load above 4GB VA, so manually set base address to standard 32-bit VA,
|
||||||
# and might as well double make sure ASLR is disabled here
|
# and might as well double make sure ASLR is disabled here
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup")
|
||||||
|
|
||||||
# set visibility to hidden
|
# set visibility to hidden
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fvisibility=hidden")
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fvisibility=hidden")
|
||||||
@@ -160,8 +179,8 @@ else()
|
|||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-ident -ffunction-sections -fdata-sections")
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-ident -ffunction-sections -fdata-sections")
|
||||||
|
|
||||||
# linker fix to load below 4GB
|
# linker fix to load below 4GB
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup")
|
||||||
|
|
||||||
# set visibility to hidden
|
# set visibility to hidden
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fvisibility=hidden")
|
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fvisibility=hidden")
|
||||||
@@ -184,8 +203,8 @@ else()
|
|||||||
set(CMAKE_CXX_FLAGS_DEBUG "-gdwarf")
|
set(CMAKE_CXX_FLAGS_DEBUG "-gdwarf")
|
||||||
|
|
||||||
# linker fix to load below 4GB
|
# linker fix to load below 4GB
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup")
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--disable-dynamicbase,--image-base=0x400000,--enable-stdcall-fixup")
|
||||||
|
|
||||||
# enable debug symbols on level 3 and keep frame pointers
|
# enable debug symbols on level 3 and keep frame pointers
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g3 -fno-omit-frame-pointer")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g3 -fno-omit-frame-pointer")
|
||||||
@@ -338,12 +357,12 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
external/cardio/cardio_runner.cpp
|
external/cardio/cardio_runner.cpp
|
||||||
|
|
||||||
# external misc
|
# external misc
|
||||||
external/scard/scard.cpp
|
|
||||||
external/stackwalker/stackwalker.cpp
|
external/stackwalker/stackwalker.cpp
|
||||||
external/tinyxml2/tinyxml2.cpp
|
external/tinyxml2/tinyxml2.cpp
|
||||||
external/http-parser/http_parser.c
|
external/http-parser/http_parser.c
|
||||||
external/usbhidusage/usb-hid-usage.c
|
external/usbhidusage/usb-hid-usage.c
|
||||||
external/toojpeg/toojpeg.cpp
|
external/toojpeg/toojpeg.cpp
|
||||||
|
external/scard/scard.cpp
|
||||||
|
|
||||||
# games
|
# games
|
||||||
games/game.cpp
|
games/game.cpp
|
||||||
@@ -443,6 +462,9 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/mfg/mfg.cpp
|
games/mfg/mfg.cpp
|
||||||
games/mfg/io.cpp
|
games/mfg/io.cpp
|
||||||
games/mfg/bi2a_hook.cpp
|
games/mfg/bi2a_hook.cpp
|
||||||
|
games/pc/pc.cpp
|
||||||
|
games/pc/io.cpp
|
||||||
|
games/pc/bi2x_hook.cpp
|
||||||
|
|
||||||
# hooks
|
# hooks
|
||||||
hooks/audio/audio.cpp
|
hooks/audio/audio.cpp
|
||||||
@@ -588,6 +610,8 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
util/lz77.cpp
|
util/lz77.cpp
|
||||||
util/tapeled.cpp
|
util/tapeled.cpp
|
||||||
util/execexe.cpp
|
util/execexe.cpp
|
||||||
|
util/dependencies.cpp
|
||||||
|
util/deferlog.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
|
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOURCE_FILES})
|
||||||
@@ -598,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)
|
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
||||||
add_executable(spicetools_spice ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_spice ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_spice
|
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)
|
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 PREFIX "")
|
||||||
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
|
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
|
||||||
|
|
||||||
@@ -607,6 +632,39 @@ IF(NOT MSVC)
|
|||||||
set_target_properties(spicetools_spice PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
set_target_properties(spicetools_spice PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# spice_laa.exe
|
||||||
|
###########
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
|
||||||
|
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
|
# spice64.exe
|
||||||
#############
|
#############
|
||||||
|
|
||||||
@@ -615,9 +673,9 @@ add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
|
|||||||
|
|
||||||
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
||||||
target_link_libraries(spicetools_spice64
|
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)
|
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 PREFIX "")
|
||||||
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
||||||
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
||||||
@@ -626,6 +684,24 @@ IF(NOT MSVC)
|
|||||||
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
endif()
|
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
|
# spicecfg.exe
|
||||||
##############
|
##############
|
||||||
@@ -634,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)
|
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
||||||
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_cfg
|
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)
|
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 PREFIX "")
|
||||||
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
||||||
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
||||||
@@ -644,6 +721,24 @@ if(NOT MSVC)
|
|||||||
set_target_properties(spicetools_cfg PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
set_target_properties(spicetools_cfg PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
endif()
|
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
|
# stubs
|
||||||
#######
|
#######
|
||||||
|
|
||||||
@@ -723,23 +818,33 @@ if(NOT MSVC)
|
|||||||
set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
set_target_properties(spicetools_stubs_nvEncodeAPI64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# cpusbxpkm.dll (32 bit)
|
||||||
|
set(SOURCE_FILES stubs/cpusbxpkm.cpp)
|
||||||
|
add_library(spicetools_stubs_cpusbxpkm SHARED ${SOURCE_FILES} stubs/cpusbxpkm.def)
|
||||||
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES PREFIX "")
|
||||||
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES OUTPUT_NAME "cpusbxpkm")
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set_target_properties(spicetools_stubs_cpusbxpkm PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||||
|
endif()
|
||||||
|
|
||||||
# output directories
|
# output directories
|
||||||
####################
|
####################
|
||||||
|
|
||||||
# output config
|
# output config
|
||||||
set_target_properties(spicetools_cfg
|
set_target_properties(spicetools_cfg spicetools_cfg_linux
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
||||||
|
|
||||||
# output 32bit
|
# output 32bit
|
||||||
set_target_properties(spicetools_spice spicetools_stubs_kbt spicetools_stubs_kld
|
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
||||||
|
|
||||||
# output 64bit
|
# 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
|
PROPERTIES
|
||||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ WORKDIR /src
|
|||||||
COPY --from=gitroot . /src/.git
|
COPY --from=gitroot . /src/.git
|
||||||
COPY . /src/src/spice2x
|
COPY . /src/src/spice2x
|
||||||
WORKDIR /src/src/spice2x
|
WORKDIR /src/src/spice2x
|
||||||
CMD ["./build_all.sh"]
|
ENTRYPOINT ["./build_all.sh"]
|
||||||
|
|||||||
@@ -247,6 +247,25 @@ which also means that your hex edits are applicable directly.
|
|||||||
- sets the contents of the 16 segment display and disables writes from game
|
- sets the contents of the 16 segment display and disables writes from game
|
||||||
- ticker_reset()
|
- ticker_reset()
|
||||||
- re-enables writes from game
|
- re-enables writes from game
|
||||||
|
- tapeled_get(name: str, ...)
|
||||||
|
- returns a list containing a dict of the current tape LED states. The dict keys are:
|
||||||
|
- `Stage Left`
|
||||||
|
- `Stage Right`
|
||||||
|
- `Cabinet Left`
|
||||||
|
- `Cabinet Right`
|
||||||
|
- `Control Panel Under`
|
||||||
|
- `Ceiling Left`
|
||||||
|
- `Title Left`
|
||||||
|
- `Title Right`
|
||||||
|
- `Ceiling Right`
|
||||||
|
- `Touch Panel Left`
|
||||||
|
- `Touch Panel Right`
|
||||||
|
- `Side Panel Left Inner`
|
||||||
|
- `Side Panel Left Outer`
|
||||||
|
- `Side Panel Left`
|
||||||
|
- `Side Panel Right Outer`
|
||||||
|
- `Side Panel Right Inner`
|
||||||
|
- `Side Panel Right`
|
||||||
|
|
||||||
#### LCD
|
#### LCD
|
||||||
- info()
|
- info()
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
namespace acio {
|
namespace acio {
|
||||||
HINSTANCE DLL_INSTANCE = nullptr;
|
HINSTANCE DLL_INSTANCE = nullptr;
|
||||||
std::vector<acio::ACIOModule *> MODULES;
|
std::vector<acio::ACIOModule *> MODULES;
|
||||||
|
std::atomic<bool> IO_INIT_IN_PROGRESS = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -58,6 +59,7 @@ static inline acio::HookMode get_hookmode() {
|
|||||||
|
|
||||||
void acio::attach() {
|
void acio::attach() {
|
||||||
log_info("acio", "SpiceTools ACIO");
|
log_info("acio", "SpiceTools ACIO");
|
||||||
|
IO_INIT_IN_PROGRESS = true;
|
||||||
|
|
||||||
// load settings and instance
|
// load settings and instance
|
||||||
acio::DLL_INSTANCE = LoadLibraryA("libacio.dll");
|
acio::DLL_INSTANCE = LoadLibraryA("libacio.dll");
|
||||||
@@ -111,6 +113,8 @@ void acio::attach() {
|
|||||||
for (auto &module : MODULES) {
|
for (auto &module : MODULES) {
|
||||||
module->attach();
|
module->attach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IO_INIT_IN_PROGRESS = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void acio::attach_icca() {
|
void acio::attach_icca() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -11,6 +12,7 @@ namespace acio {
|
|||||||
// globals
|
// globals
|
||||||
extern HINSTANCE DLL_INSTANCE;
|
extern HINSTANCE DLL_INSTANCE;
|
||||||
extern std::vector<acio::ACIOModule *> MODULES;
|
extern std::vector<acio::ACIOModule *> MODULES;
|
||||||
|
extern std::atomic<bool> IO_INIT_IN_PROGRESS;
|
||||||
|
|
||||||
void attach();
|
void attach();
|
||||||
void attach_icca();
|
void attach_icca();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace acio2emu {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IOBHandle::IOBHandle(std::wstring device) : device_(device) {
|
IOBHandle::IOBHandle(LPCWSTR device) : device_(device) {
|
||||||
nodes_[0] = std::make_unique<MasterNode>(this);
|
nodes_[0] = std::make_unique<MasterNode>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace acio2emu {
|
|||||||
void forward_packet_(const Packet &packet);
|
void forward_packet_(const Packet &packet);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IOBHandle(std::wstring device);
|
IOBHandle(LPCWSTR device);
|
||||||
|
|
||||||
bool register_node(std::unique_ptr<Node> node);
|
bool register_node(std::unique_ptr<Node> node);
|
||||||
int number_of_nodes() const;
|
int number_of_nodes() const;
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ bool ICCADevice::parse_msg(MessageData *msg_in,
|
|||||||
// send version data
|
// send version data
|
||||||
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
|
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
|
||||||
if (
|
if (
|
||||||
avs::game::is_model({"LDJ", "TBS", "UJK"}) ||
|
avs::game::is_model({"LDJ", "TBS", "UJK", "XIF"}) ||
|
||||||
// SDVX Valkyrie cabinet mode
|
// SDVX Valkyrie cabinet mode
|
||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
||||||
) {
|
) {
|
||||||
@@ -373,7 +373,7 @@ void ICCADevice::update_card(int unit) {
|
|||||||
bool kb_insert_press = false;
|
bool kb_insert_press = false;
|
||||||
|
|
||||||
// eamio keypress
|
// 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
|
// check for card
|
||||||
if (this->cards[unit] == nullptr && (eamuse_card_insert_consume(this->node_count, unit) || kb_insert_press)) {
|
if (this->cards[unit] == nullptr && (eamuse_card_insert_consume(this->node_count, unit) || kb_insert_press)) {
|
||||||
@@ -521,7 +521,7 @@ void ICCADevice::update_status(int unit) {
|
|||||||
buffer[10] = felica ? 0x01 : 0x00;
|
buffer[10] = felica ? 0x01 : 0x00;
|
||||||
|
|
||||||
} else if (
|
} else if (
|
||||||
avs::game::is_model({"LDJ", "TBS"}) ||
|
avs::game::is_model({"LDJ", "TBS", "XIF"}) ||
|
||||||
// SDVX Valkyrie cabinet mode
|
// SDVX Valkyrie cabinet mode
|
||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) {
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) {
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ using namespace rapidjson;
|
|||||||
|
|
||||||
namespace api::modules {
|
namespace api::modules {
|
||||||
|
|
||||||
|
std::optional<uint32_t> CAPTURE_QUALITY;
|
||||||
|
std::optional<uint32_t> CAPTURE_DIVIDE;
|
||||||
|
|
||||||
static thread_local std::vector<uint8_t> CAPTURE_BUFFER;
|
static thread_local std::vector<uint8_t> CAPTURE_BUFFER;
|
||||||
|
|
||||||
Capture::Capture() : Module("capture") {
|
Capture::Capture() : Module("capture") {
|
||||||
@@ -44,12 +47,21 @@ namespace api::modules {
|
|||||||
int screen = 0;
|
int screen = 0;
|
||||||
int quality = 70;
|
int quality = 70;
|
||||||
int divide = 1;
|
int divide = 1;
|
||||||
if (req.params.Size() > 0 && req.params[0].IsUint())
|
if (req.params.Size() > 0 && req.params[0].IsUint()) {
|
||||||
screen = req.params[0].GetUint();
|
screen = req.params[0].GetUint();
|
||||||
if (req.params.Size() > 1 && req.params[1].IsUint())
|
}
|
||||||
|
|
||||||
|
if (CAPTURE_QUALITY.has_value()) {
|
||||||
|
quality = CAPTURE_QUALITY.value();
|
||||||
|
} else if (req.params.Size() > 1 && req.params[1].IsUint()) {
|
||||||
quality = req.params[1].GetUint();
|
quality = req.params[1].GetUint();
|
||||||
if (req.params.Size() > 2 && req.params[2].IsUint())
|
}
|
||||||
|
|
||||||
|
if (CAPTURE_DIVIDE.has_value()) {
|
||||||
|
divide = CAPTURE_DIVIDE.value();
|
||||||
|
} else if (req.params.Size() > 2 && req.params[2].IsUint()) {
|
||||||
divide = req.params[2].GetUint();
|
divide = req.params[2].GetUint();
|
||||||
|
}
|
||||||
|
|
||||||
// receive JPEG data
|
// receive JPEG data
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "api/module.h"
|
#include "api/module.h"
|
||||||
#include "api/request.h"
|
#include "api/request.h"
|
||||||
|
|
||||||
namespace api::modules {
|
namespace api::modules {
|
||||||
|
|
||||||
|
extern std::optional<uint32_t> CAPTURE_QUALITY;
|
||||||
|
extern std::optional<uint32_t> CAPTURE_DIVIDE;
|
||||||
|
|
||||||
class Capture : public Module {
|
class Capture : public Module {
|
||||||
public:
|
public:
|
||||||
Capture();
|
Capture();
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
#include "iidx.h"
|
#include "iidx.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
|
||||||
#include "games/iidx/iidx.h"
|
|
||||||
#include "external/rapidjson/document.h"
|
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
|
||||||
namespace api::modules {
|
namespace api::modules {
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
@@ -17,6 +13,11 @@ namespace api::modules {
|
|||||||
functions["ticker_get"] = std::bind(&IIDX::ticker_get, this, _1, _2);
|
functions["ticker_get"] = std::bind(&IIDX::ticker_get, this, _1, _2);
|
||||||
functions["ticker_set"] = std::bind(&IIDX::ticker_set, this, _1, _2);
|
functions["ticker_set"] = std::bind(&IIDX::ticker_set, this, _1, _2);
|
||||||
functions["ticker_reset"] = std::bind(&IIDX::ticker_reset, this, _1, _2);
|
functions["ticker_reset"] = std::bind(&IIDX::ticker_reset, this, _1, _2);
|
||||||
|
functions["tapeled_get"] = std::bind(&IIDX::tapeled_get, this, _1, _2);
|
||||||
|
|
||||||
|
for (auto &light : games::iidx::TAPELED_MAPPING) {
|
||||||
|
this->lights_by_names.emplace(light.lightName, light);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,4 +70,51 @@ namespace api::modules {
|
|||||||
// disable read only
|
// disable read only
|
||||||
games::iidx::IIDXIO_LED_TICKER_READONLY = false;
|
games::iidx::IIDXIO_LED_TICKER_READONLY = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tapeled_get()
|
||||||
|
* tapeled_get(name: str, ...)
|
||||||
|
*/
|
||||||
|
void IIDX::tapeled_get(Request &req, Response &res) {
|
||||||
|
Value response_object(kObjectType);
|
||||||
|
|
||||||
|
// all tape leds
|
||||||
|
if (req.params.Size() == 0) {
|
||||||
|
// Iterate through each device and dump its lights data into the response
|
||||||
|
for (const auto &mapping : games::iidx::TAPELED_MAPPING) {
|
||||||
|
copy_tapeled_data(res, response_object, mapping);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// specified light names
|
||||||
|
for (Value ¶m : req.params.GetArray()) {
|
||||||
|
// check params
|
||||||
|
if (!param.IsString()) {
|
||||||
|
error_type(res, "name", "string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto name = param.GetString();
|
||||||
|
if (const auto &it = lights_by_names.find(name); it != lights_by_names.end()) {
|
||||||
|
const auto mapping = it->second.get();
|
||||||
|
copy_tapeled_data(res, response_object, mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.add_data(response_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IIDX::copy_tapeled_data(Response &res, Value &response_object, const tapeledutils::tape_led &mapping) {
|
||||||
|
// Create an array for the light state
|
||||||
|
Value light_state(kArrayType);
|
||||||
|
light_state.Reserve(mapping.data.capacity() * 3, res.doc()->GetAllocator());
|
||||||
|
for (const auto [r, g, b] : mapping.data) {
|
||||||
|
light_state.PushBack(r, res.doc()->GetAllocator());
|
||||||
|
light_state.PushBack(g, res.doc()->GetAllocator());
|
||||||
|
light_state.PushBack(b, res.doc()->GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't use StringRef here, turns some strings partially into null bytes for some reason
|
||||||
|
Value light_name(mapping.lightName.c_str(), res.doc()->GetAllocator());
|
||||||
|
response_object.AddMember(light_name, light_state, res.doc()->GetAllocator());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "api/module.h"
|
#include "api/module.h"
|
||||||
#include "api/request.h"
|
#include "api/request.h"
|
||||||
|
#include "games/iidx/iidx.h"
|
||||||
|
|
||||||
namespace api::modules {
|
namespace api::modules {
|
||||||
|
|
||||||
@@ -10,10 +11,16 @@ namespace api::modules {
|
|||||||
IIDX();
|
IIDX();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// state
|
||||||
|
robin_hood::unordered_map<std::string, std::reference_wrapper<tapeledutils::tape_led>> lights_by_names;
|
||||||
|
|
||||||
// function definitions
|
// function definitions
|
||||||
void ticker_get(Request &req, Response &res);
|
void ticker_get(Request &req, Response &res);
|
||||||
void ticker_set(Request &req, Response &res);
|
void ticker_set(Request &req, Response &res);
|
||||||
void ticker_reset(Request &req, Response &res);
|
void ticker_reset(Request &req, Response &res);
|
||||||
|
void tapeled_get(Request &req, Response &res);
|
||||||
|
|
||||||
|
// helper
|
||||||
|
void copy_tapeled_data(Response &res, rapidjson::Value &response_object, const tapeledutils::tape_led &mapping);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,3 +16,13 @@ def iidx_ticker_set(con: Connection, text: str):
|
|||||||
def iidx_ticker_reset(con: Connection):
|
def iidx_ticker_reset(con: Connection):
|
||||||
req = Request("iidx", "ticker_reset")
|
req = Request("iidx", "ticker_reset")
|
||||||
con.request(req)
|
con.request(req)
|
||||||
|
|
||||||
|
|
||||||
|
def iidx_tapeled_get(con: Connection, *light_names):
|
||||||
|
req = Request("iidx", "tapeled_get")
|
||||||
|
|
||||||
|
for light_name in light_names:
|
||||||
|
req.add_param(light_name)
|
||||||
|
|
||||||
|
res = con.request(req)
|
||||||
|
return res.get_data()
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "external/robin_hood.h"
|
#include "external/robin_hood.h"
|
||||||
#include "launcher/logger.h"
|
#include "launcher/logger.h"
|
||||||
|
#include "launcher/signal.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/fileutils.h"
|
#include "util/fileutils.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
@@ -1501,7 +1503,8 @@ namespace avs {
|
|||||||
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
|
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
|
||||||
"\n"
|
"\n"
|
||||||
, DLL_NAME, MODULE_PATH.string()) };
|
, 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;
|
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 &avs_path,
|
||||||
const std::string_view &src_path)
|
const std::string_view &src_path)
|
||||||
{
|
{
|
||||||
@@ -1745,6 +1758,7 @@ namespace avs {
|
|||||||
auto real_path = std::filesystem::absolute(src_path, err);
|
auto real_path = std::filesystem::absolute(src_path, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
avs_dir_err(real_path);
|
||||||
log_warning("avs-core", "failed to resolve '{}' path: {}", avs_path, err.message());
|
log_warning("avs-core", "failed to resolve '{}' path: {}", avs_path, err.message());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1754,7 +1768,9 @@ namespace avs {
|
|||||||
if (created) {
|
if (created) {
|
||||||
log_info("avs-core", "created '{}' at '{}'", avs_path, real_path.string());
|
log_info("avs-core", "created '{}' at '{}'", avs_path, real_path.string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
avs_dir_err(real_path);
|
||||||
log_warning("avs-core", "failed to create '{}' folder at '{}': {}",
|
log_warning("avs-core", "failed to create '{}' folder at '{}': {}",
|
||||||
avs_path,
|
avs_path,
|
||||||
real_path.string(),
|
real_path.string(),
|
||||||
@@ -1815,7 +1831,7 @@ namespace avs {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
create_dir(avs_path, device_path);
|
create_avs_dir(avs_path, device_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void create_avs_config_fs_table(
|
static void create_avs_config_fs_table(
|
||||||
@@ -1870,7 +1886,7 @@ namespace avs {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
create_dir(dst_path, src_path);
|
create_avs_dir(dst_path, src_path);
|
||||||
} while ((vfs_node = property_node_traversal(vfs_node, TRAVERSE_NEXT_SEARCH_RESULT)));
|
} while ((vfs_node = property_node_traversal(vfs_node, TRAVERSE_NEXT_SEARCH_RESULT)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1924,6 +1940,7 @@ namespace avs {
|
|||||||
static const char *LOG_LEVELS[] = { "disable", "fatal", "warning", "info", "misc", "all" };
|
static const char *LOG_LEVELS[] = { "disable", "fatal", "warning", "info", "misc", "all" };
|
||||||
char current_log_level_buffer[32] { 0 };
|
char current_log_level_buffer[32] { 0 };
|
||||||
uint32_t current_log_level = 0;
|
uint32_t current_log_level = 0;
|
||||||
|
std::string log_level_as_str;
|
||||||
|
|
||||||
if (VERSION == AVSLEGACY || VERSION == AVS21360) {
|
if (VERSION == AVSLEGACY || VERSION == AVS21360) {
|
||||||
auto level_node = property_search(config, config_node, "/log/level");
|
auto level_node = property_search(config, config_node, "/log/level");
|
||||||
@@ -1939,6 +1956,7 @@ namespace avs {
|
|||||||
{
|
{
|
||||||
if (current_log_level < std::size(LOG_LEVELS)) {
|
if (current_log_level < std::size(LOG_LEVELS)) {
|
||||||
log_info("avs-core", "log level: {}", LOG_LEVELS[current_log_level]);
|
log_info("avs-core", "log level: {}", LOG_LEVELS[current_log_level]);
|
||||||
|
log_level_as_str = LOG_LEVELS[current_log_level];
|
||||||
} else {
|
} else {
|
||||||
log_fatal("avs-core", "log level ({}) is invalid!", current_log_level);
|
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",
|
level_node = property_node_create(config, config_node, NODE_TYPE_str, "/log/level",
|
||||||
LOG_LEVELS[current_log_level]);
|
LOG_LEVELS[current_log_level]);
|
||||||
} else {
|
} 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",
|
if (property_node_refer(config, config_node, "/log/level",
|
||||||
NODE_TYPE_str, current_log_level_buffer, sizeof(current_log_level_buffer)) > 0)
|
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 {
|
} 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
|
// fix time offset
|
||||||
auto t_now = std::time(nullptr);
|
auto t_now = std::time(nullptr);
|
||||||
auto tm_now = *std::gmtime(&t_now);
|
auto tm_now = *std::gmtime(&t_now);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
namespace avs {
|
namespace avs {
|
||||||
namespace core {
|
namespace core {
|
||||||
|
|||||||
+16
-2
@@ -41,6 +41,7 @@ namespace avs {
|
|||||||
int HTTP11 = -1;
|
int HTTP11 = -1;
|
||||||
int URL_SLASH = -1;
|
int URL_SLASH = -1;
|
||||||
int PCB_TYPE = -1;
|
int PCB_TYPE = -1;
|
||||||
|
bool EA3_DEBUG_VERBOSE = false;
|
||||||
|
|
||||||
// handle
|
// handle
|
||||||
std::string VERSION_STR = "unknown";
|
std::string VERSION_STR = "unknown";
|
||||||
@@ -149,7 +150,9 @@ namespace avs {
|
|||||||
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
|
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
|
||||||
"\n"
|
"\n"
|
||||||
, DLL_NAME, MODULE_PATH.string()) };
|
, 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +359,12 @@ namespace avs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fall back to default PCBID if node is not found
|
||||||
|
if (!EA3_PCBID[0] && PCBID_CUSTOM.empty()) {
|
||||||
|
log_warning("avs-ea3", "no PCBID set, falling back to default PCBID value (04040000000000000000)");
|
||||||
|
PCBID_CUSTOM = "04040000000000000000";
|
||||||
|
}
|
||||||
|
|
||||||
// custom PCBID
|
// custom PCBID
|
||||||
if (!PCBID_CUSTOM.empty()) {
|
if (!PCBID_CUSTOM.empty()) {
|
||||||
|
|
||||||
@@ -399,13 +408,18 @@ namespace avs {
|
|||||||
avs::core::NODE_TYPE_str, "/ea3/id/accountid", &EA3_ACCOUNTID);
|
avs::core::NODE_TYPE_str, "/ea3/id/accountid", &EA3_ACCOUNTID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if PCBID is defined
|
// check if PCBID is defined - should never hit, left for sanity check only
|
||||||
if (avs::core::property_search(ea3_config, nullptr, "/ea3/id/pcbid") == nullptr) {
|
if (avs::core::property_search(ea3_config, nullptr, "/ea3/id/pcbid") == nullptr) {
|
||||||
log_fatal("avs-ea3", "node not found: /ea3/id/pcbid (try using -p to specify PCBID)");
|
log_fatal("avs-ea3", "node not found: /ea3/id/pcbid (try using -p to specify PCBID)");
|
||||||
} else if (strlen(EA3_PCBID) == 0) {
|
} else if (strlen(EA3_PCBID) == 0) {
|
||||||
log_fatal("avs-ea3", "no PCBID set (try using -p to specify PCBID)");
|
log_fatal("avs-ea3", "no PCBID set (try using -p to specify PCBID)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove <debug> since it can expose pcbid in logged requests
|
||||||
|
if (!EA3_DEBUG_VERBOSE) {
|
||||||
|
avs::core::property_search_remove_safe(ea3_config, nullptr, "/ea3/debug/verbose");
|
||||||
|
}
|
||||||
|
|
||||||
// remember IDs
|
// remember IDs
|
||||||
char pcbid_buffer[256] { 0 };
|
char pcbid_buffer[256] { 0 };
|
||||||
char accountid_buffer[256] { 0 };
|
char accountid_buffer[256] { 0 };
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace avs {
|
|||||||
extern int HTTP11;
|
extern int HTTP11;
|
||||||
extern int URL_SLASH;
|
extern int URL_SLASH;
|
||||||
extern int PCB_TYPE;
|
extern int PCB_TYPE;
|
||||||
|
extern bool EA3_DEBUG_VERBOSE;
|
||||||
|
|
||||||
// handle
|
// handle
|
||||||
extern std::string VERSION_STR;
|
extern std::string VERSION_STR;
|
||||||
|
|||||||
@@ -76,24 +76,46 @@ namespace avs {
|
|||||||
const auto dll_path_s = dll_path.string();
|
const auto dll_path_s = dll_path.string();
|
||||||
log_info("avs-game", "DLL path: {}", dll_path_s.c_str());
|
log_info("avs-game", "DLL path: {}", dll_path_s.c_str());
|
||||||
|
|
||||||
if (MAX_PATH <= (dll_path_s.length() + 64)) {
|
// MAX_PATH is 260
|
||||||
|
if (130 <= dll_path_s.length()) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"avs-game",
|
"avs-game",
|
||||||
"PATH TOO LONG WARNING\n\n\n"
|
"PATH TOO LONG WARNING\n\n"
|
||||||
"-------------------------------------------------------------------\n"
|
"-------------------------------------------------------------------\n"
|
||||||
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||||
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||||
|
" PATH TOO LONG \n"
|
||||||
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||||
"'{}' has a length of {}\n"
|
"The path '{}'\n"
|
||||||
"Most of these games will behave unexpectedly when the path is too long,\n"
|
" has a length of {}\n"
|
||||||
"often resulting in random crashes. Move the game contents to a directory\n"
|
"Most of these games may behave unexpectedly when the path is too\n"
|
||||||
"with shorter path.\n"
|
"long, often resulting in random crashes. Move the game contents to\n"
|
||||||
"-------------------------------------------------------------------\n\n\n",
|
"a directory with shorter path.\n"
|
||||||
|
"-------------------------------------------------------------------\n\n",
|
||||||
dll_path_s, dll_path_s.length());
|
dll_path_s, dll_path_s.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ddr gamemdx.dll user error
|
||||||
|
if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") {
|
||||||
|
log_warning(
|
||||||
|
"ddr",
|
||||||
|
"BAD GAME DLL ERROR\n\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
"!!! -exec gamemdx.dll was specified !!!\n"
|
||||||
|
"!!! this is the wrong DLL; the game will not load !!!\n"
|
||||||
|
"!!! 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
|
||||||
if (!fileutils::file_exists(dll_path)) {
|
if (!fileutils::file_exists(dll_path)) {
|
||||||
log_warning("avs-game", "game DLL could not be found on disk: {}", dll_path.string().c_str());
|
log_warning("avs-game", "game DLL could not be found on disk: {}", dll_path.string().c_str());
|
||||||
log_warning("avs-game", "double check -exec and -modules parameters; unless you know what you're doing, leave them blank");
|
log_warning("avs-game", "double check -exec and -modules parameters; unless you know what you're doing, leave them blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileutils::verify_header_pe(dll_path)) {
|
if (fileutils::verify_header_pe(dll_path)) {
|
||||||
DLL_INSTANCE = libutils::load_library(dll_path);
|
DLL_INSTANCE = libutils::load_library(dll_path);
|
||||||
}
|
}
|
||||||
@@ -101,7 +123,7 @@ namespace avs {
|
|||||||
// load entry points
|
// load entry points
|
||||||
dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
dll_entry_init = (ENTRY_INIT_T) libutils::get_proc(DLL_INSTANCE, ENTRY_INIT_NAME);
|
||||||
dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
dll_entry_main = (ENTRY_MAIN_T) libutils::get_proc(DLL_INSTANCE, ENTRY_MAIN_NAME);
|
||||||
log_info("avs-game", "loaded successfully ({})", fmt::ptr(DLL_INSTANCE));
|
log_info("avs-game", "loaded {} successfully ({})", DLL_NAME, fmt::ptr(DLL_INSTANCE));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool entry_init(char *sid_code, void *app_param) {
|
bool entry_init(char *sid_code, void *app_param) {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#define IDC_STATIC -1
|
#define IDC_STATIC -1
|
||||||
#define IDD_DIALOG1 129
|
#define IDD_DIALOG1 129
|
||||||
#define IDR_CHANGELOG 130
|
|
||||||
#define IDR_LICENSES 131
|
#define IDR_LICENSES 131
|
||||||
#define IDR_PATCHES 132
|
#define IDR_PATCHES 132
|
||||||
#define IDR_README 133
|
#define IDR_README 133
|
||||||
|
|||||||
@@ -19,6 +19,25 @@ function trap_error_exit {
|
|||||||
trap trap_error_dbg DEBUG
|
trap trap_error_dbg DEBUG
|
||||||
trap trap_error_exit EXIT
|
trap trap_error_exit EXIT
|
||||||
|
|
||||||
|
IGNORE_CACHE=0
|
||||||
|
|
||||||
|
# Parse options
|
||||||
|
while getopts "ih" opt; do
|
||||||
|
case $opt in
|
||||||
|
i) IGNORE_CACHE=1 ;;
|
||||||
|
h)
|
||||||
|
echo "Usage: $0 [-i]"
|
||||||
|
echo " -i: Ignore build cache"
|
||||||
|
echo " -h: Show this help"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Invalid option: -$OPTARG" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
# settings
|
# settings
|
||||||
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "none")
|
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "none")
|
||||||
GIT_HEAD=$(git rev-parse HEAD || echo "none")
|
GIT_HEAD=$(git rev-parse HEAD || echo "none")
|
||||||
@@ -30,6 +49,7 @@ BUILDDIR_64_RELEASE="./cmake-build-release-64"
|
|||||||
BUILDDIR_64_DEBUG="./cmake-build-debug-64"
|
BUILDDIR_64_DEBUG="./cmake-build-debug-64"
|
||||||
DEBUG=0
|
DEBUG=0
|
||||||
OUTDIR="./bin/spice2x"
|
OUTDIR="./bin/spice2x"
|
||||||
|
OUTDIR_EXTRAS="./bin/spice2x/extras"
|
||||||
|
|
||||||
# disabled UPX since it tends to falsely trigger malware detection
|
# disabled UPX since it tends to falsely trigger malware detection
|
||||||
UPX_ENABLE=0
|
UPX_ENABLE=0
|
||||||
@@ -40,9 +60,10 @@ INCLUDE_SRC=1
|
|||||||
DIST_ENABLE=1
|
DIST_ENABLE=1
|
||||||
DIST_FOLDER="./dist"
|
DIST_FOLDER="./dist"
|
||||||
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
|
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.'
|
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"
|
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"
|
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
|
# determine build type
|
||||||
BUILD_TYPE="Release"
|
BUILD_TYPE="Release"
|
||||||
@@ -74,6 +95,15 @@ echo "Build Type: $BUILD_TYPE"
|
|||||||
echo "Cores: $CORES"
|
echo "Cores: $CORES"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
if ((IGNORE_CACHE > 0))
|
||||||
|
then
|
||||||
|
echo "Ignoring build cache..."
|
||||||
|
else
|
||||||
|
export CCACHE_DIR="$(pwd)/.ccache"
|
||||||
|
export CMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
export CMAKE_C_COMPILER_LAUNCHER=ccache
|
||||||
|
fi
|
||||||
|
|
||||||
time (
|
time (
|
||||||
# 32 bit
|
# 32 bit
|
||||||
echo "Building 32bit targets..."
|
echo "Building 32bit targets..."
|
||||||
@@ -151,10 +181,17 @@ fi
|
|||||||
|
|
||||||
# copy to output directory
|
# copy to output directory
|
||||||
echo "Copy files to output directory..."
|
echo "Copy files to output directory..."
|
||||||
|
|
||||||
rm -rf ${OUTDIR}
|
rm -rf ${OUTDIR}
|
||||||
mkdir -p ${OUTDIR}
|
mkdir -p ${OUTDIR}
|
||||||
#mkdir -p ${OUTDIR}/stubs/32
|
mkdir -p ${OUTDIR}/stubs/32
|
||||||
mkdir -p ${OUTDIR}/stubs/64
|
mkdir -p ${OUTDIR}/stubs/64
|
||||||
|
|
||||||
|
rm -rf ${OUTDIR_EXTRAS}
|
||||||
|
mkdir -p ${OUTDIR_EXTRAS}
|
||||||
|
mkdir -p ${OUTDIR_EXTRAS}/largeaddressaware
|
||||||
|
mkdir -p ${OUTDIR_EXTRAS}/linux
|
||||||
|
|
||||||
if false # ((DEBUG > 0))
|
if false # ((DEBUG > 0))
|
||||||
then
|
then
|
||||||
# debug files
|
# debug files
|
||||||
@@ -171,18 +208,24 @@ then
|
|||||||
#cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
#cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
#cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
#cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
#cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
|
#cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||||
else
|
else
|
||||||
# release files
|
# release files
|
||||||
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
|
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.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_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/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||||
#cp ${BUILDDIR_32}/spicetools/32/kld.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.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/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/kld.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/nvcuda.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
cp ${BUILDDIR_64}/spicetools/64/nvcuvid.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||||
|
cp ${BUILDDIR_32}/spicetools/32/cpusbxpkm.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# pack source files to output directory
|
# pack source files to output directory
|
||||||
@@ -196,10 +239,10 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# copy resources
|
# copy resources
|
||||||
rm -rf ${OUTDIR}/api
|
rm -rf ${OUTDIR_EXTRAS}/api
|
||||||
mkdir ${OUTDIR}/api
|
mkdir ${OUTDIR_EXTRAS}/api
|
||||||
find ./api/resources/python -name "__pycache__" -exec rm -rf {} +
|
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
|
# build distribution archive
|
||||||
if ((DIST_ENABLE > 0))
|
if ((DIST_ENABLE > 0))
|
||||||
@@ -208,7 +251,9 @@ then
|
|||||||
mkdir -p ${DIST_FOLDER}
|
mkdir -p ${DIST_FOLDER}
|
||||||
rm -rf ${DIST_FOLDER}/${DIST_NAME}
|
rm -rf ${DIST_FOLDER}/${DIST_NAME}
|
||||||
pushd ${OUTDIR}/.. > /dev/null
|
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
|
popd > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
docker build --pull external/docker -t spicetools/deps
|
docker build --pull external/docker -t spicetools/deps
|
||||||
docker build --build-context gitroot=%cd%/../../.git . -t spicetools/spice --no-cache
|
docker build --build-context gitroot=%cd%/../../.git . -t spicetools/spice
|
||||||
docker run --rm -it -v %cd%/dist:/src/src/spice2x/dist -v %cd%/bin:/src/src/spice2x/bin spicetools/spice
|
docker run --rm -it -v %cd%/dist:/src/src/spice2x/dist -v %cd%/bin:/src/src/spice2x/bin -v %cd%/.ccache:/src/src/spice2x/.ccache spicetools/spice %*
|
||||||
@REM to generate PDBs, set DEBUG to 1 in build_all.sh, place cv2pdb in external\cv2pdb, and run below
|
@REM to generate PDBs, set DEBUG to 1 in build_all.sh, place cv2pdb in external\cv2pdb, and run below
|
||||||
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spicecfg.exe bin\spice2x\spicecfg-pdb.exe bin\spice2x\spicecfg-pdb.pdb
|
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spicecfg.exe bin\spice2x\spicecfg-pdb.exe bin\spice2x\spicecfg-pdb.pdb
|
||||||
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spice.exe bin\spice2x\spice-pdb.exe bin\spice2x\spice-pdb.pdb
|
@REM external\cv2pdb\cv2pdb.exe bin\spice2x\spice.exe bin\spice2x\spice-pdb.exe bin\spice2x\spice-pdb.pdb
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
docker build --pull $PWD/external/docker -t spicetools/deps --platform linux/x86_64
|
docker build --pull $PWD/external/docker -t spicetools/deps --platform linux/x86_64
|
||||||
docker build --build-context gitroot=$PWD/../../.git . -t spicetools/spice:latest --no-cache
|
docker build --build-context gitroot=$PWD/../../.git . -t spicetools/spice:latest
|
||||||
docker run --rm -v $PWD/dist:/src/src/spice2x/dist -v $PWD/bin:/src/src/spice2x/bin spicetools/spice
|
docker run --rm -v $PWD/dist:/src/src/spice2x/dist -v $PWD/bin:/src/src/spice2x/bin -v $PWD/.ccache:/src/src/spice2x/.ccache spicetools/spice "$@"
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
del /s /q .ccache
|
||||||
|
del /s /q dist
|
||||||
|
call build_docker.bat
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
IDR_CHANGELOG RCDATA "../changelog.txt"
|
|
||||||
IDR_LICENSES RCDATA "../licenses.txt"
|
IDR_LICENSES RCDATA "../licenses.txt"
|
||||||
IDR_PATCHES RCDATA "../build/patches.json"
|
IDR_PATCHES RCDATA "../build/patches.json"
|
||||||
IDR_README RCDATA "../readme.txt"
|
IDR_README RCDATA "../readme.txt"
|
||||||
|
|||||||
+34
-4
@@ -1,5 +1,8 @@
|
|||||||
#include "api.h"
|
#include "api.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "launcher/superexit.h"
|
||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
#include "rawinput/piuio.h"
|
#include "rawinput/piuio.h"
|
||||||
#include "util/time.h"
|
#include "util/time.h"
|
||||||
@@ -64,18 +67,29 @@ GameAPI::Buttons::State GameAPI::Buttons::getState(rawinput::RawInputManager *ma
|
|||||||
auto current_button = &_button;
|
auto current_button = &_button;
|
||||||
auto alternatives = check_alts ? ¤t_button->getAlternatives() : nullptr;
|
auto alternatives = check_alts ? ¤t_button->getAlternatives() : nullptr;
|
||||||
unsigned int button_count = 0;
|
unsigned int button_count = 0;
|
||||||
|
std::optional<bool> window_has_focus;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
// naive behavior
|
// naive behavior
|
||||||
if (current_button->isNaive()) {
|
if (current_button->isNaive()) {
|
||||||
|
GameAPI::Buttons::State state;
|
||||||
|
auto vkey = current_button->getVKey();
|
||||||
|
|
||||||
|
// check for focus
|
||||||
|
if (vkey != INVALID_VKEY && rawinput::NAIVE_REQUIRE_FOCUS) {
|
||||||
|
if (!window_has_focus.has_value()) {
|
||||||
|
window_has_focus = superexit::has_focus();
|
||||||
|
}
|
||||||
|
if (!window_has_focus.value()) {
|
||||||
|
vkey = INVALID_VKEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// read
|
// read
|
||||||
auto vkey = current_button->getVKey();
|
if (vkey == INVALID_VKEY) {
|
||||||
GameAPI::Buttons::State state;
|
|
||||||
if (vkey == 0xFF) {
|
|
||||||
state = BUTTON_NOT_PRESSED;
|
state = BUTTON_NOT_PRESSED;
|
||||||
} else {
|
} else {
|
||||||
state = (GetAsyncKeyState(current_button->getVKey()) & 0x8000) ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
state = (GetAsyncKeyState(vkey) & 0x8000) ? BUTTON_PRESSED : BUTTON_NOT_PRESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// invert
|
// invert
|
||||||
@@ -106,6 +120,16 @@ GameAPI::Buttons::State GameAPI::Buttons::getState(rawinput::RawInputManager *ma
|
|||||||
auto &devid = current_button->getDeviceIdentifier();
|
auto &devid = current_button->getDeviceIdentifier();
|
||||||
auto device = manager->devices_get(devid, false); // TODO: fix to update only
|
auto device = manager->devices_get(devid, false); // TODO: fix to update only
|
||||||
|
|
||||||
|
// check for focus
|
||||||
|
if (device && rawinput::RAWINPUT_REQUIRE_FOCUS) {
|
||||||
|
if (!window_has_focus.has_value()) {
|
||||||
|
window_has_focus = superexit::has_focus();
|
||||||
|
}
|
||||||
|
if (!window_has_focus.value()) {
|
||||||
|
device = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// get state if device was marked as updated
|
// get state if device was marked as updated
|
||||||
GameAPI::Buttons::State state = current_button->getLastState();
|
GameAPI::Buttons::State state = current_button->getLastState();
|
||||||
double *last_up = nullptr;
|
double *last_up = nullptr;
|
||||||
@@ -571,6 +595,12 @@ float GameAPI::Analogs::getState(rawinput::Device *device, Analog &analog) {
|
|||||||
switch (device->type) {
|
switch (device->type) {
|
||||||
case rawinput::MOUSE: {
|
case rawinput::MOUSE: {
|
||||||
|
|
||||||
|
// check for focus
|
||||||
|
if (rawinput::NAIVE_REQUIRE_FOCUS && !superexit::has_focus()) {
|
||||||
|
value = analog.getLastState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// get mouse position
|
// get mouse position
|
||||||
auto mouse = device->mouseInfo;
|
auto mouse = device->mouseInfo;
|
||||||
long pos;
|
long pos;
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ std::string Button::getDisplayString(rawinput::RawInputManager* manager) {
|
|||||||
std::string vKeyString = fmt::format("{:#x}", vKey);
|
std::string vKeyString = fmt::format("{:#x}", vKey);
|
||||||
|
|
||||||
// device must be existing
|
// device must be existing
|
||||||
if (this->device_identifier.empty() && vKey == 0xFF) {
|
if (this->device_identifier.empty() && vKey == INVALID_VKEY) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,14 @@ enum ButtonAnalogType {
|
|||||||
|
|
||||||
extern const char *ButtonAnalogTypeStr[];
|
extern const char *ButtonAnalogTypeStr[];
|
||||||
|
|
||||||
|
constexpr unsigned short INVALID_VKEY = UINT16_C(0xFF);
|
||||||
|
|
||||||
class Button {
|
class Button {
|
||||||
private:
|
private:
|
||||||
std::vector<Button> alternatives;
|
std::vector<Button> alternatives;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string device_identifier = "";
|
std::string device_identifier = "";
|
||||||
unsigned short vKey = 0xFF;
|
unsigned short vKey = INVALID_VKEY;
|
||||||
ButtonAnalogType analog_type = BAT_NONE;
|
ButtonAnalogType analog_type = BAT_NONE;
|
||||||
double debounce_up = 0.0;
|
double debounce_up = 0.0;
|
||||||
double debounce_down = 0.0;
|
double debounce_down = 0.0;
|
||||||
@@ -68,12 +70,12 @@ public:
|
|||||||
if (this->override_enabled) {
|
if (this->override_enabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this->vKey != 0xFF) {
|
if (this->vKey != INVALID_VKEY) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &alternative : this->alternatives) {
|
for (auto &alternative : this->alternatives) {
|
||||||
if (alternative.vKey != 0xFF) {
|
if (alternative.vKey != INVALID_VKEY) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +84,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void clearBindings() {
|
inline void clearBindings() {
|
||||||
vKey = 0xFF;
|
vKey = INVALID_VKEY;
|
||||||
alternatives.clear();
|
alternatives.clear();
|
||||||
device_identifier = "";
|
device_identifier = "";
|
||||||
analog_type = BAT_NONE;
|
analog_type = BAT_NONE;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
std::string value;
|
std::string value;
|
||||||
std::vector<Option> alternatives;
|
std::vector<Option> alternatives;
|
||||||
bool disabled = false;
|
bool disabled = false;
|
||||||
|
bool conflicting = false;
|
||||||
|
|
||||||
explicit Option(OptionDefinition definition, std::string value = "") :
|
explicit Option(OptionDefinition definition, std::string value = "") :
|
||||||
definition(std::move(definition)), value(std::move(value)) {
|
definition(std::move(definition)), value(std::move(value)) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define IDR_CHANGELOG 130
|
|
||||||
#define IDR_LICENSES 131
|
#define IDR_LICENSES 131
|
||||||
#define IDR_PATCHES 132
|
#define IDR_PATCHES 132
|
||||||
#define IDR_README 133
|
#define IDR_README 133
|
||||||
|
|||||||
@@ -15,12 +15,18 @@ namespace cfg {
|
|||||||
std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
||||||
|
|
||||||
ScreenResize::ScreenResize() {
|
ScreenResize::ScreenResize() {
|
||||||
|
bool file_exists = false;
|
||||||
if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) {
|
if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) {
|
||||||
this->config_path = SCREEN_RESIZE_CFG_PATH_OVERRIDE.value();
|
this->config_path = SCREEN_RESIZE_CFG_PATH_OVERRIDE.value();
|
||||||
} else {
|
|
||||||
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_screen_resize.json";
|
|
||||||
}
|
|
||||||
if (fileutils::file_exists(this->config_path)) {
|
if (fileutils::file_exists(this->config_path)) {
|
||||||
|
log_info("ScreenResize", "loading config from: {}", this->config_path.string());
|
||||||
|
file_exists = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this->config_path =
|
||||||
|
fileutils::get_config_file_path("ScreenResize", "spicetools_screen_resize.json", &file_exists);
|
||||||
|
}
|
||||||
|
if (file_exists) {
|
||||||
this->config_load();
|
this->config_load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,12 +35,6 @@ namespace cfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenResize::config_load() {
|
void ScreenResize::config_load() {
|
||||||
if (SCREEN_RESIZE_CFG_PATH_OVERRIDE.has_value()) {
|
|
||||||
log_info("ScreenResize", "loading custom config: {}", this->config_path.string());
|
|
||||||
} else {
|
|
||||||
log_info("ScreenResize", "loading global config from APPDATA");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string config = fileutils::text_read(this->config_path);
|
std::string config = fileutils::text_read(this->config_path);
|
||||||
if (config.empty()) {
|
if (config.empty()) {
|
||||||
log_info("ScreenResize", "config is empty");
|
log_info("ScreenResize", "config is empty");
|
||||||
@@ -87,6 +87,10 @@ namespace cfg {
|
|||||||
load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
|
load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
|
||||||
load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
|
load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
|
||||||
load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio);
|
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
|
// windowed settings are always under game settings
|
||||||
@@ -170,8 +174,6 @@ namespace cfg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScreenResize::config_save() {
|
void ScreenResize::config_save() {
|
||||||
log_info("ScreenResize", "saving config: {}", this->config_path.string());
|
|
||||||
|
|
||||||
rapidjson::Document doc;
|
rapidjson::Document doc;
|
||||||
std::string config = fileutils::text_read(this->config_path);
|
std::string config = fileutils::text_read(this->config_path);
|
||||||
if (!config.empty()) {
|
if (!config.empty()) {
|
||||||
@@ -203,6 +205,7 @@ namespace cfg {
|
|||||||
rapidjson::Pointer(root + prefix + "scale_x").Set(doc, scene.scale_x);
|
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 + "scale_y").Set(doc, scene.scale_y);
|
||||||
rapidjson::Pointer(root + prefix + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio);
|
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
|
// windowed mode settings
|
||||||
@@ -221,10 +224,10 @@ namespace cfg {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(this->config_path, buffer.GetString())) {
|
if (fileutils::write_config_file("ScreenResize", this->config_path, buffer.GetString())) {
|
||||||
// this->config_dirty = false;
|
// this->config_dirty = false;
|
||||||
} else {
|
} else {
|
||||||
log_warning("ScreenResize", "unable to save config file to {}", this->config_path.string());
|
log_warning("ScreenResize", "unable to save config file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,19 @@ namespace cfg {
|
|||||||
ResizableFrame = 2
|
ResizableFrame = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ScreenDuplicateMode {
|
||||||
|
None = 0,
|
||||||
|
CopyLeft = 1,
|
||||||
|
CopyRight = 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct fullscreen_setting {
|
struct fullscreen_setting {
|
||||||
int offset_x = 0;
|
int offset_x = 0;
|
||||||
int offset_y = 0;
|
int offset_y = 0;
|
||||||
float scale_x = 1.0;
|
float scale_x = 1.0;
|
||||||
float scale_y = 1.0;
|
float scale_y = 1.0;
|
||||||
bool keep_aspect_ratio = true;
|
bool keep_aspect_ratio = true;
|
||||||
|
ScreenDuplicateMode duplicate = ScreenDuplicateMode::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
||||||
|
|||||||
@@ -1,701 +0,0 @@
|
|||||||
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
|
|
||||||
+2
-1
@@ -11,6 +11,7 @@ RUN pacman --noconfirm -Syu git \
|
|||||||
mingw-w64-winpthreads \
|
mingw-w64-winpthreads \
|
||||||
mingw-w64-gcc \
|
mingw-w64-gcc \
|
||||||
mingw-w64-headers \
|
mingw-w64-headers \
|
||||||
mingw-w64-binutils
|
mingw-w64-binutils \
|
||||||
|
ccache
|
||||||
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||||
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay-bin.git --depth=1 && cd yay-bin && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay-bin.git --depth=1 && cd yay-bin && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
||||||
|
|||||||
+4
@@ -1527,8 +1527,10 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdangling-reference"
|
#pragma GCC diagnostic ignored "-Wdangling-reference"
|
||||||
|
#endif
|
||||||
|
|
||||||
// The type template parameter is there to avoid an ODR violation when using
|
// 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
|
// 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;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
template <bool IS_PACKED, typename Context, type, typename T,
|
template <bool IS_PACKED, typename Context, type, typename T,
|
||||||
FMT_ENABLE_IF(!IS_PACKED)>
|
FMT_ENABLE_IF(!IS_PACKED)>
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
project(imgui CXX)
|
project(imgui CXX)
|
||||||
|
|
||||||
set(HASH_LIBRARY_HEADERS
|
set(HASH_LIBRARY_HEADERS
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.9)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
cmake_policy(SET CMP0069 NEW)
|
cmake_policy(SET CMP0069 NEW)
|
||||||
project(minhook)
|
project(minhook)
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
@@ -23,6 +23,7 @@
|
|||||||
* Modified version.
|
* Modified version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef NO_SCARD
|
||||||
|
|
||||||
#include "scard.h"
|
#include "scard.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@@ -409,3 +410,5 @@ void scard_threadstart() {
|
|||||||
void scard_fini() {
|
void scard_fini() {
|
||||||
should_exit = true;
|
should_exit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace games::ccj {
|
|||||||
bool MOUSE_TRACKBALL_USE_TOGGLE = false;
|
bool MOUSE_TRACKBALL_USE_TOGGLE = false;
|
||||||
uint8_t TRACKBALL_SENSITIVITY = 10;
|
uint8_t TRACKBALL_SENSITIVITY = 10;
|
||||||
|
|
||||||
static HANDLE fakeHandle = (HANDLE)0xDEADBEEF;
|
static HANDLE fakeHandle = (HANDLE)0xDEADBEEFull;
|
||||||
static HWND hWnd = nullptr;
|
static HWND hWnd = nullptr;
|
||||||
static WNDPROC wndProc = nullptr;
|
static WNDPROC wndProc = nullptr;
|
||||||
static std::thread *tbThread = nullptr;
|
static std::thread *tbThread = nullptr;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace games::ddr {
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
bool SDMODE = false;
|
bool SDMODE = false;
|
||||||
|
bool NO_CODEC_REGISTRATION = false;
|
||||||
|
|
||||||
uint8_t DDR_TAPELEDS[TAPELED_DEVICE_COUNT][50][3] {};
|
uint8_t DDR_TAPELEDS[TAPELED_DEVICE_COUNT][50][3] {};
|
||||||
|
|
||||||
@@ -49,12 +50,82 @@ namespace games::ddr {
|
|||||||
return SendMessage_real(hWnd, Msg, wParam, lParam);
|
return SendMessage_real(hWnd, Msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool contains_only_ascii(const std::string& str) {
|
||||||
|
for (auto c: str) {
|
||||||
|
if (static_cast<unsigned char>(c) > 127) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DDRGame::DDRGame() : Game("Dance Dance Revolution") {
|
DDRGame::DDRGame() : Game("Dance Dance Revolution") {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DDRGame::register_codecs() {
|
||||||
|
// find where spice.exe / spice64.exe is located
|
||||||
|
const auto &spice_bin_path = libutils::module_file_name(nullptr).parent_path();
|
||||||
|
|
||||||
|
// find the com directory
|
||||||
|
std::filesystem::path dir = "";
|
||||||
|
if (MODULE_PATH == spice_bin_path) {
|
||||||
|
// try: \com
|
||||||
|
dir = spice_bin_path / "com";
|
||||||
|
} else {
|
||||||
|
// try: modules\..\com
|
||||||
|
dir = MODULE_PATH / ".." / "com";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileutils::dir_exists(dir)) {
|
||||||
|
log_info("ddr", "looking for codecs in this directory: {}", dir.string());
|
||||||
|
} else {
|
||||||
|
log_info("ddr", "codecs directory not found: {}", dir.string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &file : std::filesystem::directory_iterator(dir)) {
|
||||||
|
const auto &filename = file.path().filename();
|
||||||
|
const auto extension = strtolower(filename.extension().string());
|
||||||
|
|
||||||
|
if (extension != ".dll") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("ddr", "found DLL: {}, size: {} bytes", filename.string(), file.file_size());
|
||||||
|
if (filename == "k-clvsd.dll" || filename.string().find("xactengine") == 0) {
|
||||||
|
const std::wstring wcmd = L"regsvr32.exe /s \"" + file.path().wstring() + L"\"";
|
||||||
|
const std::string cmd = "regsvr32.exe /s \"" + file.path().string() + "\"";
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
std::thread t([wcmd, &result]() {
|
||||||
|
result = _wsystem(wcmd.c_str());
|
||||||
|
});
|
||||||
|
t.join();
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
log_info("ddr", "`{}` returned {}", cmd, result);
|
||||||
|
} else {
|
||||||
|
log_warning("ddr", "`{}` failed, returned {}", cmd, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contains_only_ascii(file.path().string())) {
|
||||||
|
log_warning(
|
||||||
|
"ddr",
|
||||||
|
"BAD PATH ERROR\n\n\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
"!!! filesystem path to codec contains non-ASCII characters! !!!\n"
|
||||||
|
"!!! this may cause the game to crash! !!!\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DDRGame::pre_attach() {
|
void DDRGame::pre_attach() {
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) {
|
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) {
|
||||||
log_fatal(
|
log_warning(
|
||||||
"ddr",
|
"ddr",
|
||||||
"BAD MODEL NAME ERROR\n\n\n"
|
"BAD MODEL NAME ERROR\n\n\n"
|
||||||
"!!! model name set to TDX, this is WRONG and will break your game !!!\n"
|
"!!! model name set to TDX, this is WRONG and will break your game !!!\n"
|
||||||
@@ -65,6 +136,8 @@ namespace games::ddr {
|
|||||||
"!!! !!!\n"
|
"!!! !!!\n"
|
||||||
"!!! model name set to TDX, this is WRONG and will break your game !!!\n\n\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') {
|
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::DEST[0] == 'U') {
|
||||||
@@ -87,6 +160,17 @@ namespace games::ddr {
|
|||||||
"!!! !!!\n\n\n"
|
"!!! !!!\n\n\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||||
|
if (!NO_CODEC_REGISTRATION) {
|
||||||
|
this->register_codecs();
|
||||||
|
} else {
|
||||||
|
log_warning(
|
||||||
|
"ddr",
|
||||||
|
"skipping codec registration (-ddrnocodec), "
|
||||||
|
"game may crash if you didn't register codecs before launching the game");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DDRGame::attach() {
|
void DDRGame::attach() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace games::ddr {
|
|||||||
|
|
||||||
// settings
|
// settings
|
||||||
extern bool SDMODE;
|
extern bool SDMODE;
|
||||||
|
extern bool NO_CODEC_REGISTRATION;
|
||||||
|
|
||||||
// Buffers to store RGB data for tape LEDs on gold cabinets
|
// Buffers to store RGB data for tape LEDs on gold cabinets
|
||||||
const size_t TAPELED_DEVICE_COUNT = 11;
|
const size_t TAPELED_DEVICE_COUNT = 11;
|
||||||
@@ -18,5 +19,8 @@ namespace games::ddr {
|
|||||||
virtual void pre_attach() override;
|
virtual void pre_attach() override;
|
||||||
virtual void attach() override;
|
virtual void attach() override;
|
||||||
virtual void detach() override;
|
virtual void detach() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void register_codecs();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,50 +409,27 @@ namespace games::iidx {
|
|||||||
* 16 - side panel right - 183 bytes - 61 colors
|
* 16 - side panel right - 183 bytes - 61 colors
|
||||||
*
|
*
|
||||||
* data is stored in RGB order, 3 bytes per color
|
* data is stored in RGB order, 3 bytes per color
|
||||||
*
|
|
||||||
* TODO: expose this data via API
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// data mapping
|
|
||||||
static struct TapeLedMapping {
|
|
||||||
size_t data_size;
|
|
||||||
int index_r, index_g, index_b;
|
|
||||||
|
|
||||||
TapeLedMapping(size_t data_size, int index_r, int index_g, int index_b)
|
|
||||||
: data_size(data_size), index_r(index_r), index_g(index_g), index_b(index_b) {}
|
|
||||||
|
|
||||||
} mapping[] = {
|
|
||||||
{ 19, Lights::StageLeftAvgR, Lights::StageLeftAvgG, Lights::StageLeftAvgB },
|
|
||||||
{ 19, Lights::StageRightAvgR, Lights::StageRightAvgG, Lights::StageRightAvgB },
|
|
||||||
{ 45, Lights::CabinetLeftAvgR, Lights::CabinetLeftAvgG, Lights::CabinetLeftAvgB },
|
|
||||||
{ 45, Lights::CabinetRightAvgR, Lights::CabinetRightAvgG, Lights::CabinetRightAvgB },
|
|
||||||
{ 21, Lights::ControlPanelUnderAvgR, Lights::ControlPanelUnderAvgG, Lights::ControlPanelUnderAvgB },
|
|
||||||
{ 54, Lights::CeilingLeftAvgR, Lights::CeilingLeftAvgG, Lights::CeilingLeftAvgB },
|
|
||||||
{ 11, Lights::TitleLeftAvgR, Lights::TitleLeftAvgG, Lights::TitleLeftAvgB },
|
|
||||||
{ 11, Lights::TitleRightAvgR, Lights::TitleRightAvgG, Lights::TitleRightAvgB },
|
|
||||||
{ 54, Lights::CeilingRightAvgR, Lights::CeilingRightAvgG, Lights::CeilingRightAvgB },
|
|
||||||
{ 17, Lights::TouchPanelLeftAvgR, Lights::TouchPanelLeftAvgG, Lights::TouchPanelLeftAvgB },
|
|
||||||
{ 17, Lights::TouchPanelRightAvgR, Lights::TouchPanelRightAvgG, Lights::TouchPanelRightAvgB },
|
|
||||||
{ 68, Lights::SidePanelLeftInnerAvgR, Lights::SidePanelLeftInnerAvgG, Lights::SidePanelLeftInnerAvgB },
|
|
||||||
{ 68, Lights::SidePanelLeftOuterAvgR, Lights::SidePanelLeftOuterAvgG, Lights::SidePanelLeftOuterAvgB },
|
|
||||||
{ 61, Lights::SidePanelLeftAvgR, Lights::SidePanelLeftAvgG, Lights::SidePanelLeftAvgB },
|
|
||||||
{ 68, Lights::SidePanelRightOuterAvgR, Lights::SidePanelRightOuterAvgG, Lights::SidePanelRightOuterAvgB },
|
|
||||||
{ 68, Lights::SidePanelRightInnerAvgR, Lights::SidePanelRightInnerAvgG, Lights::SidePanelRightInnerAvgB },
|
|
||||||
{ 61, Lights::SidePanelRightAvgR, Lights::SidePanelRightAvgG, Lights::SidePanelRightAvgB },
|
|
||||||
};
|
|
||||||
|
|
||||||
// check index bounds
|
// check index bounds
|
||||||
if (tapeledutils::is_enabled() && index < std::size(mapping)) {
|
if (tapeledutils::is_enabled() && index < std::size(TAPELED_MAPPING)) {
|
||||||
auto &map = mapping[index];
|
auto &map = TAPELED_MAPPING[index];
|
||||||
|
const auto data_size = map.data.capacity();
|
||||||
|
|
||||||
// pick a color to use
|
// pick a color to use
|
||||||
const auto rgb = tapeledutils::pick_color_from_led_tape(data, map.data_size);
|
const auto rgb = tapeledutils::pick_color_from_led_tape(data, data_size);
|
||||||
|
|
||||||
// program the lights into API
|
// program the lights into API
|
||||||
auto &lights = get_lights();
|
auto &lights = get_lights();
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < data_size; ++i) {
|
||||||
|
map.data[i].r = data[i * 3];
|
||||||
|
map.data[i].g = data[i * 3 + 1];
|
||||||
|
map.data[i].b = data[i * 3 + 2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (This != custom_node) {
|
if (This != custom_node) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace games::iidx {
|
|||||||
static IIDXLocalCamera *front_camera = nullptr; // camera id #1
|
static IIDXLocalCamera *front_camera = nullptr; // camera id #1
|
||||||
std::vector<IIDXLocalCamera*> LOCAL_CAMERA_LIST = {};
|
std::vector<IIDXLocalCamera*> LOCAL_CAMERA_LIST = {};
|
||||||
static IDirect3DDeviceManager9 *s_pD3DManager = nullptr;
|
static IDirect3DDeviceManager9 *s_pD3DManager = nullptr;
|
||||||
std::filesystem::path CAMERA_CONFIG_PATH = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_camera_control.json";
|
std::filesystem::path CAMERA_CONFIG_PATH;
|
||||||
bool CAMERA_READY = false;
|
bool CAMERA_READY = false;
|
||||||
|
|
||||||
bool parse_cmd_params() {
|
bool parse_cmd_params() {
|
||||||
@@ -493,7 +493,8 @@ namespace games::iidx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool camera_config_load() {
|
bool camera_config_load() {
|
||||||
log_info("iidx:camhook", "loading config");
|
CAMERA_CONFIG_PATH =
|
||||||
|
fileutils::get_config_file_path("iidx::camhook", "spicetools_camera_control.json");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// read config file
|
// read config file
|
||||||
@@ -651,9 +652,9 @@ namespace games::iidx {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(CAMERA_CONFIG_PATH, buffer.GetString())) {
|
if (fileutils::write_config_file("iidx::camhook", CAMERA_CONFIG_PATH, buffer.GetString())) {
|
||||||
} else {
|
} else {
|
||||||
log_warning("iidx:camhook", "unable to save config file to {}", CAMERA_CONFIG_PATH.string());
|
log_warning("iidx:camhook", "unable to save config file");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "games/iidx/legacy_camera.h"
|
#include "games/iidx/legacy_camera.h"
|
||||||
|
|
||||||
|
#include "hooks/audio/audio.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
#include "hooks/cfgmgr32hook.h"
|
#include "hooks/cfgmgr32hook.h"
|
||||||
#include "hooks/devicehook.h"
|
#include "hooks/devicehook.h"
|
||||||
@@ -22,11 +23,15 @@
|
|||||||
#include "misc/wintouchemu.h"
|
#include "misc/wintouchemu.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/fileutils.h"
|
#include "util/fileutils.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
#include "util/memutils.h"
|
#include "util/memutils.h"
|
||||||
#include "util/sigscan.h"
|
#include "util/sigscan.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
#include "launcher/signal.h"
|
||||||
|
|
||||||
|
#include "external/robin_hood.h"
|
||||||
|
|
||||||
#include "bi2a.h"
|
#include "bi2a.h"
|
||||||
#include "bi2x_hook.h"
|
#include "bi2x_hook.h"
|
||||||
@@ -74,6 +79,26 @@ namespace games::iidx {
|
|||||||
bool IIDXIO_LED_TICKER_READONLY = false;
|
bool IIDXIO_LED_TICKER_READONLY = false;
|
||||||
std::mutex IIDX_LED_TICKER_LOCK;
|
std::mutex IIDX_LED_TICKER_LOCK;
|
||||||
|
|
||||||
|
tapeledutils::tape_led TAPELED_MAPPING[IIDX_TAPELED_TOTAL] = {
|
||||||
|
{ 19, Lights::StageLeftAvgR, Lights::StageLeftAvgG, Lights::StageLeftAvgB, "Stage Left" },
|
||||||
|
{ 19, Lights::StageRightAvgR, Lights::StageRightAvgG, Lights::StageRightAvgB, "Stage Right" },
|
||||||
|
{ 45, Lights::CabinetLeftAvgR, Lights::CabinetLeftAvgG, Lights::CabinetLeftAvgB, "Cabinet Left" },
|
||||||
|
{ 45, Lights::CabinetRightAvgR, Lights::CabinetRightAvgG, Lights::CabinetRightAvgB, "Cabinet Right" },
|
||||||
|
{ 21, Lights::ControlPanelUnderAvgR, Lights::ControlPanelUnderAvgG, Lights::ControlPanelUnderAvgB, "Control Panel Under" },
|
||||||
|
{ 54, Lights::CeilingLeftAvgR, Lights::CeilingLeftAvgG, Lights::CeilingLeftAvgB, "Ceiling Left" },
|
||||||
|
{ 11, Lights::TitleLeftAvgR, Lights::TitleLeftAvgG, Lights::TitleLeftAvgB, "Title Left" },
|
||||||
|
{ 11, Lights::TitleRightAvgR, Lights::TitleRightAvgG, Lights::TitleRightAvgB, "Title Right" },
|
||||||
|
{ 54, Lights::CeilingRightAvgR, Lights::CeilingRightAvgG, Lights::CeilingRightAvgB, "Ceiling Right" },
|
||||||
|
{ 17, Lights::TouchPanelLeftAvgR, Lights::TouchPanelLeftAvgG, Lights::TouchPanelLeftAvgB, "Touch Panel Left" },
|
||||||
|
{ 17, Lights::TouchPanelRightAvgR, Lights::TouchPanelRightAvgG, Lights::TouchPanelRightAvgB, "Touch Panel Right" },
|
||||||
|
{ 68, Lights::SidePanelLeftInnerAvgR, Lights::SidePanelLeftInnerAvgG, Lights::SidePanelLeftInnerAvgB, "Side Panel Left Inner" },
|
||||||
|
{ 68, Lights::SidePanelLeftOuterAvgR, Lights::SidePanelLeftOuterAvgG, Lights::SidePanelLeftOuterAvgB, "Side Panel Left Outer" },
|
||||||
|
{ 61, Lights::SidePanelLeftAvgR, Lights::SidePanelLeftAvgG, Lights::SidePanelLeftAvgB, "Side Panel Left" },
|
||||||
|
{ 68, Lights::SidePanelRightOuterAvgR, Lights::SidePanelRightOuterAvgG, Lights::SidePanelRightOuterAvgB, "Side Panel Right Outer" },
|
||||||
|
{ 68, Lights::SidePanelRightInnerAvgR, Lights::SidePanelRightInnerAvgG, Lights::SidePanelRightInnerAvgB, "Side Panel Right Inner" },
|
||||||
|
{ 61, Lights::SidePanelRightAvgR, Lights::SidePanelRightAvgG, Lights::SidePanelRightAvgB, "Side Panel Right" },
|
||||||
|
};
|
||||||
|
|
||||||
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
||||||
if (lpSubKey != nullptr && phkResult != nullptr) {
|
if (lpSubKey != nullptr && phkResult != nullptr) {
|
||||||
if (hKey == HKEY_LOCAL_MACHINE &&
|
if (hKey == HKEY_LOCAL_MACHINE &&
|
||||||
@@ -210,6 +235,9 @@ namespace games::iidx {
|
|||||||
} else if (data.find(" W:touch: missing trigger:") != std::string::npos) {
|
} else if (data.find(" W:touch: missing trigger:") != std::string::npos) {
|
||||||
out.clear();
|
out.clear();
|
||||||
return true;
|
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 {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -350,7 +378,11 @@ namespace games::iidx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hooks::audio::ENABLED) {
|
||||||
apply_audio_hacks();
|
apply_audio_hacks();
|
||||||
|
} else {
|
||||||
|
log_warning("iidx", "skipping audio hooks; disabled by user");
|
||||||
|
}
|
||||||
|
|
||||||
// ASIO device hook
|
// ASIO device hook
|
||||||
RegCloseKey_orig = detour::iat_try(
|
RegCloseKey_orig = detour::iat_try(
|
||||||
@@ -380,10 +412,6 @@ namespace games::iidx {
|
|||||||
|
|
||||||
// environment variables must be set before the DLL is loaded as the VC++ runtime copies all
|
// environment variables must be set before the DLL is loaded as the VC++ runtime copies all
|
||||||
// environment variables at startup
|
// environment variables at startup
|
||||||
if (DISABLE_CAMS) {
|
|
||||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SCREEN_MODE.has_value()) {
|
if (SCREEN_MODE.has_value()) {
|
||||||
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
|
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
|
||||||
}
|
}
|
||||||
@@ -400,7 +428,7 @@ namespace games::iidx {
|
|||||||
|
|
||||||
// check bad model name
|
// check bad model name
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDJ")) {
|
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDJ")) {
|
||||||
log_fatal(
|
log_warning(
|
||||||
"iidx",
|
"iidx",
|
||||||
"BAD MODEL NAME ERROR\n\n\n"
|
"BAD MODEL NAME ERROR\n\n\n"
|
||||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n"
|
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n"
|
||||||
@@ -418,6 +446,8 @@ namespace games::iidx {
|
|||||||
"!!! !!!\n"
|
"!!! !!!\n"
|
||||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n\n\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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -740,26 +770,30 @@ namespace games::iidx {
|
|||||||
0);
|
0);
|
||||||
|
|
||||||
// attempt to detect ASIO support
|
// attempt to detect ASIO support
|
||||||
|
// <=24 : 32-bit only
|
||||||
// 25-26: has neither (no patch needed - WASAPI Exclusive by default)
|
// 25-26: has neither (no patch needed - WASAPI Exclusive by default)
|
||||||
// 27-30: has both (envvar will be respected, ASIO or WASAPI)
|
// 27-30: has both (envvar will be respected, ASIO or WASAPI)
|
||||||
// 31+: only has XONAR (ASIO by default, signature patch can be used to force WASAPI - for now)
|
// 31+: only has XONAR (ASIO by default, signature patch can be used to force WASAPI - for now)
|
||||||
|
|
||||||
if (!has_SOUND_OUTPUT_DEVICE && !has_XONAR_SOUND_CARD) {
|
if (!has_SOUND_OUTPUT_DEVICE && !has_XONAR_SOUND_CARD) {
|
||||||
|
// iidx 25-26
|
||||||
log_info("iidx", "This game only uses WASAPI audio engine");
|
log_info("iidx", "This game only uses WASAPI audio engine");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_SOUND_OUTPUT_DEVICE && has_XONAR_SOUND_CARD) {
|
if (has_SOUND_OUTPUT_DEVICE && has_XONAR_SOUND_CARD) {
|
||||||
|
// iidx 27-30
|
||||||
log_info("iidx", "This game accepts SOUND_OUTPUT_DEVICE environment variable");
|
log_info("iidx", "This game accepts SOUND_OUTPUT_DEVICE environment variable");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("iidx", "This game supports ASIO but does not accept SOUND_OUTPUT_DEVICE environment variable");
|
log_info("iidx", "This game supports ASIO but does not accept SOUND_OUTPUT_DEVICE environment variable");
|
||||||
|
|
||||||
|
// patch game to force wasapi
|
||||||
if (SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
|
if (SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi") {
|
||||||
intptr_t result = replace_pattern(
|
intptr_t result = replace_pattern(
|
||||||
avs::game::DLL_INSTANCE,
|
avs::game::DLL_INSTANCE,
|
||||||
"FF5008E8????ECFF83780803740D",
|
"FF5008E8??????FF83780803740D",
|
||||||
"??????BB00000000EB169090????",
|
"??????BB00000000EB169090????",
|
||||||
0, 0);
|
0, 0);
|
||||||
|
|
||||||
@@ -774,6 +808,41 @@ namespace games::iidx {
|
|||||||
"Successfully forced WASAPI as audio engine using signature matching @ 0x{:x}.",
|
"Successfully forced WASAPI as audio engine using signature matching @ 0x{:x}.",
|
||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log_info("iidx", "Not applying force wasapi patch; game will use ASIO");
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch iidx32+ for asio compatibility
|
||||||
|
// only do this if NOT wasapi (as opposed to checking if it's asio)
|
||||||
|
// the patch is only really needed for (some) non-XONAR devices but since people sometimes disguise
|
||||||
|
// other devices as a XONAR, don't check for the exact string (common ASIO workaround for INF)
|
||||||
|
if (avs::game::is_ext(2024090100, MAXINT) &&
|
||||||
|
!(SOUND_OUTPUT_DEVICE_IN_EFFECT.has_value() && SOUND_OUTPUT_DEVICE_IN_EFFECT.value() == "wasapi")) {
|
||||||
|
|
||||||
|
// in iidx32 final:
|
||||||
|
// ff 50 08 call QWORD PTR [rax+0x8] ; ASIO instance AddRef
|
||||||
|
// 48 8b 4b 08 mov rcx,QWORD PTR [rbx+0x8]
|
||||||
|
// 48 8b 01 mov rax,QWORD PTR [rcx]
|
||||||
|
// ff 50 08 call QWORD PTR [rax+0x8] ; ASIO instance AddRef
|
||||||
|
|
||||||
|
intptr_t result = replace_pattern(
|
||||||
|
avs::game::DLL_INSTANCE,
|
||||||
|
"FF50????????????????FF50??4533C94533C0418D51",
|
||||||
|
"????????????????????909090??????????????????",
|
||||||
|
0, 0);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
log_warning(
|
||||||
|
"iidx",
|
||||||
|
"Failed to apply ASIO compatibility fix for iidx32+. "
|
||||||
|
"Unless patches are applied, your ASIO device ({}) may hang or fail to work",
|
||||||
|
ASIO_DRIVER->c_str());
|
||||||
|
} else {
|
||||||
|
log_info(
|
||||||
|
"iidx",
|
||||||
|
"Successfully applied ASIO compatibility fix for iidx32+ using signature matching @ 0x{:x}.",
|
||||||
|
result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "games/game.h"
|
#include "games/game.h"
|
||||||
|
|
||||||
|
#include "external/robin_hood.h"
|
||||||
|
#include "util/tapeled.h"
|
||||||
|
|
||||||
namespace games::iidx {
|
namespace games::iidx {
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
@@ -30,6 +34,10 @@ namespace games::iidx {
|
|||||||
extern bool IIDXIO_LED_TICKER_READONLY;
|
extern bool IIDXIO_LED_TICKER_READONLY;
|
||||||
extern std::mutex IIDX_LED_TICKER_LOCK;
|
extern std::mutex IIDX_LED_TICKER_LOCK;
|
||||||
|
|
||||||
|
constexpr int IIDX_TAPELED_TOTAL = 17;
|
||||||
|
// data mapping
|
||||||
|
extern tapeledutils::tape_led TAPELED_MAPPING[IIDX_TAPELED_TOTAL];
|
||||||
|
|
||||||
class IIDXGame : public games::Game {
|
class IIDXGame : public games::Game {
|
||||||
public:
|
public:
|
||||||
IIDXGame();
|
IIDXGame();
|
||||||
|
|||||||
@@ -85,12 +85,19 @@ namespace games::iidx {
|
|||||||
&m_pwszSymbolicLink,
|
&m_pwszSymbolicLink,
|
||||||
&m_cchSymbolicLink
|
&m_cchSymbolicLink
|
||||||
);
|
);
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] GetAllocatedString failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
log_misc("iidx:camhook", "[{}] Symlink: {}", m_name, GetSymLink());
|
log_misc("iidx:camhook", "[{}] Symlink: {}", m_name, GetSymLink());
|
||||||
|
|
||||||
// Create the media source object.
|
// Create the media source object.
|
||||||
hr = pActivate->ActivateObject(IID_PPV_ARGS(&m_pSource));
|
hr = pActivate->ActivateObject(IID_PPV_ARGS(&m_pSource));
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] ActivateObject failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// Retain reference to the camera
|
// Retain reference to the camera
|
||||||
m_pSource->AddRef();
|
m_pSource->AddRef();
|
||||||
@@ -98,13 +105,22 @@ namespace games::iidx {
|
|||||||
|
|
||||||
// Create an attribute store to hold initialization settings.
|
// Create an attribute store to hold initialization settings.
|
||||||
hr = WrappedMFCreateAttributes(&pAttributes, 2);
|
hr = WrappedMFCreateAttributes(&pAttributes, 2);
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] MFCreateAttributes failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
hr = pAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, pD3DManager);
|
hr = pAttributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, pD3DManager);
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] SetUnknown(MF_SOURCE_READER_D3D_MANAGER) failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
hr = pAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE);
|
hr = pAttributes->SetUINT32(MF_SOURCE_READER_DISABLE_DXVA, FALSE);
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] SetUINT32(MF_SOURCE_READER_DISABLE_DXVA) failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Color space conversion
|
// TODO: Color space conversion
|
||||||
// if (SUCCEEDED(hr)) {
|
// if (SUCCEEDED(hr)) {
|
||||||
@@ -120,11 +136,18 @@ namespace games::iidx {
|
|||||||
pAttributes,
|
pAttributes,
|
||||||
&m_pSourceReader
|
&m_pSourceReader
|
||||||
);
|
);
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] MFCreateSourceReaderFromMediaSource failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
log_misc("iidx:camhook", "[{}] Created source reader", m_name);
|
log_misc("iidx:camhook", "[{}] Created source reader", m_name);
|
||||||
|
|
||||||
hr = InitTargetTexture();
|
hr = InitTargetTexture();
|
||||||
if (FAILED(hr)) { goto done; }
|
if (FAILED(hr)) {
|
||||||
|
log_warning("iidx:camhook", "[{}] InitTargetTexture failed with {:#x}", m_name, (ULONG)hr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
// Camera should be still usable even if camera control is not supported
|
// Camera should be still usable even if camera control is not supported
|
||||||
InitCameraControl();
|
InitCameraControl();
|
||||||
@@ -134,7 +157,7 @@ namespace games::iidx {
|
|||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
log_misc("iidx:camhook", "[{}] Initialized", m_name);
|
log_misc("iidx:camhook", "[{}] Initialized", m_name);
|
||||||
} else {
|
} else {
|
||||||
log_warning("iidx:camhook", "[{}] Failed to create camera: {}", m_name, hr);
|
log_warning("iidx:camhook", "[{}] Failed to create camera: {:#x}", m_name, (ULONG)hr);
|
||||||
}
|
}
|
||||||
SafeRelease(&pAttributes);
|
SafeRelease(&pAttributes);
|
||||||
LeaveCriticalSection(&m_critsec);
|
LeaveCriticalSection(&m_critsec);
|
||||||
@@ -165,7 +188,7 @@ namespace games::iidx {
|
|||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
if (hr != MF_E_NO_MORE_TYPES) {
|
if (hr != MF_E_NO_MORE_TYPES) {
|
||||||
log_warning("iidx:camhook", "[{}] Cannot get media type {} {}", m_name, i, hr);
|
log_warning("iidx:camhook", "[{}] Cannot get media type {} {:#x}", m_name, i, (ULONG)hr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -584,7 +607,7 @@ namespace games::iidx {
|
|||||||
* Return values:
|
* Return values:
|
||||||
* S_OK: this is a "better" media type than the existing one
|
* S_OK: this is a "better" media type than the existing one
|
||||||
* S_FALSE: valid media type, but not "better"
|
* S_FALSE: valid media type, but not "better"
|
||||||
* E_*: invalid meia type
|
* E_*: invalid media type
|
||||||
*/
|
*/
|
||||||
HRESULT IIDXLocalCamera::TryMediaType(IMFMediaType *pType, UINT32 *pBestWidth, double *pBestFrameRate) {
|
HRESULT IIDXLocalCamera::TryMediaType(IMFMediaType *pType, UINT32 *pBestWidth, double *pBestFrameRate) {
|
||||||
HRESULT hr = S_OK;
|
HRESULT hr = S_OK;
|
||||||
@@ -595,13 +618,13 @@ namespace games::iidx {
|
|||||||
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
log_warning("iidx:camhook", "[{}] Failed to get subtype: {}", m_name, hr);
|
log_warning("iidx:camhook", "[{}] Failed to get subtype: {:#x}", m_name, (ULONG)hr);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
|
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
log_warning("iidx:camhook", "[{}] Failed to get frame size: {}", m_name, hr);
|
log_warning("iidx:camhook", "[{}] Failed to get frame size: {:#x}", m_name, (ULONG)hr);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +642,7 @@ namespace games::iidx {
|
|||||||
(UINT32*)&frameRate.Denominator
|
(UINT32*)&frameRate.Denominator
|
||||||
);
|
);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
log_warning("iidx:camhook", "[{}] Failed to get frame rate: {}", m_name, hr);
|
log_warning("iidx:camhook", "[{}] Failed to get frame rate: {:#x}", m_name, (ULONG)hr);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
double frameRateValue = frameRate.Numerator / frameRate.Denominator;
|
double frameRateValue = frameRate.Numerator / frameRate.Denominator;
|
||||||
@@ -696,7 +719,7 @@ namespace games::iidx {
|
|||||||
if (SUCCEEDED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
log_misc("iidx:camhook", "[{}] Created texture", m_name);
|
log_misc("iidx:camhook", "[{}] Created texture", m_name);
|
||||||
} else {
|
} else {
|
||||||
log_warning("iidx:camhook", "[{}] Failed to create texture: {}", m_name, hr);
|
log_warning("iidx:camhook", "[{}] Failed to create texture: {:#x}", m_name, (ULONG)hr);
|
||||||
}
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@@ -785,7 +808,7 @@ namespace games::iidx {
|
|||||||
FlushDrawCommands();
|
FlushDrawCommands();
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
log_warning("iidx:camhook", "Error in DrawSample {}", hr);
|
log_warning("iidx:camhook", "Error in DrawSample {:#x}", (ULONG)hr);
|
||||||
}
|
}
|
||||||
SafeRelease(&pCameraSurf);
|
SafeRelease(&pCameraSurf);
|
||||||
LeaveCriticalSection(&m_critsec);
|
LeaveCriticalSection(&m_critsec);
|
||||||
|
|||||||
@@ -266,8 +266,8 @@ namespace games::iidx::poke {
|
|||||||
y *= rawinput::TOUCHSCREEN_RANGE_Y;
|
y *= rawinput::TOUCHSCREEN_RANGE_Y;
|
||||||
} else if (GRAPHICS_IIDX_WSUB) {
|
} else if (GRAPHICS_IIDX_WSUB) {
|
||||||
// Scale to windowed subscreen
|
// Scale to windowed subscreen
|
||||||
x *= GRAPHICS_IIDX_WSUB_WIDTH;
|
x *= GRAPHICS_WSUB_WIDTH;
|
||||||
y *= GRAPHICS_IIDX_WSUB_HEIGHT;
|
y *= GRAPHICS_WSUB_HEIGHT;
|
||||||
} else if (GENERIC_SUB_WINDOW_FULLSIZE || !overlay::OVERLAY->get_active()) {
|
} else if (GENERIC_SUB_WINDOW_FULLSIZE || !overlay::OVERLAY->get_active()) {
|
||||||
// Overlay is not present, scale to main screen
|
// Overlay is not present, scale to main screen
|
||||||
if (GRAPHICS_WINDOWED) {
|
if (GRAPHICS_WINDOWED) {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "ccj/io.h"
|
#include "ccj/io.h"
|
||||||
#include "qks/io.h"
|
#include "qks/io.h"
|
||||||
#include "mfg/io.h"
|
#include "mfg/io.h"
|
||||||
|
#include "pc/io.h"
|
||||||
|
|
||||||
namespace games {
|
namespace games {
|
||||||
|
|
||||||
@@ -313,6 +314,15 @@ namespace games {
|
|||||||
buttons.insert({ mfg, mfg::get_buttons() });
|
buttons.insert({ mfg, mfg::get_buttons() });
|
||||||
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
||||||
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
||||||
|
|
||||||
|
// Polaris Chord
|
||||||
|
const std::string pc("Polaris Chord");
|
||||||
|
games.push_back(pc);
|
||||||
|
buttons.insert({ pc, pc::get_buttons() });
|
||||||
|
buttons_help.insert({ pc, pc::get_buttons_help() });
|
||||||
|
analogs.insert({ pc, pc::get_analogs() });
|
||||||
|
lights.insert({ pc, pc::get_lights() });
|
||||||
|
file_hints[pc].emplace_back("game/svm_Data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &get_games() {
|
const std::vector<std::string> &get_games() {
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ namespace games::jb {
|
|||||||
const auto current_path = std::filesystem::current_path();
|
const auto current_path = std::filesystem::current_path();
|
||||||
log_misc("jubeat", "current working directory: {}", current_path.string());
|
log_misc("jubeat", "current working directory: {}", current_path.string());
|
||||||
if (current_path.parent_path() == current_path.root_path()) {
|
if (current_path.parent_path() == current_path.root_path()) {
|
||||||
log_fatal(
|
log_warning(
|
||||||
"jubeat",
|
"jubeat",
|
||||||
"\n\nInvalid path error; jubeat cannot run from a directory in the drive root\n"
|
"\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"
|
"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"
|
"To fix this, create a new directory and move ALL game files there.\n\n"
|
||||||
"Your current working directory: {}\n",
|
"Your current working directory: {}\n",
|
||||||
current_path.string());
|
current_path.string());
|
||||||
|
|
||||||
|
log_fatal(
|
||||||
|
"jubeat",
|
||||||
|
"Invalid path error; jubeat cannot run from a directory in the drive root");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,14 @@
|
|||||||
|
|
||||||
namespace games::loveplus {
|
namespace games::loveplus {
|
||||||
|
|
||||||
|
bool CAMERA_ENABLE = false;
|
||||||
|
|
||||||
// touch stuff
|
// touch stuff
|
||||||
static bool TOUCH_ENABLE = false;
|
static bool TOUCH_ENABLE = false;
|
||||||
static bool TOUCH_ATTACHED = false;
|
static bool TOUCH_ATTACHED = false;
|
||||||
|
|
||||||
|
static std::string lp_args = "-noWatchDog -noIOError -noIrda -notarget";
|
||||||
|
|
||||||
void touch_update() {
|
void touch_update() {
|
||||||
|
|
||||||
// check if touch enabled
|
// check if touch enabled
|
||||||
@@ -28,16 +32,15 @@ namespace games::loveplus {
|
|||||||
if (!TOUCH_ATTACHED) {
|
if (!TOUCH_ATTACHED) {
|
||||||
|
|
||||||
// Find the game window.
|
// Find the game window.
|
||||||
// We check the foreground window first, then fall back to searching for the window title
|
HWND wnd = FindProcessWindowBeginsWith("LovePlusAC");
|
||||||
// All game versions seem to have their model first in the window title
|
|
||||||
HWND wnd = GetForegroundWindow();
|
|
||||||
if (!string_begins_with(GetActiveWindowTitle(), "LovePlus")) {
|
|
||||||
wnd = FindWindowBeginsWith(avs::game::MODEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach touch hook
|
// attach touch hook
|
||||||
if (wnd) {
|
if (wnd) {
|
||||||
log_info("loveplus", "using window handle for touch: {}", fmt::ptr(wnd));
|
log_info(
|
||||||
|
"loveplus",
|
||||||
|
"using window handle for touch: {} ({})",
|
||||||
|
fmt::ptr(wnd),
|
||||||
|
get_window_title(wnd));
|
||||||
touch_create_wnd(wnd);
|
touch_create_wnd(wnd);
|
||||||
} else {
|
} else {
|
||||||
log_info("loveplus", "falling back to the DirectX window handle for touch");
|
log_info("loveplus", "falling back to the DirectX window handle for touch");
|
||||||
@@ -117,12 +120,26 @@ namespace games::loveplus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LPSTR __stdcall GetCommandLineA_hook() {
|
static LPSTR __stdcall GetCommandLineA_hook() {
|
||||||
static std::string lp_args = "-win -noCamera -noWatchDog -noIOError -noIrda -notarget";
|
|
||||||
|
|
||||||
return lp_args.data();
|
return lp_args.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool lp_spam_remover(void *user, const std::string &data, logger::Style style, std::string &out) {
|
||||||
|
if (data.empty() || data[0] != '[') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data.find("> [INFO] err_code: 0, err_title: , err_str:") != std::string::npos) {
|
||||||
|
out = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
LovePlusGame::LovePlusGame() : Game("LovePlus") {
|
LovePlusGame::LovePlusGame() : Game("LovePlus") {
|
||||||
|
logger::hook_add(lp_spam_remover, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LovePlusGame::~LovePlusGame() {
|
||||||
|
logger::hook_remove(lp_spam_remover, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LovePlusGame::attach() {
|
void LovePlusGame::attach() {
|
||||||
@@ -157,9 +174,17 @@ namespace games::loveplus {
|
|||||||
HMODULE seteq = libutils::try_library("ad_hd_seteq_dll.dll");
|
HMODULE seteq = libutils::try_library("ad_hd_seteq_dll.dll");
|
||||||
detour::inline_hook((void *) SetEqualizer, libutils::try_proc(seteq, "SetEqualizer"));
|
detour::inline_hook((void *) SetEqualizer, libutils::try_proc(seteq, "SetEqualizer"));
|
||||||
|
|
||||||
|
// set up command line args
|
||||||
|
if (!CAMERA_ENABLE) {
|
||||||
|
lp_args += " -noCamera";
|
||||||
|
}
|
||||||
|
if (GRAPHICS_WINDOWED) {
|
||||||
|
lp_args += " -win";
|
||||||
|
}
|
||||||
// get command line hook
|
// get command line hook
|
||||||
HMODULE lpac = libutils::try_library("lpac.dll");
|
HMODULE lpac = libutils::try_library("lpac.dll");
|
||||||
detour::iat("GetCommandLineA", GetCommandLineA_hook, lpac);
|
detour::iat("GetCommandLineA", GetCommandLineA_hook, lpac);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LovePlusGame::detach() {
|
void LovePlusGame::detach() {
|
||||||
|
|||||||
@@ -4,12 +4,15 @@
|
|||||||
|
|
||||||
namespace games::loveplus {
|
namespace games::loveplus {
|
||||||
|
|
||||||
|
extern bool CAMERA_ENABLE;
|
||||||
|
|
||||||
// touch stuff
|
// touch stuff
|
||||||
void touch_update();
|
void touch_update();
|
||||||
|
|
||||||
class LovePlusGame : public games::Game {
|
class LovePlusGame : public games::Game {
|
||||||
public:
|
public:
|
||||||
LovePlusGame();
|
LovePlusGame();
|
||||||
|
virtual ~LovePlusGame() override;
|
||||||
virtual void attach() override;
|
virtual void attach() override;
|
||||||
virtual void detach() override;
|
virtual void detach() override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -288,6 +288,21 @@ namespace games::mfc {
|
|||||||
MFCGame::MFCGame() : Game("Mahjong Fight Club") {
|
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() {
|
void MFCGame::attach() {
|
||||||
Game::attach();
|
Game::attach();
|
||||||
|
|
||||||
@@ -308,6 +323,13 @@ namespace games::mfc {
|
|||||||
auto allinone_module = libutils::try_module("allinone.dll");
|
auto allinone_module = libutils::try_module("allinone.dll");
|
||||||
auto system_module = libutils::try_module("system.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
|
// network fix
|
||||||
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
|
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(
|
detour::inline_hook((void *) mouse_utl_step, libutils::try_proc(
|
||||||
allinone_module, "?mouse_utl_step@@YAXXZ"));
|
allinone_module, "?mouse_utl_step@@YAXXZ"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger::hook_add(spam_remover, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace games::mfg {
|
|||||||
SetEnvironmentVariableA("VFG_CABINET_TYPE", MFG_CABINET_TYPE.c_str());
|
SetEnvironmentVariableA("VFG_CABINET_TYPE", MFG_CABINET_TYPE.c_str());
|
||||||
|
|
||||||
// add card reader
|
// add card reader
|
||||||
portName = MFG_CABINET_TYPE == "UKS" ? L"\\\\.\\COM1" : L"\\\\.\\COM3";
|
portName = (MFG_CABINET_TYPE == "UKS") ? std::wstring(L"\\\\.\\COM1") : std::wstring(L"\\\\.\\COM3");
|
||||||
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
||||||
devicehook_init_trampoline();
|
devicehook_init_trampoline();
|
||||||
devicehook_add(acioHandle);
|
devicehook_add(acioHandle);
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace games::otoca {
|
|||||||
bool kb_insert_press = false;
|
bool kb_insert_press = false;
|
||||||
|
|
||||||
// eamio keypress
|
// 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
|
// check for card
|
||||||
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
|
if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) {
|
||||||
|
|||||||
@@ -0,0 +1,739 @@
|
|||||||
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "rawinput/rawinput.h"
|
||||||
|
#include "misc/eamuse.h"
|
||||||
|
#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
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct AIO_SCI_COMM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_NMGR_IOB2 {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1 {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__SETTING {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__INPUT
|
||||||
|
{
|
||||||
|
uint8_t DevIoCounter;
|
||||||
|
uint8_t bExIoAErr;
|
||||||
|
uint8_t bExIoBErr;
|
||||||
|
uint8_t bPcPowerOn;
|
||||||
|
uint8_t bPcPowerCheck;
|
||||||
|
uint8_t bCoin1Jam;
|
||||||
|
uint8_t bCoin2Jam;
|
||||||
|
uint8_t bCoin3Jam;
|
||||||
|
uint8_t bCoin4Jam;
|
||||||
|
uint8_t Coin1Count;
|
||||||
|
uint8_t Coin2Count;
|
||||||
|
uint8_t Coin3Count;
|
||||||
|
uint8_t Coin4Count;
|
||||||
|
uint16_t AnalogCh1;
|
||||||
|
uint16_t AnalogCh2;
|
||||||
|
uint16_t AnalogCh3;
|
||||||
|
uint16_t AnalogCh4;
|
||||||
|
uint8_t CN8_8;
|
||||||
|
uint8_t CN8_9;
|
||||||
|
uint8_t CN8_10;
|
||||||
|
uint8_t CN9_8;
|
||||||
|
uint8_t CN9_9;
|
||||||
|
uint8_t CN9_10;
|
||||||
|
uint8_t CN11_11;
|
||||||
|
uint8_t CN11_12;
|
||||||
|
uint8_t CN11_13;
|
||||||
|
uint8_t CN11_14;
|
||||||
|
uint8_t CN11_15;
|
||||||
|
uint8_t CN11_16;
|
||||||
|
uint8_t CN11_17;
|
||||||
|
uint8_t CN11_18;
|
||||||
|
uint8_t CN11_19;
|
||||||
|
uint8_t CN11_20;
|
||||||
|
uint8_t CN12_11;
|
||||||
|
uint8_t CN12_12;
|
||||||
|
uint8_t CN12_13;
|
||||||
|
uint8_t CN12_14;
|
||||||
|
uint8_t CN12_15;
|
||||||
|
uint8_t CN12_16;
|
||||||
|
uint8_t CN12_17;
|
||||||
|
uint8_t CN12_18;
|
||||||
|
uint8_t CN12_19;
|
||||||
|
uint8_t CN12_20;
|
||||||
|
uint8_t CN12_21;
|
||||||
|
uint8_t CN12_22;
|
||||||
|
uint8_t CN12_23;
|
||||||
|
uint8_t CN12_24;
|
||||||
|
uint8_t CN15_3;
|
||||||
|
uint8_t CN15_4;
|
||||||
|
uint8_t CN15_5;
|
||||||
|
uint8_t CN15_6;
|
||||||
|
uint8_t CN15_7;
|
||||||
|
uint8_t CN15_8;
|
||||||
|
uint8_t CN15_9;
|
||||||
|
uint8_t CN15_10;
|
||||||
|
uint8_t CN15_11;
|
||||||
|
uint8_t CN15_12;
|
||||||
|
uint8_t CN15_13;
|
||||||
|
uint8_t CN15_14;
|
||||||
|
uint8_t CN15_15;
|
||||||
|
uint8_t CN15_16;
|
||||||
|
uint8_t CN15_17;
|
||||||
|
uint8_t CN15_18;
|
||||||
|
uint8_t CN15_19;
|
||||||
|
uint8_t CN15_20;
|
||||||
|
uint8_t CN19_8;
|
||||||
|
uint8_t CN19_9;
|
||||||
|
uint8_t CN19_10;
|
||||||
|
uint8_t CN19_11;
|
||||||
|
uint8_t CN19_12;
|
||||||
|
uint8_t CN19_13;
|
||||||
|
uint8_t CN19_14;
|
||||||
|
uint8_t CN19_15;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__INPUTDATA {
|
||||||
|
uint8_t data[247];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__OUTPUTDATA {
|
||||||
|
uint8_t data[48];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__ICNPIN {
|
||||||
|
uint16_t Ain[4];
|
||||||
|
uint64_t CnPin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__DEVSTATUS {
|
||||||
|
uint8_t InputCounter;
|
||||||
|
uint8_t OutputCounter;
|
||||||
|
uint8_t IoResetCounter;
|
||||||
|
uint8_t TapeLedCounter;
|
||||||
|
uint8_t TapeLedRate[8];
|
||||||
|
AIO_IOB2_BI2X_AC1__INPUT Input;
|
||||||
|
AIO_IOB2_BI2X_AC1__INPUTDATA InputData;
|
||||||
|
AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData;
|
||||||
|
AIO_IOB2_BI2X_AC1__ICNPIN ICnPinHist[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
typedef AIO_IOB2_BI2X_AC1* (__fastcall *aioIob2Bi2xAC1_Create_t)(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId,
|
||||||
|
AIO_IOB2_BI2X_AC1__SETTING *i_Setting);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_GetDeviceStatus_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl,
|
||||||
|
AIO_IOB2_BI2X_AC1__DEVSTATUS *o_DevStatus);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetWatchDogTimer_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint8_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_AddCounter_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_Counter,
|
||||||
|
uint32_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetOutputData_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_CnPin,
|
||||||
|
uint8_t i_Data);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetTapeLedDataPart_t)(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);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_SetTapeLedDataGroup_t)(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_bfGroup);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_SetTapeLedDataLimit_t)(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_Channel,
|
||||||
|
uint8_t i_Scale, uint8_t i_Limit);
|
||||||
|
typedef AIO_IOB2_BI2X_WRFIRM *(__fastcall *aioIob2Bi2x_CreateWriteFirmContext_t)(uint32_t i_SerialNumber,
|
||||||
|
uint32_t i_bfIob);
|
||||||
|
typedef AIO_SCI_COMM* (__fastcall *aioIob2Bi2x_OpenSciUsbCdc_t)(uint32_t i_SerialNumber);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_DestroyWriteFirmContext_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||||||
|
typedef int32_t (__fastcall *aioIob2Bi2x_WriteFirmGetState_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||||||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsCompleted_t)(int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsError_t)(int32_t i_State);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
typedef AIO_NMGR_IOB2 *(__fastcall *aioNMgrIob2_Create_t)(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode);
|
||||||
|
typedef void (__fastcall *aioNMgrIob_BeginManage_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
typedef void (__fastcall *aioSci_Destroy_t)(AIO_SCI_COMM *i_pNodeMgr);
|
||||||
|
typedef void (__fastcall *aioNodeMgr_Destroy_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
typedef int32_t (__fastcall *aioNodeMgr_GetState_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsReady_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsError_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef void (__fastcall *aioNodeCtl_Destroy_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl);
|
||||||
|
typedef int32_t (__fastcall *aioNodeCtl_GetState_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsReady_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsError_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function pointers
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
static aioIob2Bi2xAC1_Create_t aioIob2Bi2xAC1_Create_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_GetDeviceStatus_t aioIob2Bi2xAC1_GetDeviceStatus_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetWatchDogTimer_t aioIob2Bi2xAC1_SetWatchDogTimer_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_AddCounter_t aioIob2Bi2xAC1_AddCounter_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetOutputData_t aioIob2Bi2xAC1_SetOutputData_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetTapeLedDataPart_t aioIob2Bi2xAC1_SetTapeLedDataPart_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_SetTapeLedDataGroup_t aioIob2Bi2x_SetTapeLedDataGroup_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_SetTapeLedDataLimit_t aioIob2Bi2x_SetTapeLedDataLimit_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_OpenSciUsbCdc_t aioIob2Bi2x_OpenSciUsbCdc_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_CreateWriteFirmContext_t aioIob2Bi2x_CreateWriteFirmContext_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_DestroyWriteFirmContext_t aioIob2Bi2x_DestroyWriteFirmContext_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmGetState_t aioIob2Bi2x_WriteFirmGetState_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmIsCompleted_t aioIob2Bi2x_WriteFirmIsCompleted_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmIsError_t aioIob2Bi2x_WriteFirmIsError_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
static aioNMgrIob2_Create_t aioNMgrIob2_Create_orig = nullptr;
|
||||||
|
static aioNMgrIob_BeginManage_t aioNMgrIob_BeginManage_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
static aioSci_Destroy_t aioSci_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_Destroy_t aioNodeMgr_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_GetState_t aioNodeMgr_GetState_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsReady_t aioNodeMgr_IsReady_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsError_t aioNodeMgr_IsError_orig = nullptr;
|
||||||
|
static aioNodeCtl_Destroy_t aioNodeCtl_Destroy_orig = nullptr;
|
||||||
|
static aioNodeCtl_GetState_t aioNodeCtl_GetState_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsReady_t aioNodeCtl_IsReady_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsError_t aioNodeCtl_IsError_orig = nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_AC1 *aioIob2Bi2xAc1;
|
||||||
|
static AIO_SCI_COMM *aioSciComm;
|
||||||
|
static AIO_NMGR_IOB2 *aioNmgrIob2;
|
||||||
|
static AIO_IOB2_BI2X_WRFIRM *aioIob2Bi2xWrfirm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_AC1* __fastcall aioIob2Bi2xAC1_Create(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId,
|
||||||
|
AIO_IOB2_BI2X_AC1__SETTING *i_Setting) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
log_info("bi2x_hook", "aioIob2Bi2xAC1_Create hook hit");
|
||||||
|
aioIob2Bi2xAc1 = new AIO_IOB2_BI2X_AC1;
|
||||||
|
return aioIob2Bi2xAc1;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2xAC1_Create_orig(i_pNodeMgr, i_DevId, i_Setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_GetDeviceStatus(AIO_IOB2_BI2X_AC1 *i_pNodeCtl,
|
||||||
|
AIO_IOB2_BI2X_AC1__DEVSTATUS *o_DevStatus) {
|
||||||
|
RI_MGR->devices_flush_output();
|
||||||
|
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_GetDeviceStatus_orig(i_pNodeCtl, o_DevStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(o_DevStatus, 0x00, sizeof(AIO_IOB2_BI2X_AC1__DEVSTATUS));
|
||||||
|
|
||||||
|
auto &buttons = get_buttons();
|
||||||
|
o_DevStatus->Input.CN8_8 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN8_9 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN8_10 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN15_10 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Headphone]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN15_12 = 0xFF; // Recorder off; present in I/O test menu but unused in game
|
||||||
|
|
||||||
|
o_DevStatus->Input.CN12_11 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button1]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_12 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button2]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_13 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button3]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_14 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button4]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_15 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button5]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_16 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button6]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_17 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button7]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_18 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button8]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_19 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button9]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_20 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button10]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_21 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button11]) ? 0 : 0xFF;
|
||||||
|
o_DevStatus->Input.CN12_22 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button12]) ? 0 : 0xFF;
|
||||||
|
|
||||||
|
auto &analogs = get_analogs();
|
||||||
|
|
||||||
|
// FADER-L
|
||||||
|
float val = 0.f;
|
||||||
|
if (analogs[Analogs::FaderL].isSet()) {
|
||||||
|
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])) {
|
||||||
|
val = 0.f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left])) {
|
||||||
|
val = -1.0f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right])) {
|
||||||
|
val = +1.0f;
|
||||||
|
}
|
||||||
|
o_DevStatus->Input.CN15_7 = (val < 0.2f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_6 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_5 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_4 = (val > -0.35f && val < 0.85f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN15_3 = (val > -0.2f) ? 0xFF : 0;
|
||||||
|
|
||||||
|
// FADER-R
|
||||||
|
val = 0.f;
|
||||||
|
if (analogs[Analogs::FaderR].isSet()) {
|
||||||
|
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])) {
|
||||||
|
val = 0.f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left])) {
|
||||||
|
val = -1.0f;
|
||||||
|
} else if (GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right])) {
|
||||||
|
val = +1.0f;
|
||||||
|
}
|
||||||
|
o_DevStatus->Input.CN11_20 = (val < 0.2f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN11_19 = (val > -0.85f && val < 0.35f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN9_10 = (val > -0.6f && val < 0.6f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN9_9 = (val > -0.35f && val < 0.85f) ? 0xFF : 0;
|
||||||
|
o_DevStatus->Input.CN9_8 = (val > -0.2f) ? 0xFF : 0;
|
||||||
|
|
||||||
|
// coin
|
||||||
|
o_DevStatus->Input.Coin1Count = eamuse_coin_get_stock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetWatchDogTimer(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint8_t i_Count) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetWatchDogTimer_orig(i_pNodeCtl, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_AddCounter(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_Counter, uint32_t i_Count) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1 && i_Count == 0) {
|
||||||
|
eamuse_coin_set_stock((uint16_t) i_Count);
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2xAC1_AddCounter_orig(i_pNodeCtl, i_Counter, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetOutputData(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_CnPin, uint8_t i_Data) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetOutputData_orig(i_pNodeCtl, i_CnPin, i_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_CnPin == 0x1) {
|
||||||
|
eamuse_coin_set_block(i_Data == 0xFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &lights = get_lights();
|
||||||
|
if (i_CnPin == 0x11) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_R), i_Data / 255.0f);
|
||||||
|
} else if (i_CnPin == 0x12) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_G), i_Data / 255.0f);
|
||||||
|
} else if (i_CnPin == 0x13) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_B), i_Data / 255.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetTapeLedDataPart_orig(i_pNodeCtl, i_TapeLedCh, i_Offset, i_pData, i_cntTapeLed, i_bReverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2x_SetTapeLedDataGroup_orig(i_pNodeCtl, i_bfGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2x_SetTapeLedDataLimit(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_Channel,
|
||||||
|
uint8_t i_Scale, uint8_t i_Limit) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2x_SetTapeLedDataLimit_orig(i_pNodeCtl, i_Channel, i_Scale, i_Limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_SCI_COMM *__fastcall aioIob2Bi2x_OpenSciUsbCdc(uint32_t i_SerialNumber) {
|
||||||
|
aioSciComm = new AIO_SCI_COMM;
|
||||||
|
return aioSciComm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_WRFIRM *__fastcall aioIob2Bi2x_CreateWriteFirmContext(
|
||||||
|
uint32_t i_SerialNumber, uint32_t i_bfIob) {
|
||||||
|
|
||||||
|
aioIob2Bi2xWrfirm = new AIO_IOB2_BI2X_WRFIRM;
|
||||||
|
return aioIob2Bi2xWrfirm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioIob2Bi2x_DestroyWriteFirmContext(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||||||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||||||
|
delete aioIob2Bi2xWrfirm;
|
||||||
|
aioIob2Bi2xWrfirm = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_DestroyWriteFirmContext_orig(i_pWrFirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioIob2Bi2x_WriteFirmGetState(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||||||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmGetState_orig(i_pWrFirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsCompleted(int32_t i_State) {
|
||||||
|
if (aioIob2Bi2xWrfirm != nullptr) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmIsCompleted_orig(i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsError(int32_t i_State) {
|
||||||
|
if (aioIob2Bi2xWrfirm != nullptr) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmIsError_orig(i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
|
||||||
|
static AIO_NMGR_IOB2 *__fastcall aioNMgrIob2_Create(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode) {
|
||||||
|
if (i_pSci == aioSciComm) {
|
||||||
|
aioNmgrIob2 = new AIO_NMGR_IOB2;
|
||||||
|
return aioNmgrIob2;
|
||||||
|
} else {
|
||||||
|
return aioNMgrIob2_Create_orig(i_pSci, i_bfMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNMgrIob_BeginManage(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr != aioNmgrIob2) {
|
||||||
|
return aioNMgrIob_BeginManage_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
|
||||||
|
static void __fastcall aioSci_Destroy(AIO_SCI_COMM *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioSciComm) {
|
||||||
|
delete aioSciComm;
|
||||||
|
} else {
|
||||||
|
return aioSci_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeMgr_Destroy(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
delete aioNmgrIob2;
|
||||||
|
aioNmgrIob2 = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeMgr_GetState(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_GetState_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsReady(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsReady_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsError(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsError_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeCtl_Destroy(AIO_IOB2_BI2X_AC1 *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
delete aioIob2Bi2xAc1;
|
||||||
|
aioIob2Bi2xAc1 = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_Destroy_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeCtl_GetState(AIO_IOB2_BI2X_AC1 *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_GetState_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsReady(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsReady_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsError(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsError_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bi2x_hook_init() {
|
||||||
|
// avoid double init
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// announce
|
||||||
|
log_info("bi2x_hook", "init");
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
const auto libaioIob2VideoDll = "libaio-iob2_video.dll";
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_Create",
|
||||||
|
aioIob2Bi2xAC1_Create, &aioIob2Bi2xAC1_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_GetDeviceStatus",
|
||||||
|
aioIob2Bi2xAC1_GetDeviceStatus, &aioIob2Bi2xAC1_GetDeviceStatus_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetWatchDogTimer",
|
||||||
|
aioIob2Bi2xAC1_SetWatchDogTimer, &aioIob2Bi2xAC1_SetWatchDogTimer_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_AddCounter",
|
||||||
|
aioIob2Bi2xAC1_AddCounter, &aioIob2Bi2xAC1_AddCounter_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetOutputData",
|
||||||
|
aioIob2Bi2xAC1_SetOutputData, &aioIob2Bi2xAC1_SetOutputData_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetTapeLedDataPart",
|
||||||
|
aioIob2Bi2xAC1_SetTapeLedDataPart, &aioIob2Bi2xAC1_SetTapeLedDataPart_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_SetTapeLedDataGroup",
|
||||||
|
aioIob2Bi2x_SetTapeLedDataGroup, &aioIob2Bi2x_SetTapeLedDataGroup_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_SetTapeLedDataLimit",
|
||||||
|
aioIob2Bi2x_SetTapeLedDataLimit, &aioIob2Bi2x_SetTapeLedDataLimit_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_OpenSciUsbCdc",
|
||||||
|
aioIob2Bi2x_OpenSciUsbCdc, &aioIob2Bi2x_OpenSciUsbCdc_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_CreateWriteFirmContext",
|
||||||
|
aioIob2Bi2x_CreateWriteFirmContext, &aioIob2Bi2x_CreateWriteFirmContext_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_DestroyWriteFirmContext",
|
||||||
|
aioIob2Bi2x_DestroyWriteFirmContext, &aioIob2Bi2x_DestroyWriteFirmContext_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmGetState",
|
||||||
|
aioIob2Bi2x_WriteFirmGetState, &aioIob2Bi2x_WriteFirmGetState_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsCompleted",
|
||||||
|
aioIob2Bi2x_WriteFirmIsCompleted, &aioIob2Bi2x_WriteFirmIsCompleted_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsError",
|
||||||
|
aioIob2Bi2x_WriteFirmIsError, &aioIob2Bi2x_WriteFirmIsError_orig);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
const auto libaioIobDll = "libaio-iob.dll";
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob2_Create",
|
||||||
|
aioNMgrIob2_Create, &aioNMgrIob2_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob_BeginManage",
|
||||||
|
aioNMgrIob_BeginManage, &aioNMgrIob_BeginManage_orig);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
const auto libaioDll = "libaio.dll";
|
||||||
|
execexe::trampoline_try(libaioDll, "aioSci_Destroy",
|
||||||
|
aioSci_Destroy, &aioSci_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_Destroy",
|
||||||
|
aioNodeMgr_Destroy, &aioNodeMgr_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_GetState",
|
||||||
|
aioNodeMgr_GetState, &aioNodeMgr_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsReady",
|
||||||
|
aioNodeMgr_IsReady, &aioNodeMgr_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsError",
|
||||||
|
aioNodeMgr_IsError, &aioNodeMgr_IsError_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_Destroy",
|
||||||
|
aioNodeCtl_Destroy, &aioNodeCtl_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_GetState",
|
||||||
|
aioNodeCtl_GetState, &aioNodeCtl_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsReady",
|
||||||
|
aioNodeCtl_IsReady, &aioNodeCtl_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||||||
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
void bi2x_hook_init();
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
std::vector<Button> &games::pc::get_buttons() {
|
||||||
|
static std::vector<Button> buttons;
|
||||||
|
|
||||||
|
if (buttons.empty()) {
|
||||||
|
buttons = GameAPI::Buttons::getButtons("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Buttons::sortButtons(
|
||||||
|
&buttons,
|
||||||
|
"Service",
|
||||||
|
"Test",
|
||||||
|
"Coin Mech",
|
||||||
|
"Button 1",
|
||||||
|
"Button 2",
|
||||||
|
"Button 3",
|
||||||
|
"Button 4",
|
||||||
|
"Button 5",
|
||||||
|
"Button 6",
|
||||||
|
"Button 7",
|
||||||
|
"Button 8",
|
||||||
|
"Button 9",
|
||||||
|
"Button 10",
|
||||||
|
"Button 11",
|
||||||
|
"Button 12",
|
||||||
|
"Fader-L Left",
|
||||||
|
"Fader-L Right",
|
||||||
|
"Fader-R Left",
|
||||||
|
"Fader-R Right",
|
||||||
|
"Headphone"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string games::pc::get_buttons_help() {
|
||||||
|
// keep to max 100 characters wide
|
||||||
|
return
|
||||||
|
" FADER-L FADER-R \n"
|
||||||
|
"\n"
|
||||||
|
" B1 B2 B3 ... B11 B12\n"
|
||||||
|
"\n"
|
||||||
|
" Most menu interactions are on the touch screen; you can use your mouse.\n"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Analog> &games::pc::get_analogs() {
|
||||||
|
static std::vector<Analog> analogs;
|
||||||
|
|
||||||
|
if (analogs.empty()) {
|
||||||
|
analogs = GameAPI::Analogs::getAnalogs("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Analogs::sortAnalogs(
|
||||||
|
&analogs,
|
||||||
|
"Fader-L",
|
||||||
|
"Fader-R"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return analogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Light> &games::pc::get_lights() {
|
||||||
|
static std::vector<Light> lights;
|
||||||
|
|
||||||
|
if (lights.empty()) {
|
||||||
|
lights = GameAPI::Lights::getLights("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Lights::sortLights(
|
||||||
|
&lights,
|
||||||
|
"IC Reader R",
|
||||||
|
"IC Reader G",
|
||||||
|
"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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "cfg/api.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
namespace Buttons {
|
||||||
|
enum {
|
||||||
|
Service,
|
||||||
|
Test,
|
||||||
|
CoinMech,
|
||||||
|
Button1,
|
||||||
|
Button2,
|
||||||
|
Button3,
|
||||||
|
Button4,
|
||||||
|
Button5,
|
||||||
|
Button6,
|
||||||
|
Button7,
|
||||||
|
Button8,
|
||||||
|
Button9,
|
||||||
|
Button10,
|
||||||
|
Button11,
|
||||||
|
Button12,
|
||||||
|
FaderL_Left,
|
||||||
|
FaderL_Right,
|
||||||
|
FaderR_Left,
|
||||||
|
FaderR_Right,
|
||||||
|
Headphone
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Analogs {
|
||||||
|
enum {
|
||||||
|
FaderL,
|
||||||
|
FaderR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Lights {
|
||||||
|
typedef enum {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getters
|
||||||
|
std::vector<Button> &get_buttons();
|
||||||
|
std::string get_buttons_help();
|
||||||
|
std::vector<Analog> &get_analogs();
|
||||||
|
std::vector<Light> &get_lights();
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
#include "pc.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
#include "bi2x_hook.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/fileutils.h"
|
||||||
|
#include "util/unity_player.h"
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "acioemu/handle.h"
|
||||||
|
#include "misc/wintouchemu.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
#include "rawinput/rawinput.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
std::string PC_INJECT_ARGS = "";
|
||||||
|
bool PC_NO_IO = false;
|
||||||
|
|
||||||
|
static acioemu::ACIOHandle *acioHandle = nullptr;
|
||||||
|
static std::wstring portName = L"COM1";
|
||||||
|
|
||||||
|
static decltype(RegisterRawInputDevices) *RegisterRawInputDevices_orig = nullptr;
|
||||||
|
static decltype(EnumDisplaySettingsW) *EnumDisplaySettingsW_orig = nullptr;
|
||||||
|
static decltype(QueryDisplayConfig) *QueryDisplayConfig_orig = nullptr;
|
||||||
|
|
||||||
|
static BOOL WINAPI RegisterRawInputDevices_hook(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) {
|
||||||
|
|
||||||
|
// if the caller is spice itself, then pass through.
|
||||||
|
if (pRawInputDevices &&
|
||||||
|
(uiNumDevices > 0) &&
|
||||||
|
(pRawInputDevices[0].hwndTarget == RI_MGR->input_hwnd)) {
|
||||||
|
|
||||||
|
return RegisterRawInputDevices_orig(pRawInputDevices, uiNumDevices, cbSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, it must be the game; prevent the game from registering for raw input
|
||||||
|
// and hijacking WM_INPUT messages.
|
||||||
|
SetLastError(0xDEADBEEF);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL WINAPI EnumDisplaySettingsW_hook(LPCWSTR lpszDeviceName, DWORD iModeNum, DEVMODEW* lpDevMode) {
|
||||||
|
auto result = EnumDisplaySettingsW_orig(lpszDeviceName, iModeNum, lpDevMode);
|
||||||
|
|
||||||
|
// https://docs.unity3d.com/2022.3/Documentation/ScriptReference/Screen-currentResolution.html
|
||||||
|
// "If the player is running in windowed mode, this returns the current dimensions of the game window in pixels and the display refresh rate."
|
||||||
|
// Override it to 1920x1080 to avoid broken UI under Windowed mode
|
||||||
|
if (result && iModeNum == ENUM_CURRENT_SETTINGS) {
|
||||||
|
// Actually make it returns size of the game window, Can I?
|
||||||
|
lpDevMode->dmPelsWidth = 1920;
|
||||||
|
lpDevMode->dmPelsHeight = 1080;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG WINAPI QueryDisplayConfig_hook(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO*, UINT32*, DISPLAYCONFIG_MODE_INFO*, DISPLAYCONFIG_TOPOLOGY_ID*) {
|
||||||
|
// make unity fallback to EnumDisplaySettingsW as I don't
|
||||||
|
// want to deal with this api which is way more complex
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCGame::attach() {
|
||||||
|
Game::attach();
|
||||||
|
|
||||||
|
// add card reader
|
||||||
|
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
||||||
|
devicehook_init_trampoline();
|
||||||
|
devicehook_add(acioHandle);
|
||||||
|
|
||||||
|
execexe::init();
|
||||||
|
execexe::init_deferred([] () {
|
||||||
|
execexe::init_port_hook(portName, acioHandle);
|
||||||
|
execexe::load_library("libaio.dll");
|
||||||
|
execexe::load_library("libaio-iob.dll");
|
||||||
|
execexe::load_library("libaio-iob_video.dll");
|
||||||
|
execexe::load_library("libaio-iob2_video.dll");
|
||||||
|
execexe::load_library("win10actlog.dll");
|
||||||
|
|
||||||
|
if (!PC_NO_IO) {
|
||||||
|
bi2x_hook_init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto user32Dll = "user32.dll";
|
||||||
|
detour::trampoline_try(user32Dll, "RegisterRawInputDevices",
|
||||||
|
RegisterRawInputDevices_hook, &RegisterRawInputDevices_orig);
|
||||||
|
detour::trampoline_try(user32Dll, "QueryDisplayConfig",
|
||||||
|
QueryDisplayConfig_hook, &QueryDisplayConfig_orig);
|
||||||
|
detour::trampoline_try(user32Dll, "EnumDisplaySettingsW",
|
||||||
|
EnumDisplaySettingsW_hook, &EnumDisplaySettingsW_orig);
|
||||||
|
|
||||||
|
if (GRAPHICS_SHOW_CURSOR) {
|
||||||
|
unity_utils::force_show_cursor(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unity_utils::set_args(
|
||||||
|
std::format("{} {}{}",
|
||||||
|
GetCommandLineA(),
|
||||||
|
PC_INJECT_ARGS,
|
||||||
|
unity_utils::get_unity_player_args()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCGame::detach() {
|
||||||
|
Game::detach();
|
||||||
|
|
||||||
|
devicehook_dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "games/game.h"
|
||||||
|
|
||||||
|
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:
|
||||||
|
PCGame() : Game("Polaris Chord") {}
|
||||||
|
|
||||||
|
virtual void attach() override;
|
||||||
|
virtual void detach() override;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ namespace games::pcm {
|
|||||||
static double BILL_DELAY = 2.0;
|
static double BILL_DELAY = 2.0;
|
||||||
|
|
||||||
static int bill_kind = 0;
|
static int bill_kind = 0;
|
||||||
|
static int accept_bill_kind = 0;
|
||||||
|
|
||||||
static int __cdecl BillVali_GetEscrowBillKind() {
|
static int __cdecl BillVali_GetEscrowBillKind() {
|
||||||
return bill_kind;
|
return bill_kind;
|
||||||
@@ -74,6 +75,12 @@ namespace games::pcm {
|
|||||||
BILL_IN_TIME = get_performance_seconds();
|
BILL_IN_TIME = get_performance_seconds();
|
||||||
} else if ((BILL_IN_TIME != 0) && ((BILL_IN_TIME + BILL_DELAY) <= get_performance_seconds())) {
|
} else if ((BILL_IN_TIME != 0) && ((BILL_IN_TIME + BILL_DELAY) <= get_performance_seconds())) {
|
||||||
BILL_IN_TIME = 0;
|
BILL_IN_TIME = 0;
|
||||||
|
|
||||||
|
if (accept_bill_kind != 0 && accept_bill_kind != bill_kind) {
|
||||||
|
bill_kind = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (bill_kind) {
|
switch (bill_kind) {
|
||||||
case 1:
|
case 1:
|
||||||
return 1;
|
return 1;
|
||||||
@@ -98,7 +105,8 @@ namespace games::pcm {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __cdecl BillVali_SetAcceptBill(int) {
|
static bool __cdecl BillVali_SetAcceptBill(int a1) {
|
||||||
|
accept_bill_kind = a1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,5 +156,13 @@ namespace games::pcm {
|
|||||||
system, "?GetEscrowBillKind@GsBillVali@@SAHXZ"));
|
system, "?GetEscrowBillKind@GsBillVali@@SAHXZ"));
|
||||||
detour::inline_hook(BillVali_SetAcceptBill, libutils::try_proc(
|
detour::inline_hook(BillVali_SetAcceptBill, libutils::try_proc(
|
||||||
system, "?SetAcceptBill@GsBillVali@@SA_NH@Z"));
|
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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,134 +14,24 @@
|
|||||||
#include <mfidl.h>
|
#include <mfidl.h>
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "hooks/cfgmgr32hook.h"
|
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/memutils.h"
|
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
static VTBL_TYPE(IMFActivate, GetAllocatedString) GetAllocatedString_orig = nullptr;
|
|
||||||
|
|
||||||
static decltype(MFEnumDeviceSources) *MFEnumDeviceSources_orig = nullptr;
|
|
||||||
|
|
||||||
namespace games::sdvx {
|
namespace games::sdvx {
|
||||||
|
|
||||||
static std::wstring CAMERA0_ID;
|
|
||||||
|
|
||||||
static HRESULT WINAPI GetAllocatedString_hook(IMFActivate* This, REFGUID guidKey, LPWSTR *ppwszValue,
|
|
||||||
UINT32 *pcchLength) {
|
|
||||||
// call the original
|
|
||||||
HRESULT result = GetAllocatedString_orig(This, guidKey, ppwszValue, pcchLength);
|
|
||||||
|
|
||||||
// try first camera
|
|
||||||
wchar_t *pwc = nullptr;
|
|
||||||
if (CAMERA0_ID.length() == 23)
|
|
||||||
pwc = wcsstr(*ppwszValue, CAMERA0_ID.c_str());
|
|
||||||
|
|
||||||
// check if camera could be identified
|
|
||||||
if (pwc) {
|
|
||||||
|
|
||||||
// fake the USB IDs
|
|
||||||
pwc[4] = L'2';
|
|
||||||
pwc[5] = L'8';
|
|
||||||
pwc[6] = L'8';
|
|
||||||
pwc[7] = L'c';
|
|
||||||
pwc[13] = L'0';
|
|
||||||
pwc[14] = L'0';
|
|
||||||
pwc[15] = L'0';
|
|
||||||
pwc[16] = L'2';
|
|
||||||
pwc[21] = L'0';
|
|
||||||
pwc[22] = L'0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// return original result
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hook_camera(IMFActivate* camera, size_t no, std::wstring camera_id, std::string camera_instance) {
|
|
||||||
|
|
||||||
// don't hook if camera 0 is already hooked
|
|
||||||
if (CAMERA0_ID.length() > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// save the camera ID
|
|
||||||
CAMERA0_ID = camera_id;
|
|
||||||
|
|
||||||
// cfgmgr hook
|
|
||||||
CFGMGR32_HOOK_SETTING camera_setting;
|
|
||||||
camera_setting.device_instance = 0xDEADBEEF;
|
|
||||||
camera_setting.parent_instance = ~camera_setting.device_instance;
|
|
||||||
camera_setting.device_id = "USB\\VEN_1022&DEV_7908";
|
|
||||||
camera_setting.device_node_id = "USB\\VID_288C&PID_0002&MI_00\\?&????????&?&????";
|
|
||||||
if (camera_instance.length() == 17) {
|
|
||||||
for (int i = 0; i < 17; i++) {
|
|
||||||
camera_setting.device_node_id[28 + i] = camera_instance[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cfgmgr32hook_add(camera_setting);
|
|
||||||
|
|
||||||
// save original method for later use
|
|
||||||
if (GetAllocatedString_orig == nullptr) {
|
|
||||||
GetAllocatedString_orig = camera->lpVtbl->GetAllocatedString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hook allocated string method for camera identification
|
|
||||||
memutils::VProtectGuard camera_guard(camera->lpVtbl);
|
|
||||||
camera->lpVtbl->GetAllocatedString = GetAllocatedString_hook;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate,
|
static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate,
|
||||||
UINT32 *pcSourceActivate) {
|
UINT32 *pcSourceActivate) {
|
||||||
|
|
||||||
// call original function
|
*pppSourceActivate = nullptr;
|
||||||
HRESULT result_orig = MFEnumDeviceSources_orig(pAttributes, pppSourceActivate, pcSourceActivate);
|
*pcSourceActivate = 0;
|
||||||
|
log_misc("sdvx", "MFEnumDeviceSources_hook called, returning 0 cameras");
|
||||||
// check for capture devices
|
return S_OK;
|
||||||
if (FAILED(result_orig) || !*pcSourceActivate) {
|
|
||||||
return result_orig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate cameras
|
|
||||||
size_t cam_hook_num = 0;
|
|
||||||
for (size_t cam_num = 0; cam_num < *pcSourceActivate && cam_hook_num < 1; cam_num++) {
|
|
||||||
|
|
||||||
// flip
|
|
||||||
size_t cam_num_flipped = cam_num;
|
|
||||||
|
|
||||||
// get camera link
|
|
||||||
IMFActivate *camera = (*pppSourceActivate)[cam_num_flipped];
|
|
||||||
LPWSTR camera_link_lpwstr;
|
|
||||||
UINT32 camera_link_length;
|
|
||||||
if (SUCCEEDED(camera->lpVtbl->GetAllocatedString(
|
|
||||||
camera,
|
|
||||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
|
|
||||||
&camera_link_lpwstr,
|
|
||||||
&camera_link_length))) {
|
|
||||||
|
|
||||||
// cut name to make ID
|
|
||||||
std::wstring camera_link_ws = std::wstring(camera_link_lpwstr);
|
|
||||||
std::wstring camera_id = camera_link_ws.substr(8, 23);
|
|
||||||
|
|
||||||
// get camera instance
|
|
||||||
std::string camera_link = ws2s(camera_link_ws);
|
|
||||||
std::string camera_instance = camera_link.substr(32, 17);
|
|
||||||
|
|
||||||
// hook the camera
|
|
||||||
hook_camera(camera, cam_hook_num, camera_id, camera_instance);
|
|
||||||
|
|
||||||
// increase camera hook number
|
|
||||||
cam_hook_num++;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return result
|
|
||||||
return result_orig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void camera_init() {
|
void camera_init() {
|
||||||
|
|
||||||
// camera media framework hook
|
// camera media framework hook
|
||||||
MFEnumDeviceSources_orig = detour::iat_try(
|
log_info("sdvx", "installing camera hooks...");
|
||||||
"MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE);
|
detour::iat_try("MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "hooks/sleephook.h"
|
#include "hooks/sleephook.h"
|
||||||
#include "hooks/winuser.h"
|
#include "hooks/winuser.h"
|
||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/sigscan.h"
|
#include "util/sigscan.h"
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "acioemu/handle.h"
|
#include "acioemu/handle.h"
|
||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
|
#include "launcher/signal.h"
|
||||||
|
|
||||||
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
|
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
|
||||||
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
|
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
|
||||||
@@ -39,7 +41,6 @@ namespace games::sdvx {
|
|||||||
const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)";
|
const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)";
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
bool DISABLECAMS = false;
|
|
||||||
bool NATIVETOUCH = false;
|
bool NATIVETOUCH = false;
|
||||||
uint8_t DIGITAL_KNOB_SENS = 16;
|
uint8_t DIGITAL_KNOB_SENS = 16;
|
||||||
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
|
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
|
||||||
@@ -210,6 +211,19 @@ namespace games::sdvx {
|
|||||||
out = "";
|
out = "";
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +277,7 @@ namespace games::sdvx {
|
|||||||
AUTO_INSERT_CARD_COOLDOWN = 15.f;
|
AUTO_INSERT_CARD_COOLDOWN = 15.f;
|
||||||
// check bad model name
|
// check bad model name
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("UFC")) {
|
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("UFC")) {
|
||||||
log_fatal(
|
log_warning(
|
||||||
"sdvx",
|
"sdvx",
|
||||||
"BAD MODEL NAME ERROR\n\n\n"
|
"BAD MODEL NAME ERROR\n\n\n"
|
||||||
"!!! model name set to UFC, this is WRONG and will break your game !!!\n"
|
"!!! model name set to UFC, this is WRONG and will break your game !!!\n"
|
||||||
@@ -273,6 +287,9 @@ namespace games::sdvx {
|
|||||||
"!!! !!!\n"
|
"!!! !!!\n"
|
||||||
"!!! model name set to UFC, this is WRONG and will break your game !!!\n\n\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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,17 +386,17 @@ namespace games::sdvx {
|
|||||||
winuser_hook_init(avs::game::DLL_INSTANCE);
|
winuser_hook_init(avs::game::DLL_INSTANCE);
|
||||||
|
|
||||||
// hook camera
|
// hook camera
|
||||||
if (!DISABLECAMS) {
|
|
||||||
camera_init();
|
camera_init();
|
||||||
}
|
|
||||||
|
|
||||||
// RGB CAMERA error ignore
|
// RGB CAMERA error ignore for SDVX5
|
||||||
if (!replace_pattern(
|
// SDVX5: boot sequence triggers camera error if camera is not detected
|
||||||
|
// SDVX6: boots fine, but game title screen in attract loop will have camera error (cosmetic only)
|
||||||
|
if (replace_pattern(
|
||||||
avs::game::DLL_INSTANCE,
|
avs::game::DLL_INSTANCE,
|
||||||
"418D480484C074218D51FD",
|
"418D480484C074218D51FD",
|
||||||
"????????????9090??????",
|
"????????????9090??????",
|
||||||
0, 0)) {
|
0, 0)) {
|
||||||
log_info("sdvx", "did not find matching signature for camera error patch");
|
log_info("sdvx", "applied camera error patch (sdvx5)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove log spam
|
// remove log spam
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ namespace games::sdvx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
extern bool DISABLECAMS;
|
|
||||||
extern bool NATIVETOUCH;
|
extern bool NATIVETOUCH;
|
||||||
extern uint8_t DIGITAL_KNOB_SENS;
|
extern uint8_t DIGITAL_KNOB_SENS;
|
||||||
extern std::optional<std::string> ASIO_DRIVER;
|
extern std::optional<std::string> ASIO_DRIVER;
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ namespace games::shared {
|
|||||||
|
|
||||||
// error
|
// error
|
||||||
if (!clear) {
|
if (!clear) {
|
||||||
log_fatal("sdvx", "could not find path");
|
log_fatal("printer", "could not find path");
|
||||||
}
|
}
|
||||||
|
|
||||||
return "DUMMY";
|
return "DUMMY";
|
||||||
@@ -326,7 +326,7 @@ namespace games::shared {
|
|||||||
memcpy(image_data, pBandImage->baseAddr, (size_t) (image_width * image_height * 3));
|
memcpy(image_data, pBandImage->baseAddr, (size_t) (image_width * image_height * 3));
|
||||||
|
|
||||||
// convert BGR to RGB
|
// convert BGR to RGB
|
||||||
log_info("printer", "converting BGR to RGB...");
|
log_misc("printer", "converting BGR to RGB...");
|
||||||
for (int pixel = 0; pixel < image_width * image_height; pixel++) {
|
for (int pixel = 0; pixel < image_width * image_height; pixel++) {
|
||||||
int index = pixel * 3;
|
int index = pixel * 3;
|
||||||
uint8_t tmp = image_data[index];
|
uint8_t tmp = image_data[index];
|
||||||
@@ -334,7 +334,26 @@ namespace games::shared {
|
|||||||
image_data[index + 2] = tmp;
|
image_data[index + 2] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (avs::game::is_model({"KLP", "KFC"})) {
|
||||||
|
// rotate image clockwise
|
||||||
|
log_misc("printer", "rotate clockwise...");
|
||||||
|
auto rotated = new uint8_t[image_width * image_height * 3];
|
||||||
|
for (int x = 0; x < image_width; x++) {
|
||||||
|
for (int y = 0; y < image_height; y++) {
|
||||||
|
int index1 = (y * image_width + x) * 3;
|
||||||
|
int index2 = (x * image_height + y) * 3;
|
||||||
|
rotated[index2 + 0] = image_data[index1 + 0];
|
||||||
|
rotated[index2 + 1] = image_data[index1 + 1];
|
||||||
|
rotated[index2 + 2] = image_data[index1 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete[] image_data;
|
||||||
|
image_data = rotated;
|
||||||
|
std::swap(image_width, image_height);
|
||||||
|
|
||||||
|
} else {
|
||||||
// flip horizontally
|
// flip horizontally
|
||||||
|
log_misc("printer", "flip horizontally...");
|
||||||
for (int x = 0; x < image_width / 2; x++) {
|
for (int x = 0; x < image_width / 2; x++) {
|
||||||
for (int y = 0; y < image_height; y++) {
|
for (int y = 0; y < image_height; y++) {
|
||||||
int index1 = (y * image_width + x) * 3;
|
int index1 = (y * image_width + x) * 3;
|
||||||
@@ -350,9 +369,10 @@ namespace games::shared {
|
|||||||
image_data[index2 + 2] = b;
|
image_data[index2 + 2] = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// iterate folders
|
// iterate folders
|
||||||
log_info("printer", "writing files...");
|
log_misc("printer", "writing files...");
|
||||||
for (const auto &path : PRINTER_PATH) {
|
for (const auto &path : PRINTER_PATH) {
|
||||||
for (const auto &format : PRINTER_FORMAT) {
|
for (const auto &format : PRINTER_FORMAT) {
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,14 @@
|
|||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "launcher/options.h"
|
#include "launcher/options.h"
|
||||||
|
#include "launcher/signal.h"
|
||||||
#include "launcher/shutdown.h"
|
#include "launcher/shutdown.h"
|
||||||
#include "misc/clipboard.h"
|
#include "misc/clipboard.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "misc/wintouchemu.h"
|
#include "misc/wintouchemu.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/flags_helper.h"
|
#include "util/flags_helper.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
#include "util/logging.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 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() {
|
static bool is_dx9_on_12_enabled() {
|
||||||
|
bool result = false;
|
||||||
switch (GRAPHICS_9_ON_12_STATE) {
|
switch (GRAPHICS_9_ON_12_STATE) {
|
||||||
case DX9ON12_FORCE_OFF:
|
case DX9ON12_FORCE_OFF:
|
||||||
log_info("graphics::d3d9", "DirectX 9on12: forced OFF by user (-dx9on12)");
|
log_info("graphics::d3d9", "DirectX 9on12: forced OFF by user (-dx9on12)");
|
||||||
return false;
|
result = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case DX9ON12_FORCE_ON:
|
case DX9ON12_FORCE_ON:
|
||||||
log_info("graphics::d3d9", "DirectX 9on12: forced ON by user (-9on12 or -dx9on12)");
|
log_info("graphics::d3d9", "DirectX 9on12: forced ON by user (-9on12 or -dx9on12)");
|
||||||
return true;
|
result = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case DX9ON12_AUTO:
|
case DX9ON12_AUTO:
|
||||||
default:
|
default:
|
||||||
@@ -219,14 +256,33 @@ static bool is_dx9_on_12_enabled() {
|
|||||||
log_info(
|
log_info(
|
||||||
"graphics::d3d9",
|
"graphics::d3d9",
|
||||||
"DirectX 9on12: enabled automatically for current game (tip: use -dx9on12 to force on or off)");
|
"DirectX 9on12: enabled automatically for current game (tip: use -dx9on12 to force on or off)");
|
||||||
return true;
|
result = true;
|
||||||
} else {
|
} else {
|
||||||
log_info(
|
log_info(
|
||||||
"graphics::d3d9",
|
"graphics::d3d9",
|
||||||
"DirectX 9on12: disabled by default, using DX9 (tip: use -dx9on12 to force on or off)");
|
"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) {
|
static IDirect3D9 *WINAPI Direct3DCreate9_hook(UINT SDKVersion) {
|
||||||
@@ -775,6 +831,7 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDevice(
|
|||||||
|
|
||||||
// log error
|
// log error
|
||||||
log_info("graphics::d3d9", "IDirect3D9::CreateDevice failed, hr={}", FMT_HRESULT(ret));
|
log_info("graphics::d3d9", "IDirect3D9::CreateDevice failed, hr={}", FMT_HRESULT(ret));
|
||||||
|
log_create_device_failure(ret);
|
||||||
} else if (!D3D9_DEVICE_HOOK_DISABLE) {
|
} else if (!D3D9_DEVICE_HOOK_DISABLE) {
|
||||||
graphics_hook_window(hFocusWindow, pPresentationParameters);
|
graphics_hook_window(hFocusWindow, pPresentationParameters);
|
||||||
|
|
||||||
@@ -994,6 +1051,8 @@ HRESULT STDMETHODCALLTYPE WrappedIDirect3D9::CreateDeviceEx(
|
|||||||
|
|
||||||
// log error
|
// log error
|
||||||
log_warning("graphics::d3d9", "CreateDeviceEx failed, hr={}", FMT_HRESULT(result));
|
log_warning("graphics::d3d9", "CreateDeviceEx failed, hr={}", FMT_HRESULT(result));
|
||||||
|
log_create_device_failure(result);
|
||||||
|
|
||||||
} else if (!D3D9_DEVICE_HOOK_DISABLE) {
|
} else if (!D3D9_DEVICE_HOOK_DISABLE) {
|
||||||
graphics_hook_window(hFocusWindow, pPresentationParameters);
|
graphics_hook_window(hFocusWindow, pPresentationParameters);
|
||||||
|
|
||||||
|
|||||||
@@ -734,6 +734,16 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
|||||||
const int w = param.BackBufferWidth;
|
const int w = param.BackBufferWidth;
|
||||||
const int h = param.BackBufferHeight;
|
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;
|
D3DLOCKED_RECT rect;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
topSurface->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
|
topSurface->LockRect(&rect, NULL, D3DLOCK_DONOTWAIT);
|
||||||
@@ -750,6 +760,7 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
|||||||
(LONG)(rectLeft + w),
|
(LONG)(rectLeft + w),
|
||||||
(LONG)(rectTop + h),
|
(LONG)(rectTop + h),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2);
|
originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2);
|
||||||
originRect.top = (topSurface_height / 2) - (GRAPHICS_FS_ORIGINAL_HEIGHT / 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;
|
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(
|
// log_misc(
|
||||||
// "graphics::d3d9", "originRect: {} {} {} {}",
|
// "graphics::d3d9", "originRect: {} {} {} {}",
|
||||||
// originRect.left, originRect.top, originRect.right, originRect.bottom);
|
// originRect.left, originRect.top, originRect.right, originRect.bottom);
|
||||||
@@ -768,9 +794,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
|||||||
if (hr != D3D_OK) {
|
if (hr != D3D_OK) {
|
||||||
log_warning(
|
log_warning(
|
||||||
"graphics::d3d9",
|
"graphics::d3d9",
|
||||||
"SurfaceHook - StretchRect backbuffer failed, rect: {} {} {} {}",
|
"SurfaceHook - StretchRect backbuffer failed for main image, rect: {} {} {} {}",
|
||||||
originRect.left, originRect.top, originRect.right, originRect.bottom);
|
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();
|
topSurface->UnlockRect();
|
||||||
|
|
||||||
// phase 2 - viewport calculation - do the actual zoom / offset math
|
// phase 2 - viewport calculation - do the actual zoom / offset math
|
||||||
|
|||||||
@@ -374,6 +374,27 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
|||||||
if ((is_tdj_sub_window && GRAPHICS_IIDX_WSUB) || is_sdvx_sub_window) {
|
if ((is_tdj_sub_window && GRAPHICS_IIDX_WSUB) || is_sdvx_sub_window) {
|
||||||
dwStyle &= ~(WS_MAXIMIZEBOX);
|
dwStyle &= ~(WS_MAXIMIZEBOX);
|
||||||
}
|
}
|
||||||
|
if ((is_tdj_sub_window || is_sdvx_sub_window) && GRAPHICS_WSUB_BORDERLESS) {
|
||||||
|
dwStyle &= ~(WS_OVERLAPPEDWINDOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_sdvx_sub_window) {
|
||||||
|
graphics_load_windowed_subscreen_parameters();
|
||||||
|
if (GRAPHICS_WSUB_SIZE.has_value()) {
|
||||||
|
nWidth = GRAPHICS_WSUB_WIDTH;
|
||||||
|
nHeight = GRAPHICS_WSUB_HEIGHT;
|
||||||
|
} else {
|
||||||
|
GRAPHICS_WSUB_WIDTH = nWidth;
|
||||||
|
GRAPHICS_WSUB_HEIGHT = nHeight;
|
||||||
|
}
|
||||||
|
if (GRAPHICS_WSUB_POS.has_value()) {
|
||||||
|
x = GRAPHICS_WSUB_X;
|
||||||
|
y = GRAPHICS_WSUB_Y;
|
||||||
|
} else {
|
||||||
|
GRAPHICS_WSUB_X = x;
|
||||||
|
GRAPHICS_WSUB_Y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// call original
|
// call original
|
||||||
HWND result = CreateWindowExA_orig(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight,
|
HWND result = CreateWindowExA_orig(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight,
|
||||||
@@ -529,11 +550,11 @@ static BOOL WINAPI MoveWindow_hook(HWND hWnd, int X, int Y, int nWidth, int nHei
|
|||||||
|
|
||||||
dwStyle = GetWindowLongA(hWnd, GWL_STYLE);
|
dwStyle = GetWindowLongA(hWnd, GWL_STYLE);
|
||||||
|
|
||||||
SetRect(&rect, 0, 0, GRAPHICS_IIDX_WSUB_WIDTH, GRAPHICS_IIDX_WSUB_HEIGHT);
|
SetRect(&rect, 0, 0, GRAPHICS_WSUB_WIDTH, GRAPHICS_WSUB_HEIGHT);
|
||||||
AdjustWindowRect(&rect, dwStyle, 0);
|
AdjustWindowRect(&rect, dwStyle, 0);
|
||||||
|
|
||||||
X = GRAPHICS_IIDX_WSUB_X;
|
X = GRAPHICS_WSUB_X;
|
||||||
Y = GRAPHICS_IIDX_WSUB_Y;
|
Y = GRAPHICS_WSUB_Y;
|
||||||
|
|
||||||
nWidth = rect.right - rect.left;
|
nWidth = rect.right - rect.left;
|
||||||
nHeight = rect.bottom - rect.top;
|
nHeight = rect.bottom - rect.top;
|
||||||
@@ -865,6 +886,9 @@ void graphics_hook_subscreen_window(HWND hWnd) {
|
|||||||
WSUB_WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
|
WSUB_WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
|
||||||
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WsubWindowProc));
|
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WsubWindowProc));
|
||||||
}
|
}
|
||||||
|
if (GRAPHICS_WSUB_ALWAYS_ON_TOP) {
|
||||||
|
graphics_update_z_order(hWnd, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphics_screens_register(int screen) {
|
void graphics_screens_register(int screen) {
|
||||||
|
|||||||
@@ -50,12 +50,14 @@ extern bool GRAPHICS_WINDOW_ALWAYS_ON_TOP;
|
|||||||
extern bool GRAPHICS_WINDOW_BACKBUFFER_SCALE;
|
extern bool GRAPHICS_WINDOW_BACKBUFFER_SCALE;
|
||||||
|
|
||||||
extern bool GRAPHICS_IIDX_WSUB;
|
extern bool GRAPHICS_IIDX_WSUB;
|
||||||
extern std::optional<std::string> GRAPHICS_IIDX_WSUB_SIZE;
|
extern std::optional<std::string> GRAPHICS_WSUB_SIZE;
|
||||||
extern std::optional<std::string> GRAPHICS_IIDX_WSUB_POS;
|
extern std::optional<std::string> GRAPHICS_WSUB_POS;
|
||||||
extern int GRAPHICS_IIDX_WSUB_WIDTH;
|
extern int GRAPHICS_WSUB_WIDTH;
|
||||||
extern int GRAPHICS_IIDX_WSUB_HEIGHT;
|
extern int GRAPHICS_WSUB_HEIGHT;
|
||||||
extern int GRAPHICS_IIDX_WSUB_X;
|
extern int GRAPHICS_WSUB_X;
|
||||||
extern int GRAPHICS_IIDX_WSUB_Y;
|
extern int GRAPHICS_WSUB_Y;
|
||||||
|
extern bool GRAPHICS_WSUB_BORDERLESS;
|
||||||
|
extern bool GRAPHICS_WSUB_ALWAYS_ON_TOP;
|
||||||
extern HWND TDJ_SUBSCREEN_WINDOW;
|
extern HWND TDJ_SUBSCREEN_WINDOW;
|
||||||
extern HWND SDVX_SUBSCREEN_WINDOW;
|
extern HWND SDVX_SUBSCREEN_WINDOW;
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ std::string graphics_screenshot_genpath();
|
|||||||
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
void graphics_windowed_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
void graphics_capture_initial_window(HWND hWnd);
|
void graphics_capture_initial_window(HWND hWnd);
|
||||||
void graphics_update_window_style(HWND hWnd);
|
void graphics_update_window_style(HWND hWnd);
|
||||||
void graphics_update_z_order(HWND hWnd);
|
void graphics_update_z_order(HWND hWnd, bool always_on_top);
|
||||||
void graphics_move_resize_window(HWND hWnd);
|
void graphics_move_resize_window(HWND hWnd);
|
||||||
bool graphics_window_change_crashes_game();
|
bool graphics_window_change_crashes_game();
|
||||||
void graphics_load_windowed_subscreen_parameters();
|
void graphics_load_windowed_subscreen_parameters();
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ bool GRAPHICS_WINDOW_BACKBUFFER_SCALE = false;
|
|||||||
|
|
||||||
// IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed
|
// IIDX Windowed Subscreen - starts out as false, enabled by IIDX module on pre-attach as needed
|
||||||
bool GRAPHICS_IIDX_WSUB = false;
|
bool GRAPHICS_IIDX_WSUB = false;
|
||||||
std::optional<std::string> GRAPHICS_IIDX_WSUB_SIZE;
|
std::optional<std::string> GRAPHICS_WSUB_SIZE;
|
||||||
std::optional<std::string> GRAPHICS_IIDX_WSUB_POS;
|
std::optional<std::string> GRAPHICS_WSUB_POS;
|
||||||
int GRAPHICS_IIDX_WSUB_WIDTH = 1280;
|
int GRAPHICS_WSUB_WIDTH = 1280;
|
||||||
int GRAPHICS_IIDX_WSUB_HEIGHT = 720;
|
int GRAPHICS_WSUB_HEIGHT = 720;
|
||||||
int GRAPHICS_IIDX_WSUB_X = 0;
|
int GRAPHICS_WSUB_X = 0;
|
||||||
int GRAPHICS_IIDX_WSUB_Y = 0;
|
int GRAPHICS_WSUB_Y = 0;
|
||||||
|
bool GRAPHICS_WSUB_BORDERLESS = false;
|
||||||
|
bool GRAPHICS_WSUB_ALWAYS_ON_TOP = false;
|
||||||
|
|
||||||
// these flags are carefully constructed to ensure maximum compatibility
|
// these flags are carefully constructed to ensure maximum compatibility
|
||||||
// (e.g., DDR likes to hang when SetWindowPos is called with certain params)
|
// (e.g., DDR likes to hang when SetWindowPos is called with certain params)
|
||||||
@@ -108,7 +110,7 @@ void graphics_capture_initial_window(HWND hWnd) {
|
|||||||
}
|
}
|
||||||
if (cfg::SCREENRESIZE->window_always_on_top) {
|
if (cfg::SCREENRESIZE->window_always_on_top) {
|
||||||
log_info("graphics-windowed", "change window z-order - always on top");
|
log_info("graphics-windowed", "change window z-order - always on top");
|
||||||
graphics_update_z_order(hWnd);
|
graphics_update_z_order(hWnd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure spicetouch coordinates are initialized
|
// ensure spicetouch coordinates are initialized
|
||||||
@@ -169,29 +171,29 @@ void graphics_load_windowed_subscreen_parameters() {
|
|||||||
|
|
||||||
log_debug("graphics-windowed", "graphics_load_windowed_subscreen_parameters called");
|
log_debug("graphics-windowed", "graphics_load_windowed_subscreen_parameters called");
|
||||||
|
|
||||||
if (GRAPHICS_IIDX_WSUB_SIZE.has_value()) {
|
if (GRAPHICS_WSUB_SIZE.has_value()) {
|
||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_SIZE");
|
"graphics_load_windowed_parameters - load GRAPHICS_WSUB_SIZE");
|
||||||
|
|
||||||
std::pair<uint32_t, uint32_t> result;
|
std::pair<uint32_t, uint32_t> result;
|
||||||
if (parse_width_height(GRAPHICS_IIDX_WSUB_SIZE.value(), result)) {
|
if (parse_width_height(GRAPHICS_WSUB_SIZE.value(), result)) {
|
||||||
GRAPHICS_IIDX_WSUB_WIDTH = result.first;
|
GRAPHICS_WSUB_WIDTH = result.first;
|
||||||
GRAPHICS_IIDX_WSUB_HEIGHT = result.second;
|
GRAPHICS_WSUB_HEIGHT = result.second;
|
||||||
} else {
|
} else {
|
||||||
log_warning("graphics-windowed", "failed to parse -wsubsize");
|
log_warning("graphics-windowed", "failed to parse -wsubsize");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GRAPHICS_IIDX_WSUB_POS.has_value()) {
|
if (GRAPHICS_WSUB_POS.has_value()) {
|
||||||
log_debug(
|
log_debug(
|
||||||
"graphics-windowed",
|
"graphics-windowed",
|
||||||
"graphics_load_windowed_parameters - load GRAPHICS_IIDX_WSUB_POS");
|
"graphics_load_windowed_parameters - load GRAPHICS_WSUB_POS");
|
||||||
|
|
||||||
std::pair<uint32_t, uint32_t> result;
|
std::pair<uint32_t, uint32_t> result;
|
||||||
if (parse_width_height(GRAPHICS_IIDX_WSUB_POS.value(), result)) {
|
if (parse_width_height(GRAPHICS_WSUB_POS.value(), result)) {
|
||||||
GRAPHICS_IIDX_WSUB_X = result.first;
|
GRAPHICS_WSUB_X = result.first;
|
||||||
GRAPHICS_IIDX_WSUB_Y = result.second;
|
GRAPHICS_WSUB_Y = result.second;
|
||||||
} else {
|
} else {
|
||||||
log_warning("graphics-windowed", "failed to parse -wsubpos");
|
log_warning("graphics-windowed", "failed to parse -wsubpos");
|
||||||
}
|
}
|
||||||
@@ -398,7 +400,7 @@ void graphics_update_window_style(HWND hWnd) {
|
|||||||
log_debug("graphics-windowed", "graphics_update_window_style returned");
|
log_debug("graphics-windowed", "graphics_update_window_style returned");
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphics_update_z_order(HWND hWnd) {
|
void graphics_update_z_order(HWND hWnd, bool always_on_top) {
|
||||||
if (!GRAPHICS_WINDOWED) {
|
if (!GRAPHICS_WINDOWED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -406,7 +408,7 @@ void graphics_update_z_order(HWND hWnd) {
|
|||||||
log_debug("graphics-windowed", "graphics_update_z_order called");
|
log_debug("graphics-windowed", "graphics_update_z_order called");
|
||||||
|
|
||||||
HWND insert_after = nullptr;
|
HWND insert_after = nullptr;
|
||||||
if (cfg::SCREENRESIZE->window_always_on_top) {
|
if (always_on_top) {
|
||||||
insert_after = HWND_TOPMOST;
|
insert_after = HWND_TOPMOST;
|
||||||
} else {
|
} else {
|
||||||
insert_after = HWND_NOTOPMOST;
|
insert_after = HWND_NOTOPMOST;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <ntstatus.h>
|
#include <ntstatus.h>
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
|
#include "games/iidx/iidx.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
@@ -18,9 +19,11 @@ constexpr UINT CODEPAGE_SHIFT_JIS = 932;
|
|||||||
static decltype(GetACP) *GetACP_orig = nullptr;
|
static decltype(GetACP) *GetACP_orig = nullptr;
|
||||||
static decltype(GetOEMCP) *GetOEMCP_orig = nullptr;
|
static decltype(GetOEMCP) *GetOEMCP_orig = nullptr;
|
||||||
static decltype(MultiByteToWideChar) *MultiByteToWideChar_orig = nullptr;
|
static decltype(MultiByteToWideChar) *MultiByteToWideChar_orig = nullptr;
|
||||||
|
static decltype(GetLocaleInfoEx) *GetLocaleInfoEx_orig = nullptr;
|
||||||
|
|
||||||
#ifdef SPICE64
|
#ifdef SPICE64
|
||||||
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
|
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
|
||||||
|
static decltype(IsDBCSLeadByte) *IsDBCSLeadByte_orig = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
|
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
|
||||||
@@ -119,6 +122,59 @@ static int WINAPI MultiByteToWideChar_hook(
|
|||||||
cchWideChar);
|
cchWideChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int WINAPI GetLocaleInfoEx_hook (
|
||||||
|
LPCWSTR lpLocaleName,
|
||||||
|
LCTYPE LCType,
|
||||||
|
LPWSTR lpLCData,
|
||||||
|
int cchData)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (lpLocaleName == LOCALE_NAME_INVARIANT) {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit (LOCALE_NAME_INVARIANT), {}, {}", LCType, cchData);
|
||||||
|
} else if (lpLocaleName == LOCALE_NAME_SYSTEM_DEFAULT) {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit (LOCALE_NAME_SYSTEM_DEFAULT), {}, {}", LCType, cchData);
|
||||||
|
} else if (lpLocaleName == LOCALE_NAME_USER_DEFAULT) {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit (LOCALE_NAME_USER_DEFAULT), {}, {}", LCType, cchData);
|
||||||
|
} else {
|
||||||
|
log_misc("hooks::lang", "GetLocaleInfoEx_hook hit ({}), {}, {}", ws2s(lpLocaleName), LCType, cchData);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (lpLocaleName == LOCALE_NAME_USER_DEFAULT &&
|
||||||
|
LCType == LOCALE_SISO639LANGNAME &&
|
||||||
|
lpLCData != NULL &&
|
||||||
|
cchData >= 3) {
|
||||||
|
log_misc("hooks::lang",
|
||||||
|
"GetLocaleInfoEx_hook hit (LOCALE_NAME_USER_DEFAULT / LOCALE_SISO639LANGNAME), return `ja`");
|
||||||
|
wcscpy(lpLCData, L"ja");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpLocaleName == LOCALE_NAME_USER_DEFAULT &&
|
||||||
|
LCType == LOCALE_SISO3166CTRYNAME &&
|
||||||
|
lpLCData != NULL &&
|
||||||
|
cchData >= 3) {
|
||||||
|
log_misc("hooks::lang",
|
||||||
|
"GetLocaleInfoEx_hook hit (LOCALE_NAME_USER_DEFAULT / LOCALE_SISO3166CTRYNAME), return `JP`");
|
||||||
|
wcscpy(lpLCData, L"JP");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
void hooks::lang::early_init() {
|
||||||
log_info("hooks::lang", "early initialization");
|
log_info("hooks::lang", "early initialization");
|
||||||
|
|
||||||
@@ -138,6 +194,27 @@ void hooks::lang::early_init() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (avs::game::is_model("XIF")) {
|
||||||
|
log_info("hooks::lang", "hooking GetLocaleInfoEx");
|
||||||
|
detour::trampoline_try(
|
||||||
|
"kernel32.dll",
|
||||||
|
"GetLocaleInfoEx",
|
||||||
|
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() {
|
void hooks::lang::init() {
|
||||||
|
|||||||
@@ -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) {
|
static int WINAPI bind_hook(SOCKET s, const struct sockaddr *name, int namelen) {
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma ide diagnostic ignored "OCDFAInspection"
|
#pragma ide diagnostic ignored "OCDFAInspection"
|
||||||
|
#endif
|
||||||
|
|
||||||
// cast to sockaddr_in
|
// cast to sockaddr_in
|
||||||
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
|
struct sockaddr_in *in_name = (struct sockaddr_in *) name;
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
// override bind to allow all hosts
|
// override bind to allow all hosts
|
||||||
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
|
in_name->sin_addr.s_addr = inet_addr("0.0.0.0");
|
||||||
@@ -179,7 +183,7 @@ void networkhook_init() {
|
|||||||
strncpy(s_prefix, inet_ntoa(prefix), 16);
|
strncpy(s_prefix, inet_ntoa(prefix), 16);
|
||||||
|
|
||||||
// log preferences
|
// log preferences
|
||||||
log_info("network", "Network preferences: {}", s_network, s_subnet, s_prefix);
|
// log_info("network", "Network preferences: {}, {}, {}", s_network, s_subnet, s_prefix);
|
||||||
|
|
||||||
// GetAdaptersInfo hook
|
// GetAdaptersInfo hook
|
||||||
auto orig_addr = detour::iat_try(
|
auto orig_addr = detour::iat_try(
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <cfg/configurator.h>
|
#include <cfg/configurator.h>
|
||||||
|
|
||||||
|
#include "api/modules/capture.h"
|
||||||
#include "acio/acio.h"
|
#include "acio/acio.h"
|
||||||
#include "acio/icca/icca.h"
|
#include "acio/icca/icca.h"
|
||||||
#include "api/controller.h"
|
#include "api/controller.h"
|
||||||
@@ -19,7 +20,9 @@
|
|||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
#include "easrv/easrv.h"
|
#include "easrv/easrv.h"
|
||||||
#include "external/cardio/cardio_runner.h"
|
#include "external/cardio/cardio_runner.h"
|
||||||
|
#ifndef NO_SCARD
|
||||||
#include "external/scard/scard.h"
|
#include "external/scard/scard.h"
|
||||||
|
#endif
|
||||||
#include "games/game.h"
|
#include "games/game.h"
|
||||||
#include "games/io.h"
|
#include "games/io.h"
|
||||||
#include "games/bbc/bbc.h"
|
#include "games/bbc/bbc.h"
|
||||||
@@ -60,6 +63,7 @@
|
|||||||
#include "games/ccj/trackball.h"
|
#include "games/ccj/trackball.h"
|
||||||
#include "games/qks/qks.h"
|
#include "games/qks/qks.h"
|
||||||
#include "games/mfg/mfg.h"
|
#include "games/mfg/mfg.h"
|
||||||
|
#include "games/pc/pc.h"
|
||||||
#include "games/museca/museca.h"
|
#include "games/museca/museca.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
@@ -95,6 +99,7 @@
|
|||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
#include "util/cpuutils.h"
|
#include "util/cpuutils.h"
|
||||||
#include "util/crypt.h"
|
#include "util/crypt.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/fileutils.h"
|
#include "util/fileutils.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
@@ -149,6 +154,9 @@ static bool check_dll(const std::string &model) {
|
|||||||
|
|
||||||
void update_msvcrt_args(int argc, char *argv[]);
|
void update_msvcrt_args(int argc, char *argv[]);
|
||||||
|
|
||||||
|
void dump_button_bindings(std::vector<Button> *buttons);
|
||||||
|
void dump_analog_bindings();
|
||||||
|
|
||||||
int main_implementation(int argc, char *argv[]) {
|
int main_implementation(int argc, char *argv[]) {
|
||||||
|
|
||||||
// remember argv, argv
|
// remember argv, argv
|
||||||
@@ -218,6 +226,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
bool attach_ccj = false;
|
bool attach_ccj = false;
|
||||||
bool attach_qks = false;
|
bool attach_qks = false;
|
||||||
bool attach_mfg = false;
|
bool attach_mfg = false;
|
||||||
|
bool attach_pc = false;
|
||||||
bool attach_museca = false;
|
bool attach_museca = false;
|
||||||
bool show_cursor_if_no_touch = false;
|
bool show_cursor_if_no_touch = false;
|
||||||
|
|
||||||
@@ -243,6 +252,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// parse arguments
|
// parse arguments
|
||||||
LAUNCHER_OPTIONS = launcher::parse_options(argc, argv);
|
LAUNCHER_OPTIONS = launcher::parse_options(argc, argv);
|
||||||
|
|
||||||
|
// command line override (must be done before merging options with cfg)
|
||||||
|
if (LAUNCHER_OPTIONS->at(launcher::Options::OptionConflictResolution).value_bool()) {
|
||||||
|
launcher::USE_CMD_OVERRIDE = true;
|
||||||
|
}
|
||||||
|
|
||||||
// determine config file path - must be done before anything else
|
// determine config file path - must be done before anything else
|
||||||
const auto &cfg_path = LAUNCHER_OPTIONS->at(launcher::Options::ConfigurationPath);
|
const auto &cfg_path = LAUNCHER_OPTIONS->at(launcher::Options::ConfigurationPath);
|
||||||
if (cfg_path.is_active()) {
|
if (cfg_path.is_active()) {
|
||||||
@@ -251,7 +265,8 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// detect model used to load option overrides
|
// detect model used to load option overrides
|
||||||
auto options_version = launcher::detect_gameversion(
|
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.model.empty() && options_version.model.size() < 4) {
|
||||||
if (options_version.dest.size() == 1) {
|
if (options_version.dest.size() == 1) {
|
||||||
@@ -284,21 +299,6 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config;
|
cfg::CONFIGURATOR_TYPE = cfg::ConfigType::Config;
|
||||||
cfg_run = true;
|
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()) {
|
if (options[launcher::Options::EAmusementEmulation].value_bool()) {
|
||||||
avs::ea3::URL_SLASH = 1;
|
avs::ea3::URL_SLASH = 1;
|
||||||
easrv_port = 8080;
|
easrv_port = 8080;
|
||||||
@@ -353,6 +353,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::VerboseAVSLogging].value_bool()) {
|
if (options[launcher::Options::VerboseAVSLogging].value_bool()) {
|
||||||
hooks::avs::config::LOG = true;
|
hooks::avs::config::LOG = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::AllowEA3Verbose].value_bool()) {
|
||||||
|
avs::ea3::EA3_DEBUG_VERBOSE = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::spice2x_AutoOrientation].is_active()) {
|
if (options[launcher::Options::spice2x_AutoOrientation].is_active()) {
|
||||||
GRAPHICS_ADJUST_ORIENTATION =
|
GRAPHICS_ADJUST_ORIENTATION =
|
||||||
(graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32();
|
(graphics_orientation)options[launcher::Options::spice2x_AutoOrientation].value_uint32();
|
||||||
@@ -423,9 +426,6 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) {
|
if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) {
|
||||||
attach_sdvx = true;
|
attach_sdvx = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::SDVXDisableCameras].value_bool()) {
|
|
||||||
games::sdvx::DISABLECAMS = true;
|
|
||||||
}
|
|
||||||
if (options[launcher::Options::SDVXNativeTouch].value_bool()) {
|
if (options[launcher::Options::SDVXNativeTouch].value_bool()) {
|
||||||
games::sdvx::NATIVETOUCH = true;
|
games::sdvx::NATIVETOUCH = true;
|
||||||
}
|
}
|
||||||
@@ -466,6 +466,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// Disable legacy behaviour to avoid conflict
|
// Disable legacy behaviour to avoid conflict
|
||||||
games::iidx::DISABLE_CAMS = true;
|
games::iidx::DISABLE_CAMS = true;
|
||||||
}
|
}
|
||||||
|
if (games::iidx::DISABLE_CAMS) {
|
||||||
|
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||||
|
}
|
||||||
if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
|
if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
|
||||||
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
|
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
|
||||||
}
|
}
|
||||||
@@ -616,12 +619,18 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
||||||
attach_mfg = true;
|
attach_mfg = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::LoadPCModule].value_bool()) {
|
||||||
|
attach_pc = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
||||||
attach_museca = true;
|
attach_museca = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::DDR43Mode].value_bool()) {
|
if (options[launcher::Options::DDR43Mode].value_bool()) {
|
||||||
games::ddr::SDMODE = true;
|
games::ddr::SDMODE = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::DDRSkipCodecRegisteration].value_bool()) {
|
||||||
|
games::ddr::NO_CODEC_REGISTRATION = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::LoadSteelChronicleModule].value_bool()) {
|
if (options[launcher::Options::LoadSteelChronicleModule].value_bool()) {
|
||||||
attach_sc = true;
|
attach_sc = true;
|
||||||
}
|
}
|
||||||
@@ -661,21 +670,42 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::SDVXPrinterEmulation].value_bool()) {
|
if (options[launcher::Options::SDVXPrinterEmulation].value_bool()) {
|
||||||
attach_cpusbxpkm_printer = true;
|
attach_cpusbxpkm_printer = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::SDVXPrinterOutputOverwrite].value_bool()) {
|
|
||||||
|
// printer overwrite
|
||||||
|
if (options[launcher::Options::SDVXPrinterOutputOverwrite].value_bool() ||
|
||||||
|
options[launcher::Options::LovePlusPrinterOutputOverwrite].value_bool()) {
|
||||||
games::shared::PRINTER_OVERWRITE_FILE = true;
|
games::shared::PRINTER_OVERWRITE_FILE = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// printer output path
|
||||||
for (auto &path : options[launcher::Options::SDVXPrinterOutputPath].values_text()) {
|
for (auto &path : options[launcher::Options::SDVXPrinterOutputPath].values_text()) {
|
||||||
games::shared::PRINTER_PATH.push_back(path);
|
games::shared::PRINTER_PATH.push_back(path);
|
||||||
}
|
}
|
||||||
|
for (auto &path : options[launcher::Options::LovePlusPrinterOutputPath].values_text()) {
|
||||||
|
games::shared::PRINTER_PATH.push_back(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printer file format
|
||||||
for (auto &path : options[launcher::Options::SDVXPrinterOutputFormat].values_text()) {
|
for (auto &path : options[launcher::Options::SDVXPrinterOutputFormat].values_text()) {
|
||||||
games::shared::PRINTER_FORMAT.push_back(path);
|
games::shared::PRINTER_FORMAT.push_back(path);
|
||||||
}
|
}
|
||||||
|
for (auto &path : options[launcher::Options::LovePlusPrinterOutputFormat].values_text()) {
|
||||||
|
games::shared::PRINTER_FORMAT.push_back(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printer JPG quality
|
||||||
if (options[launcher::Options::SDVXPrinterJPGQuality].is_active()) {
|
if (options[launcher::Options::SDVXPrinterJPGQuality].is_active()) {
|
||||||
games::shared::PRINTER_JPG_QUALITY = options[launcher::Options::SDVXPrinterJPGQuality].value_uint32();
|
games::shared::PRINTER_JPG_QUALITY = options[launcher::Options::SDVXPrinterJPGQuality].value_uint32();
|
||||||
|
} else if (options[launcher::Options::LovePlusPrinterJPGQuality].is_active()) {
|
||||||
|
games::shared::PRINTER_JPG_QUALITY = options[launcher::Options::LovePlusPrinterJPGQuality].value_uint32();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::SDVXPrinterOutputClear].value_bool()) {
|
|
||||||
|
// printer output clear
|
||||||
|
if (options[launcher::Options::SDVXPrinterOutputClear].value_bool() ||
|
||||||
|
options[launcher::Options::LovePlusPrinterOutputClear].value_bool()) {
|
||||||
games::shared::PRINTER_CLEAR = true;
|
games::shared::PRINTER_CLEAR = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options[launcher::Options::HTTP11].is_active()) {
|
if (options[launcher::Options::HTTP11].is_active()) {
|
||||||
avs::ea3::HTTP11 = options[launcher::Options::HTTP11].value_uint32();
|
avs::ea3::HTTP11 = options[launcher::Options::HTTP11].value_uint32();
|
||||||
}
|
}
|
||||||
@@ -776,6 +806,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
for (auto &sextet : options[launcher::Options::SextetStreamPort].values_text()) {
|
for (auto &sextet : options[launcher::Options::SextetStreamPort].values_text()) {
|
||||||
sextet_devices.emplace_back(sextet);
|
sextet_devices.emplace_back(sextet);
|
||||||
}
|
}
|
||||||
|
#ifndef NO_SCARD
|
||||||
if (options[launcher::Options::HIDSmartCard].value_bool()) {
|
if (options[launcher::Options::HIDSmartCard].value_bool()) {
|
||||||
WINSCARD_CONFIG.cardinfo_callback = eamuse_scard_callback;
|
WINSCARD_CONFIG.cardinfo_callback = eamuse_scard_callback;
|
||||||
scard_threadstart();
|
scard_threadstart();
|
||||||
@@ -795,6 +826,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
WINSCARD_CONFIG.add_padding_to_felica = true;
|
WINSCARD_CONFIG.add_padding_to_felica = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (options[launcher::Options::CardIOHIDReaderOrderFlip].value_bool()) {
|
if (options[launcher::Options::CardIOHIDReaderOrderFlip].value_bool()) {
|
||||||
CARDIO_RUNNER_FLIP = true;
|
CARDIO_RUNNER_FLIP = true;
|
||||||
}
|
}
|
||||||
@@ -813,6 +845,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::AdapterSubnet].is_active()) {
|
if (options[launcher::Options::AdapterSubnet].is_active()) {
|
||||||
NETWORK_SUBNET = options[launcher::Options::AdapterSubnet].value_text();
|
NETWORK_SUBNET = options[launcher::Options::AdapterSubnet].value_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options[launcher::Options::APITCPPort].is_active()) {
|
if (options[launcher::Options::APITCPPort].is_active()) {
|
||||||
api_enable = true;
|
api_enable = true;
|
||||||
api_port = options[launcher::Options::APITCPPort].value_uint32();
|
api_port = options[launcher::Options::APITCPPort].value_uint32();
|
||||||
@@ -835,6 +868,13 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::APIDebugMode].value_bool()) {
|
if (options[launcher::Options::APIDebugMode].value_bool()) {
|
||||||
api_debug = true;
|
api_debug = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::APIScreenMirrorQuality].is_active()) {
|
||||||
|
api::modules::CAPTURE_QUALITY = options[launcher::Options::APIScreenMirrorQuality].value_uint32();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::APIScreenMirrorDivide].is_active()) {
|
||||||
|
api::modules::CAPTURE_DIVIDE = options[launcher::Options::APIScreenMirrorDivide].value_uint32();
|
||||||
|
}
|
||||||
|
|
||||||
if (options[launcher::Options::DisableDebugHooks].value_bool()) {
|
if (options[launcher::Options::DisableDebugHooks].value_bool()) {
|
||||||
debughook::DEBUGHOOK_LOGGING = false;
|
debughook::DEBUGHOOK_LOGGING = false;
|
||||||
}
|
}
|
||||||
@@ -890,6 +930,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
if (options[launcher::Options::DisableAudioHooks].value_bool()) {
|
if (options[launcher::Options::DisableAudioHooks].value_bool()) {
|
||||||
hooks::audio::ENABLED = false;
|
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()) {
|
if (options[launcher::Options::spice2x_DisableVolumeHook].value_bool()) {
|
||||||
hooks::audio::VOLUME_HOOK_ENABLED = false;
|
hooks::audio::VOLUME_HOOK_ENABLED = false;
|
||||||
@@ -976,12 +1021,24 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
GRAPHICS_WINDOW_ALWAYS_ON_TOP = options[launcher::Options::spice2x_WindowAlwaysOnTop].value_bool();
|
GRAPHICS_WINDOW_ALWAYS_ON_TOP = options[launcher::Options::spice2x_WindowAlwaysOnTop].value_bool();
|
||||||
GRAPHICS_WINDOW_BACKBUFFER_SCALE = options[launcher::Options::WindowForceScaling].value_bool();
|
GRAPHICS_WINDOW_BACKBUFFER_SCALE = options[launcher::Options::WindowForceScaling].value_bool();
|
||||||
|
|
||||||
// IIDX Windowed Subscreen
|
// IIDX/SDVX Windowed Subscreen
|
||||||
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].is_active()) {
|
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].is_active()) {
|
||||||
GRAPHICS_IIDX_WSUB_SIZE = options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].value_text();
|
GRAPHICS_WSUB_SIZE = options[launcher::Options::spice2x_IIDXWindowedSubscreenSize].value_text();
|
||||||
|
} else if (options[launcher::Options::SDVXWindowedSubscreenSize].is_active()) {
|
||||||
|
GRAPHICS_WSUB_SIZE = options[launcher::Options::SDVXWindowedSubscreenSize].value_text();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].is_active()) {
|
if (options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].is_active()) {
|
||||||
GRAPHICS_IIDX_WSUB_POS = options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].value_text();
|
GRAPHICS_WSUB_POS = options[launcher::Options::spice2x_IIDXWindowedSubscreenPosition].value_text();
|
||||||
|
} else if (options[launcher::Options::SDVXWindowedSubscreenPosition].is_active()) {
|
||||||
|
GRAPHICS_WSUB_POS = options[launcher::Options::SDVXWindowedSubscreenPosition].value_text();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::IIDXWindowedSubscreenBorderless].value_bool() ||
|
||||||
|
options[launcher::Options::SDVXWindowedSubscreenBorderless].value_bool()) {
|
||||||
|
GRAPHICS_WSUB_BORDERLESS = true;
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::IIDXWindowedSubscreenAlwaysOnTop].value_bool() ||
|
||||||
|
options[launcher::Options::SDVXWindowedSubscreenAlwaysOnTop].value_bool()) {
|
||||||
|
GRAPHICS_WSUB_ALWAYS_ON_TOP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options[launcher::Options::spice2x_JubeatLegacyTouch].value_bool()) {
|
if (options[launcher::Options::spice2x_JubeatLegacyTouch].value_bool()) {
|
||||||
@@ -1050,12 +1107,32 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::MFGNoIO].is_active()) {
|
if (options[launcher::Options::MFGNoIO].is_active()) {
|
||||||
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::PCArgs].is_active()) {
|
||||||
|
games::pc::PC_INJECT_ARGS = options[launcher::Options::PCArgs].value_text();
|
||||||
|
}
|
||||||
|
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()) {
|
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
||||||
rawinput::ENABLE_SMX_STAGE = true;
|
rawinput::ENABLE_SMX_STAGE = true;
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::spice2x_EnableSMXDedicab].value_bool()) {
|
if (options[launcher::Options::spice2x_EnableSMXDedicab].value_bool()) {
|
||||||
rawinput::ENABLE_SMX_DEDICAB = true;
|
rawinput::ENABLE_SMX_DEDICAB = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::InputRequiresFocus].is_active()) {
|
||||||
|
const auto &text = options[launcher::Options::InputRequiresFocus].value_text();
|
||||||
|
if (text == "always") {
|
||||||
|
rawinput::NAIVE_REQUIRE_FOCUS = true;
|
||||||
|
rawinput::RAWINPUT_REQUIRE_FOCUS = true;
|
||||||
|
} else if (text == "never") {
|
||||||
|
rawinput::NAIVE_REQUIRE_FOCUS = false;
|
||||||
|
rawinput::RAWINPUT_REQUIRE_FOCUS = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options[launcher::Options::MidiAlgoVer].is_active()) {
|
if (options[launcher::Options::MidiAlgoVer].is_active()) {
|
||||||
if (options[launcher::Options::MidiAlgoVer].value_text() == "legacy") {
|
if (options[launcher::Options::MidiAlgoVer].value_text() == "legacy") {
|
||||||
midi_algo = rawinput::MidiNoteAlgorithm::LEGACY;
|
midi_algo = rawinput::MidiNoteAlgorithm::LEGACY;
|
||||||
@@ -1077,6 +1154,10 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
rawinput::MIDI_NOTE_SUSTAIN = options[launcher::Options::MidiNoteSustain].value_uint32();
|
rawinput::MIDI_NOTE_SUSTAIN = options[launcher::Options::MidiNoteSustain].value_uint32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options[launcher::Options::LovePlusCamEnable].value_bool()) {
|
||||||
|
games::loveplus::CAMERA_ENABLE = true;
|
||||||
|
}
|
||||||
|
|
||||||
// API debugging
|
// API debugging
|
||||||
if (api_debug && !cfg::CONFIGURATOR_STANDALONE) {
|
if (api_debug && !cfg::CONFIGURATOR_STANDALONE) {
|
||||||
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
API_CONTROLLER = std::make_unique<api::Controller>(api_port, api_pass, api_pretty);
|
||||||
@@ -1116,13 +1197,28 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// log
|
// log
|
||||||
|
#ifndef SPICE_LINUX
|
||||||
#ifdef SPICE64
|
#ifdef SPICE64
|
||||||
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
||||||
|
#elif SPICE32_LARGE_ADDRESS_AWARE
|
||||||
|
log_info("launcher", "SpiceTools Bootstrap (x32 - Large Address Aware) (spice2x)");
|
||||||
#else
|
#else
|
||||||
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
||||||
#endif
|
#endif
|
||||||
|
#else
|
||||||
|
#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);
|
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
|
// log command line arguments
|
||||||
std::ostringstream arguments;
|
std::ostringstream arguments;
|
||||||
for (auto &root_option : options) {
|
for (auto &root_option : options) {
|
||||||
@@ -1161,6 +1257,71 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
log_info("launcher", "arguments:\n{}", arguments.str());
|
log_info("launcher", "arguments:\n{}", arguments.str());
|
||||||
|
|
||||||
|
// print out conflicts
|
||||||
|
size_t conflicts = 0;
|
||||||
|
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,
|
||||||
|
value);
|
||||||
|
} else {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"multiple values for -{}, spicecfg values take precedence: {}",
|
||||||
|
option.get_definition().name,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (conflicts) {
|
||||||
|
if (launcher::USE_CMD_OVERRIDE) {
|
||||||
|
log_info(
|
||||||
|
"launcher",
|
||||||
|
"user specified -cmdoverride, therefore command line args took precedence over spicecfg");
|
||||||
|
} else {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"spicecfg values take precedence over command line args; to change this behavior, use -cmdoverride");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options[launcher::Options::GameExecutable].is_active() && !cfg::CONFIGURATOR_STANDALONE) {
|
||||||
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"WARNING - user specified -exec option\n\n\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
"!!! Using -exec option disables all game-specific hooks! !!!\n"
|
||||||
|
"!!! Unless you know exactly what you are doing, clear -exec !!!\n"
|
||||||
|
"!!! and try again. Using -exec by itself will result in weird !!!\n"
|
||||||
|
"!!! errors and loss of functionality. !!!\n"
|
||||||
|
"!!! !!!\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()) {
|
if (options[launcher::Options::FullscreenResolution].is_active()) {
|
||||||
std::pair<uint32_t, uint32_t> result;
|
std::pair<uint32_t, uint32_t> result;
|
||||||
if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) {
|
if (parse_width_height(options[launcher::Options::FullscreenResolution].value_text(), result)) {
|
||||||
@@ -1170,13 +1331,19 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
|
// SDVXFullscreenLandscape disabled due to it messing with in-game camera angle
|
||||||
#if SPICE64
|
// FullscreenOrientationFlip continues to live on, however.
|
||||||
GRAPHICS_FS_ORIENTATION_SWAP = true;
|
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool()) {
|
||||||
#else
|
log_fatal("launcher", "-sdvxlandscape removed due to a camera bug in SDVX!");
|
||||||
log_warning("launcher", "-sdvxlandscape is not supported in 32-bit SDVX, ignoring...");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
// if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
|
||||||
|
// #if SPICE64
|
||||||
|
// GRAPHICS_FS_ORIENTATION_SWAP = true;
|
||||||
|
// #else
|
||||||
|
// log_warning("launcher", "-sdvxlandscape is not supported in 32-bit SDVX, ignoring...");
|
||||||
|
// #endif
|
||||||
|
// }
|
||||||
|
|
||||||
if (options[launcher::Options::FullscreenOrientationFlip].value_bool() && !GRAPHICS_WINDOWED) {
|
if (options[launcher::Options::FullscreenOrientationFlip].value_bool() && !GRAPHICS_WINDOWED) {
|
||||||
GRAPHICS_FS_ORIENTATION_SWAP = true;
|
GRAPHICS_FS_ORIENTATION_SWAP = true;
|
||||||
}
|
}
|
||||||
@@ -1239,7 +1406,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
log_info("launcher", "loading early hook DLL {}", hook);
|
log_info("launcher", "loading early hook DLL {}", hook);
|
||||||
HMODULE module;
|
HMODULE module;
|
||||||
if (!(module = libutils::try_library(hook))) {
|
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())
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1506,6 +1677,14 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
attach_io = true;
|
attach_io = true;
|
||||||
attach_mfc = true;
|
attach_mfc = true;
|
||||||
break;
|
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
|
// FutureTomTom
|
||||||
@@ -1616,6 +1795,16 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Polaris Chord
|
||||||
|
if (check_dll("kamunity.dll") && fileutils::dir_exists("game/svm_Data")) {
|
||||||
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
|
attach_io = true;
|
||||||
|
attach_pc = true;
|
||||||
|
launcher::signal::USE_VEH_WORKAROUND = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Busou Shinki: Armored Princess Battle Conductor
|
// Busou Shinki: Armored Princess Battle Conductor
|
||||||
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
||||||
avs::game::DLL_NAME = "kamunity.dll";
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
@@ -1640,7 +1829,16 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// usage error
|
// usage error
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE
|
if (!cfg::CONFIGURATOR_STANDALONE
|
||||||
&& (!CHECK_DLL_IGNORE_ARCH)) {
|
&& (!CHECK_DLL_IGNORE_ARCH)) {
|
||||||
log_fatal("launcher", "module auto detection failed.");
|
log_warning(
|
||||||
|
"launcher",
|
||||||
|
"module auto detection failed!\n\n"
|
||||||
|
"This usually means one of the following:\n\n"
|
||||||
|
" 1. You put spice executables in the wrong place, or\n"
|
||||||
|
" 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;
|
break;
|
||||||
|
|
||||||
@@ -1768,6 +1966,10 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::core::set_default_heap_size("kamunity.dll");
|
avs::core::set_default_heap_size("kamunity.dll");
|
||||||
games.push_back(new games::mfg::MFGGame());
|
games.push_back(new games::mfg::MFGGame());
|
||||||
}
|
}
|
||||||
|
if (attach_pc) {
|
||||||
|
avs::core::HEAP_SIZE = 536870912; // 512MB
|
||||||
|
games.push_back(new games::pc::PCGame());
|
||||||
|
}
|
||||||
|
|
||||||
// apply user heap size, if defined
|
// apply user heap size, if defined
|
||||||
if (user_heap_size > 0) {
|
if (user_heap_size > 0) {
|
||||||
@@ -1800,6 +2002,24 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
exit(spicecfg_run(sextet_devices));
|
exit(spicecfg_run(sextet_devices));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// log some DLLs found in path (purely for troubleshooting purposes to detect
|
||||||
|
// dxvk, ForceD3D9On12, ifs_layeredfs, etc)
|
||||||
|
libutils::warn_if_dll_exists("d3d8.dll");
|
||||||
|
libutils::warn_if_dll_exists("d3d9.dll");
|
||||||
|
libutils::warn_if_dll_exists("d3d10core.dll");
|
||||||
|
libutils::warn_if_dll_exists("d3d11.dll");
|
||||||
|
libutils::warn_if_dll_exists("d3d12.dll");
|
||||||
|
libutils::warn_if_dll_exists("dxgi.dll");
|
||||||
|
libutils::warn_if_dll_exists("opengl32.dll");
|
||||||
|
libutils::warn_if_dll_exists("nvcuda.dll");
|
||||||
|
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();
|
||||||
|
|
||||||
// print cpu features
|
// print cpu features
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE && dump_sysinfo) {
|
if (!cfg::CONFIGURATOR_STANDALONE && dump_sysinfo) {
|
||||||
cpuutils::print_cpu_features();
|
cpuutils::print_cpu_features();
|
||||||
@@ -1817,6 +2037,21 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// print devices
|
// print devices
|
||||||
RI_MGR->devices_print();
|
RI_MGR->devices_print();
|
||||||
|
|
||||||
|
auto buttons = games::get_buttons(eamuse_get_game());
|
||||||
|
log_misc("rawinput", "Button mappings:");
|
||||||
|
dump_button_bindings(buttons);
|
||||||
|
|
||||||
|
log_misc("rawinput", "Keypad button mappings:");
|
||||||
|
auto keypads = games::get_buttons_keypads(eamuse_get_game());
|
||||||
|
dump_button_bindings(keypads);
|
||||||
|
|
||||||
|
log_misc("rawinput", "Overlay button mappings:");
|
||||||
|
auto overlay_buttons = games::get_buttons_overlay(eamuse_get_game());
|
||||||
|
dump_button_bindings(overlay_buttons);
|
||||||
|
|
||||||
|
log_misc("rawinput", "Analog mappings:");
|
||||||
|
dump_analog_bindings();
|
||||||
|
|
||||||
// for certain games, show cursor if no touch is available (must be called after RI_MGR is available)
|
// for certain games, show cursor if no touch is available (must be called after RI_MGR is available)
|
||||||
if (show_cursor_if_no_touch && !is_touch_available("launcher::main_implementation")) {
|
if (show_cursor_if_no_touch && !is_touch_available("launcher::main_implementation")) {
|
||||||
GRAPHICS_SHOW_CURSOR = true;
|
GRAPHICS_SHOW_CURSOR = true;
|
||||||
@@ -1958,15 +2193,6 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
networkhook_init();
|
networkhook_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// layeredfs
|
|
||||||
if (fileutils::dir_exists("data_mods") &&
|
|
||||||
!fileutils::file_exists("ifs_hook.dll") &&
|
|
||||||
!fileutils::file_exists(MODULE_PATH / "ifs_hook.dll")) {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
update_msvcrt_args(argc, argv);
|
update_msvcrt_args(argc, argv);
|
||||||
|
|
||||||
// load hooks
|
// load hooks
|
||||||
@@ -1974,12 +2200,28 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
log_info("launcher", "loading hook DLL {}", hook);
|
log_info("launcher", "loading hook DLL {}", hook);
|
||||||
HMODULE module;
|
HMODULE module;
|
||||||
if (!(module = libutils::try_library(hook))) {
|
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 {
|
} else {
|
||||||
bt5api_hook(module);
|
bt5api_hook(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// layeredfs
|
||||||
|
if (fileutils::dir_exists("data_mods") &&
|
||||||
|
GetModuleHandleA("ifs_hook.dll") == nullptr) {
|
||||||
|
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
|
// apply patches
|
||||||
{
|
{
|
||||||
overlay::windows::PatchManager patch_manager(nullptr, true);
|
overlay::windows::PatchManager patch_manager(nullptr, true);
|
||||||
@@ -2112,8 +2354,10 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// debug hook
|
// debug hook
|
||||||
debughook::detach();
|
debughook::detach();
|
||||||
|
|
||||||
|
#ifndef NO_SCARD
|
||||||
// scard
|
// scard
|
||||||
scard_fini();
|
scard_fini();
|
||||||
|
#endif
|
||||||
|
|
||||||
// stop reader thread in case it was running
|
// stop reader thread in case it was running
|
||||||
stop_reader_thread();
|
stop_reader_thread();
|
||||||
@@ -2202,6 +2446,65 @@ void update_msvcrt_args(int argc, char *argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_button_bindings(std::vector<Button> *buttons) {
|
||||||
|
if (!buttons) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto button = buttons->begin(); button != buttons->end(); ++button) {
|
||||||
|
if (!button->isSet()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button->isNaive()) {
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] dev=Naive, vkey={}",
|
||||||
|
button->getName(),
|
||||||
|
button->getVKey()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] dev={}, vkey={}, analogtype={}",
|
||||||
|
button->getName(),
|
||||||
|
button->getDeviceIdentifier(),
|
||||||
|
button->getVKey(),
|
||||||
|
button->getAnalogType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& alt : button->getAlternatives()) {
|
||||||
|
if (alt.getVKey() == INVALID_VKEY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] (alt) dev={}, vkey={}, analogtype={}",
|
||||||
|
button->getName(),
|
||||||
|
alt.isNaive() ? "Naive" : alt.getDeviceIdentifier(),
|
||||||
|
alt.getVKey(),
|
||||||
|
alt.getAnalogType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_analog_bindings() {
|
||||||
|
auto analogs = games::get_analogs(eamuse_get_game());
|
||||||
|
if (!analogs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto& analog : *analogs) {
|
||||||
|
if (!analog.isSet()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
log_misc(
|
||||||
|
"rawinput", " [{}] dev={}, index={}",
|
||||||
|
analog.getName(),
|
||||||
|
analog.getDeviceIdentifier(),
|
||||||
|
analog.getIndex()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SPICETOOLS_SPICECFG_STANDALONE
|
#ifndef SPICETOOLS_SPICECFG_STANDALONE
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
return main_implementation(argc, argv);
|
return main_implementation(argc, argv);
|
||||||
|
|||||||
@@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#ifdef NO_SCARD
|
||||||
|
#define WITH_SCARD 0
|
||||||
|
#else
|
||||||
|
#define WITH_SCARD 1
|
||||||
|
#endif
|
||||||
|
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_API = {
|
static const std::vector<std::string> CATEGORY_ORDER_API = {
|
||||||
"SpiceCompanion and API",
|
"SpiceCompanion and API",
|
||||||
"API (Serial)",
|
"API (Serial)",
|
||||||
@@ -17,7 +23,6 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
|
|||||||
"Game Options",
|
"Game Options",
|
||||||
"Common",
|
"Common",
|
||||||
"Network",
|
"Network",
|
||||||
"Overlay",
|
|
||||||
"Graphics (Common)",
|
"Graphics (Common)",
|
||||||
"Graphics (Full Screen)",
|
"Graphics (Full Screen)",
|
||||||
"Graphics (Windowed)",
|
"Graphics (Windowed)",
|
||||||
@@ -26,35 +31,42 @@ static const std::vector<std::string> CATEGORY_ORDER_BASIC = {
|
|||||||
|
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
|
static const std::vector<std::string> CATEGORY_ORDER_ADVANCED = {
|
||||||
"Game Options (Advanced)",
|
"Game Options (Advanced)",
|
||||||
|
"Overlay",
|
||||||
"Network (Advanced)",
|
"Network (Advanced)",
|
||||||
"Performance",
|
"Performance",
|
||||||
"Miscellaneous",
|
"Miscellaneous",
|
||||||
"Paths",
|
|
||||||
"Touch Parameters",
|
"Touch Parameters",
|
||||||
"I/O Options",
|
"I/O Options",
|
||||||
"NFC Card Readers",
|
"NFC Card Readers",
|
||||||
};
|
};
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_DEV = {
|
static const std::vector<std::string> CATEGORY_ORDER_DEV = {
|
||||||
"Network Adapters",
|
"Path Overrides",
|
||||||
|
"Network (Development)",
|
||||||
|
"Audio (Hacks)",
|
||||||
"I/O Modules",
|
"I/O Modules",
|
||||||
"Development",
|
"Development",
|
||||||
|
"Debug Log",
|
||||||
};
|
};
|
||||||
static const std::vector<std::string> CATEGORY_ORDER_NONE = {
|
static const std::vector<std::string> CATEGORY_ORDER_NONE = {
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool launcher::USE_CMD_OVERRIDE = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Option Definitions
|
* Option Definitions
|
||||||
* Be aware that the order must be the same as in the enum launcher::Options!
|
* Be aware that the order must be the same as in the enum launcher::Options!
|
||||||
*/
|
*/
|
||||||
static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||||
{
|
{
|
||||||
.title = "Game Executable",
|
.title = "Override Game Executable & Disable Hooks",
|
||||||
.name = "exec",
|
.name = "exec",
|
||||||
.desc = "Path to the game DLL file",
|
.desc = "Path to the game DLL file.\n\n"
|
||||||
|
"This option is typically not needed; leave it empty to allow spice to auto-detect your game.\n\n"
|
||||||
|
"WARNING: this option also disables all game-specific hooks and turns off most I/O modules!",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.setting_name = "*.dll",
|
.setting_name = "*.dll",
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Open Configurator",
|
.title = "Open Configurator",
|
||||||
@@ -81,6 +93,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Network",
|
.category = "Network",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// ServiceURL
|
||||||
.title = "EA Service URL",
|
.title = "EA Service URL",
|
||||||
.name = "url",
|
.name = "url",
|
||||||
.desc = "Sets a custom service URL override",
|
.desc = "Sets a custom service URL override",
|
||||||
@@ -142,6 +155,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Graphics (Windowed)",
|
.category = "Graphics (Windowed)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// InjectHook
|
||||||
.title = "Inject DLL Hooks",
|
.title = "Inject DLL Hooks",
|
||||||
.name = "k",
|
.name = "k",
|
||||||
.desc = "Multiple files are allowed; use multiple -k flags, or in SpiceCfg, separate by "
|
.desc = "Multiple files are allowed; use multiple -k flags, or in SpiceCfg, separate by "
|
||||||
@@ -152,6 +166,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Common",
|
.category = "Common",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// EarlyInjectHook
|
||||||
.title = "Inject Early DLL Hooks",
|
.title = "Inject Early DLL Hooks",
|
||||||
.name = "z",
|
.name = "z",
|
||||||
.desc = "Equivalent to 'Inject DLL Hooks' option, but ensures hooks are injected before "
|
.desc = "Equivalent to 'Inject DLL Hooks' option, but ensures hooks are injected before "
|
||||||
@@ -228,7 +243,8 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.desc =
|
.desc =
|
||||||
"Allows you to play portrait games in in landscape (and vice versa) by transposing resolution and applying image scaling.\n\n"
|
"Allows you to play portrait games in in landscape (and vice versa) by transposing resolution and applying image scaling.\n\n"
|
||||||
"Works great for some games, but can COMPLETELY BREAK other games - YMMV!\n\n"
|
"Works great for some games, but can COMPLETELY BREAK other games - YMMV!\n\n"
|
||||||
"Strongly consider combining this with -forceres option to render at monitor native resolution",
|
"Strongly consider combining this with -forceres option to render at monitor native resolution\n\n"
|
||||||
|
"WARNING: for SDVX, this messes with camera angle for note lanes, causing it to be zoomed out!",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Graphics (Full Screen)"
|
.category = "Graphics (Full Screen)"
|
||||||
},
|
},
|
||||||
@@ -262,7 +278,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "nolegacy",
|
.name = "nolegacy",
|
||||||
.desc = "Disables legacy key activation in-game.",
|
.desc = "Disables legacy key activation in-game.",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Miscellaneous",
|
.category = "I/O Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Discord Rich Presence",
|
.title = "Discord Rich Presence",
|
||||||
@@ -304,28 +320,29 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.desc = "This is NOT the EA service URL; use -url for that. "
|
.desc = "This is NOT the EA service URL; use -url for that. "
|
||||||
"Force the use of an adapter with the specified network. Must also provide -subnet",
|
"Force the use of an adapter with the specified network. Must also provide -subnet",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Network Adapters",
|
.category = "Network (Development)",
|
||||||
|
.sensitive = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Preferred NetAdapter Subnet",
|
.title = "Preferred NetAdapter Subnet",
|
||||||
.name = "subnet",
|
.name = "subnet",
|
||||||
.desc = "Force the use of an adapter with the specified subnet. Must also provide -network",
|
.desc = "Force the use of an adapter with the specified subnet. Must also provide -network",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Network Adapters",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Disable Network Fixes",
|
.title = "Disable Network Fixes",
|
||||||
.name = "netfixdisable",
|
.name = "netfixdisable",
|
||||||
.desc = "Force disables network fixes",
|
.desc = "Force disables network fixes",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Network Adapters",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "HTTP/1.1",
|
.title = "HTTP/1.1",
|
||||||
.name = "http11",
|
.name = "http11",
|
||||||
.desc = "Sets EA3 http11 value",
|
.desc = "Sets EA3 http11 value",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Network (Advanced)",
|
.category = "Network (Development)",
|
||||||
.elements = {{"0", "Off"}, {"1", "On"}},
|
.elements = {{"0", "Off"}, {"1", "On"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -333,7 +350,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "ssldisable",
|
.name = "ssldisable",
|
||||||
.desc = "Prevents the SSL protocol from being registered",
|
.desc = "Prevents the SSL protocol from being registered",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Network (Advanced)",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "URL Slash",
|
.title = "URL Slash",
|
||||||
@@ -348,7 +365,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "r",
|
.name = "r",
|
||||||
.desc = "Set custom SOFTID override",
|
.desc = "Set custom SOFTID override",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Network (Advanced)",
|
.category = "Development",
|
||||||
.sensitive = true,
|
.sensitive = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -543,10 +560,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "IIDX BIO2 Firmware",
|
.title = "IIDX BIO2 Firmware Update",
|
||||||
.name = "iidxbio2fw",
|
.name = "iidxbio2fw",
|
||||||
.desc = "Enables BIO2 firmware updates",
|
.desc = "Enables BIO2 firmware updates. WARNING - can cause semi-permanent change to your I/O board",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = true,
|
||||||
.game_name = "Beatmania IIDX",
|
.game_name = "Beatmania IIDX",
|
||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
@@ -666,6 +684,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// SDVXPrinterOutputPath
|
||||||
.title = "SDVX Printer Output Path",
|
.title = "SDVX Printer Output Path",
|
||||||
.name = "printerpath",
|
.name = "printerpath",
|
||||||
.desc = "Path to folder where images will be stored",
|
.desc = "Path to folder where images will be stored",
|
||||||
@@ -690,9 +709,10 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// SDVXPrinterOutputFormat
|
||||||
.title = "SDVX Printer Output Format",
|
.title = "SDVX Printer Output Format",
|
||||||
.name = "printerformat",
|
.name = "printerformat",
|
||||||
.desc = "Path to folder where images will be stored",
|
.desc = "File format for printer output",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.setting_name = "(png/bmp/tga/jpg)",
|
.setting_name = "(png/bmp/tga/jpg)",
|
||||||
.game_name = "Sound Voltex",
|
.game_name = "Sound Voltex",
|
||||||
@@ -708,10 +728,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "SDVX Disable Cameras",
|
.title = "SDVX Disable Cameras (DEPRECATED - no longer needed)",
|
||||||
.name = "sdvxdisablecams",
|
.name = "sdvxdisablecams",
|
||||||
.desc = "Disables cameras",
|
.desc = "This option does nothing.\n\n"
|
||||||
|
"This option was used in the past to fix cameras in SDVX5 but this is no longer "
|
||||||
|
"needed as camera check will always be skipped with a built-in patch.",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = true,
|
||||||
.game_name = "Sound Voltex",
|
.game_name = "Sound Voltex",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
@@ -797,6 +820,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Dance Dance Revolution",
|
.game_name = "Dance Dance Revolution",
|
||||||
.category = "Game Options",
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// DDRSkipCodecRegisteration
|
||||||
|
.title = "DDR Skip Codec Registration",
|
||||||
|
.name = "ddrnocodec",
|
||||||
|
.desc = "Prevent automatic registration of codecs in the com folder",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Dance Dance Revolution",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.title = "Force Load Pop'n Music Module",
|
.title = "Force Load Pop'n Music Module",
|
||||||
.name = "pnm",
|
.name = "pnm",
|
||||||
@@ -1024,7 +1056,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// LoadCCJModule
|
// LoadCCJModule
|
||||||
.title = "Force Load Chase Chase Jokers",
|
.title = "Force Load Chase Chase Jokers Module",
|
||||||
.name = "ccj",
|
.name = "ccj",
|
||||||
.desc = "manually enable Chase Chase Jokers module",
|
.desc = "manually enable Chase Chase Jokers module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
@@ -1033,7 +1065,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// LoadQKSModule
|
// LoadQKSModule
|
||||||
.title = "Force Load QuizKnock STADIUM",
|
.title = "Force Load QuizKnock STADIUM Module",
|
||||||
.name = "qks",
|
.name = "qks",
|
||||||
.desc = "manually enable QuizKnock STADIUM module",
|
.desc = "manually enable QuizKnock STADIUM module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
@@ -1042,16 +1074,25 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// LoadMFGModule
|
// LoadMFGModule
|
||||||
.title = "Force Load Mahjong Fight Girl",
|
.title = "Force Load Mahjong Fight Girl Module",
|
||||||
.name = "mfg",
|
.name = "mfg",
|
||||||
.desc = "manually enable Mahjong Fight Girl module",
|
.desc = "manually enable Mahjong Fight Girl module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.game_name = "Mahjong Fight Girl",
|
.game_name = "Mahjong Fight Girl",
|
||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// LoadPCModule
|
||||||
|
.title = "Force Load Polaris Chord Module",
|
||||||
|
.name = "pc",
|
||||||
|
.desc = "manually enable Polaris Chord module",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// LoadMusecaModule
|
// LoadMusecaModule
|
||||||
.title = "Force Load Museca",
|
.title = "Force Load Museca Module",
|
||||||
.name = "museca",
|
.name = "museca",
|
||||||
.desc = "manually enable Museca module",
|
.desc = "manually enable Museca module",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
@@ -1059,88 +1100,88 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Modules Folder Path",
|
.title = "Modules Folder Override",
|
||||||
.name = "modules",
|
.name = "modules",
|
||||||
.desc = "Sets a custom path to the modules folder",
|
.desc = "Sets a custom path to the modules folder",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Screenshot Folder Path",
|
.title = "Screenshot Folder Override",
|
||||||
.name = "screenshotpath",
|
.name = "screenshotpath",
|
||||||
.desc = "Sets a custom path to the screenshots folder",
|
.desc = "Sets a custom path to the screenshots folder",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Configuration Path",
|
.title = "Configuration Path Override",
|
||||||
.name = "cfgpath",
|
.name = "cfgpath",
|
||||||
.desc = "Sets a custom file path for config file. Must be passed via the command line. "
|
.desc = "Sets a custom file path for config file. Must be passed via the command line. "
|
||||||
"If left empty, %appdata%\\spicetools.xml will be used",
|
"If left empty, %appdata%\\spicetools.xml will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.setting_name = "(default)",
|
.setting_name = "(default)",
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
.disabled = true,
|
.disabled = true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// ScreenResizeConfigPath
|
// ScreenResizeConfigPath
|
||||||
.title = "Screen Resize Config Path",
|
.title = "Screen Resize Config Path Override",
|
||||||
.name = "resizecfgpath",
|
.name = "resizecfgpath",
|
||||||
.desc = "Sets a custom file path for screen resize config file. "
|
.desc = "Sets a custom file path for screen resize config file. "
|
||||||
"If left empty, %appdata%\\spicetools_screen_resize.json will be used",
|
"If left empty, %appdata%\\spice2x\\spicetools_screen_resize.json will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// PatchManagerConfigPath
|
// PatchManagerConfigPath
|
||||||
.title = "Patch Manager Config Path",
|
.title = "Patch Manager Config Path Override",
|
||||||
.name = "patchcfgpath",
|
.name = "patchcfgpath",
|
||||||
.desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. "
|
.desc = "Sets a custom file path for patch manager config file. Can be used to manage 'profiles' for auto-patches. "
|
||||||
"If left empty, %appdata%\\spicetools_patch_manager.json will be used",
|
"If left empty, %appdata%\\spice2x\\spicetools_patch_manager.json will be used",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Intel SDE Folder Path",
|
.title = "Intel SDE",
|
||||||
.name = "sde",
|
.name = "sde",
|
||||||
.desc = "Path to Intel SDE kit path for automatic attaching",
|
.desc = "Path to Intel SDE kit path for automatic attaching",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Development",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to ea3-config.xml",
|
.title = "ea3-config.xml Override",
|
||||||
.name = "e",
|
.name = "e",
|
||||||
.desc = "Sets a custom path to ea3-config.xml",
|
.desc = "Sets a custom path to ea3-config.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to app-config.xml",
|
.title = "app-config.xml Override",
|
||||||
.name = "a",
|
.name = "a",
|
||||||
.desc = "Sets a custom path to app-config.xml",
|
.desc = "Sets a custom path to app-config.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to avs-config.xml",
|
.title = "avs-config.xml Override",
|
||||||
.name = "v",
|
.name = "v",
|
||||||
.desc = "Sets a custom path to avs-config.xml",
|
.desc = "Sets a custom path to avs-config.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to bootstrap.xml",
|
.title = "bootstrap.xml Override",
|
||||||
.name = "b",
|
.name = "b",
|
||||||
.desc = "Sets a custom path to bootstrap.xml",
|
.desc = "Sets a custom path to bootstrap.xml",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Path to log.txt",
|
.title = "log.txt Override",
|
||||||
.name = "y",
|
.name = "y",
|
||||||
.desc = "Sets a custom path to log.txt",
|
.desc = "Sets a custom path to log.txt",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Paths",
|
.category = "Path Overrides",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "API TCP Port",
|
.title = "API TCP Port",
|
||||||
@@ -1192,6 +1233,28 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "API (Dev)",
|
.category = "API (Dev)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// APIScreenMirrorQuality
|
||||||
|
.title = "API Screen Mirror Quality Override",
|
||||||
|
.name = "apiscreenq",
|
||||||
|
.desc = "JPEG compression level of mirrored images, overriding any client request. "
|
||||||
|
"Value must be between 0 (poor quality) and 100 (best quality), inclusive. Default: 70",
|
||||||
|
.type = OptionType::Integer,
|
||||||
|
.setting_name = "(0-100)",
|
||||||
|
.category = "SpiceCompanion and API",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// APIScreenMirrorDivide
|
||||||
|
.title = "API Screen Mirror Divide Override",
|
||||||
|
.name = "apiscreendiv",
|
||||||
|
.desc = "Divide value of mirrored images, overriding any client request. "
|
||||||
|
"Divide of 1 means send every pixel, 2 means every other pixel, 3 means every third pixel, and so on; "
|
||||||
|
"increasing the value drastically reduces transfer size at the cost of image quality. "
|
||||||
|
"Value must be 1 or greater. Default: 1",
|
||||||
|
.type = OptionType::Integer,
|
||||||
|
.setting_name = "1",
|
||||||
|
.category = "SpiceCompanion and API",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.title = "Enable All IO Modules",
|
.title = "Enable All IO Modules",
|
||||||
.name = "io",
|
.name = "io",
|
||||||
@@ -1287,6 +1350,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Touch Parameters",
|
.category = "Touch Parameters",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// ICCAReaderPort
|
||||||
.title = "ICCA Reader Port",
|
.title = "ICCA Reader Port",
|
||||||
.name = "reader",
|
.name = "reader",
|
||||||
.desc = "Connects to and uses a ICCA on a given COM port",
|
.desc = "Connects to and uses a ICCA on a given COM port",
|
||||||
@@ -1327,21 +1391,27 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "scard",
|
.name = "scard",
|
||||||
.desc = "Detects and uses HID smart card readers for card input. Developed for ACR122U reader",
|
.desc = "Detects and uses HID smart card readers for card input. Developed for ACR122U reader",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = !WITH_SCARD,
|
||||||
.category = "NFC Card Readers",
|
.category = "NFC Card Readers",
|
||||||
|
.disabled = !WITH_SCARD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "HID SmartCard Order Flip",
|
.title = "HID SmartCard Order Flip",
|
||||||
.name = "scardflip",
|
.name = "scardflip",
|
||||||
.desc = "Flips the order of detection for P1/P2",
|
.desc = "Flips the order of detection for P1/P2",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = !WITH_SCARD,
|
||||||
.category = "NFC Card Readers",
|
.category = "NFC Card Readers",
|
||||||
|
.disabled = !WITH_SCARD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "HID SmartCard Order Toggle",
|
.title = "HID SmartCard Order Toggle",
|
||||||
.name = "scardtoggle",
|
.name = "scardtoggle",
|
||||||
.desc = "Toggles reader between P1/P2 using the NumLock key state",
|
.desc = "Toggles reader between P1/P2 using the NumLock key state",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = !WITH_SCARD,
|
||||||
.category = "NFC Card Readers",
|
.category = "NFC Card Readers",
|
||||||
|
.disabled = !WITH_SCARD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// HIDSmartCardIdConvert
|
// HIDSmartCardIdConvert
|
||||||
@@ -1355,19 +1425,22 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"For example, abcd56780123 is converted to e00401abcd567801 on card in. This results in different card numbers so "
|
"For example, abcd56780123 is converted to e00401abcd567801 on card in. This results in different card numbers so "
|
||||||
"be careful when connecting to servers!",
|
"be careful when connecting to servers!",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
|
.hidden = !WITH_SCARD,
|
||||||
.category = "NFC Card Readers",
|
.category = "NFC Card Readers",
|
||||||
.elements = {
|
.elements = {
|
||||||
{"legacy", "Use cards as-is"},
|
{"legacy", "Use cards as-is"},
|
||||||
{"fix", "Fix bad cards only"},
|
{"fix", "Fix bad cards only"},
|
||||||
{"all", "Force all cards"},
|
{"all", "Force all cards"},
|
||||||
},
|
},
|
||||||
|
.disabled = !WITH_SCARD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// SextetStreamPort
|
||||||
.title = "SextetStream Port",
|
.title = "SextetStream Port",
|
||||||
.name = "sextet",
|
.name = "sextet",
|
||||||
.desc = "Use a SextetStream device on a given COM port",
|
.desc = "Use a SextetStream device on a given COM port",
|
||||||
.type = OptionType::Text,
|
.type = OptionType::Text,
|
||||||
.category = "Miscellaneous",
|
.category = "I/O Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Enable BemaniTools 5 API",
|
.title = "Enable BemaniTools 5 API",
|
||||||
@@ -1468,7 +1541,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"you use a different backend instead of exclusive WASAPI).\n\n"
|
"you use a different backend instead of exclusive WASAPI).\n\n"
|
||||||
"Check this if you want games to natively access your audio device",
|
"Check this if you want games to natively access your audio device",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// spice2x_DisableVolumeHook
|
// spice2x_DisableVolumeHook
|
||||||
@@ -1480,7 +1553,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"Default: off (prevent games from changing audio volume by hooking IAudioEndpointVolume).\n\n"
|
"Default: off (prevent games from changing audio volume by hooking IAudioEndpointVolume).\n\n"
|
||||||
"Check this if you want games to freely change your volume",
|
"Check this if you want games to freely change your volume",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Spice Audio Hook Backend",
|
.title = "Spice Audio Hook Backend",
|
||||||
@@ -1489,7 +1562,10 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"Does nothing for games that do not output to exclusive WASAPI",
|
"Does nothing for games that do not output to exclusive WASAPI",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Audio",
|
.category = "Audio",
|
||||||
.elements = {{"asio", "ASIO"}, {"waveout", "waveOut"}},
|
.elements = {
|
||||||
|
{"asio", "ASIO"},
|
||||||
|
{"waveout", "broken, do not use"}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Spice Audio Hook ASIO Driver ID",
|
.title = "Spice Audio Hook ASIO Driver ID",
|
||||||
@@ -1505,7 +1581,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
"This is automatically enabled when required and not normally needed",
|
"This is automatically enabled when required and not normally needed",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.hidden = true,
|
.hidden = true,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// DelayBy5Seconds
|
// DelayBy5Seconds
|
||||||
@@ -1558,11 +1634,11 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.elements = {{"0", "90 (CW)"}, {"1", "270 (CCW)"}},
|
.elements = {{"0", "90 (CW)"}, {"1", "270 (CCW)"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Log Level",
|
.title = "AVS Log Level",
|
||||||
.name = "loglevel",
|
.name = "loglevel",
|
||||||
.desc = "Set the level of detail that gets written to the log",
|
.desc = "Set the level of detail for AVS log messages written to the log. Does not affect logging from spice",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Performance",
|
.category = "Debug Log",
|
||||||
.elements = {{"fatal", ""}, {"warning", ""}, {"info", ""}, {"misc", ""}, {"all", ""}, {"disable", ""}},
|
.elements = {{"fatal", ""}, {"warning", ""}, {"info", ""}, {"misc", ""}, {"all", ""}, {"disable", ""}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1570,14 +1646,14 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "automap",
|
.name = "automap",
|
||||||
.desc = "Enable automap in patch configuration",
|
.desc = "Enable automap in patch configuration",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "EA Netdump",
|
.title = "EA Netdump",
|
||||||
.name = "netdump",
|
.name = "netdump",
|
||||||
.desc = "Enable automap in network dumping configuration",
|
.desc = "Enable automap in network dumping configuration",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Network (Development)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Discord RPC AppID Override",
|
.title = "Discord RPC AppID Override",
|
||||||
@@ -1591,35 +1667,45 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "logblock",
|
.name = "logblock",
|
||||||
.desc = "Slower but safer logging used for debugging",
|
.desc = "Slower but safer logging used for debugging",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Debug CreateFile",
|
.title = "Debug CreateFile",
|
||||||
.name = "createfiledebug",
|
.name = "createfiledebug",
|
||||||
.desc = "Outputs CreateFile debug prints",
|
.desc = "Outputs CreateFile debug prints",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Verbose Graphics Logging",
|
.title = "Verbose Graphics Logging",
|
||||||
.name = "graphicsverbose",
|
.name = "graphicsverbose",
|
||||||
.desc = "Enable the verbose logging of graphics hook code",
|
.desc = "Enable the verbose logging of graphics hook code",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Verbose AVS Logging",
|
.title = "Verbose AVS Logging",
|
||||||
.name = "avsverbose",
|
.name = "avsverbose",
|
||||||
.desc = "Enable the verbose logging of AVS filesystem functions",
|
.desc = "Enable the verbose logging of AVS filesystem functions",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AllowEA3Verbose
|
||||||
|
.title = "Allow EA3 Verbose Debug Logging",
|
||||||
|
.name = "ea3verbose",
|
||||||
|
.desc = "This option is only useful for network developers; leave this OFF.\n\n"
|
||||||
|
"By default, ea3/debug/verbose node is removed by spice to prevent exposing PCBID in the logs. "
|
||||||
|
"When this is enabled, ea3/debug/verbose node in the XML will be kept and exposed to the game",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Disable Colored Output",
|
.title = "Disable Colored Output",
|
||||||
.name = "nocolor",
|
.name = "nocolor",
|
||||||
.desc = "Disable terminal colors for log outputs to console",
|
.desc = "Disable terminal colors for log outputs to console",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.title = "Disable ACP Hook",
|
.title = "Disable ACP Hook",
|
||||||
@@ -1654,7 +1740,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "pebprint",
|
.name = "pebprint",
|
||||||
.desc = "Prints PEB on startup to console",
|
.desc = "Prints PEB on startup to console",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// DumpSystemInfo
|
// DumpSystemInfo
|
||||||
@@ -1662,7 +1748,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.name = "sysdump",
|
.name = "sysdump",
|
||||||
.desc = "Print system information to the log on startup. Default: basic",
|
.desc = "Print system information to the log on startup. Default: basic",
|
||||||
.type = OptionType::Enum,
|
.type = OptionType::Enum,
|
||||||
.category = "Development",
|
.category = "Debug Log",
|
||||||
.elements = {
|
.elements = {
|
||||||
{"none", "Nothing"},
|
{"none", "Nothing"},
|
||||||
{"basic", "OS, CPU, SMBIOS, GPU"},
|
{"basic", "OS, CPU, SMBIOS, GPU"},
|
||||||
@@ -1747,6 +1833,35 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Mahjong Fight Girl",
|
.game_name = "Mahjong Fight Girl",
|
||||||
.category = "Game Options (Advanced)"
|
.category = "Game Options (Advanced)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// PCArgs
|
||||||
|
.title = "PC Arguments Override",
|
||||||
|
.name = "pcargs",
|
||||||
|
.desc = "Command line arguments passed to the game.",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// PCNoIO
|
||||||
|
.title = "PC Disable IO Emulation",
|
||||||
|
.name = "pcnoio",
|
||||||
|
.desc = "Disables BI2X hooks for PC",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.setting_name = "",
|
||||||
|
.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
|
// spice2x_LightsOverallBrightness
|
||||||
.title = "Lights Brightness Adjustment",
|
.title = "Lights Brightness Adjustment",
|
||||||
@@ -1841,6 +1956,24 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Beatmania IIDX",
|
.game_name = "Beatmania IIDX",
|
||||||
.category = "Graphics (Windowed)",
|
.category = "Graphics (Windowed)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// IIDXWindowedSubscreenBorderless
|
||||||
|
.title = "IIDX Windowed Subscreen Borderless",
|
||||||
|
.name = "iidxwsubborderless",
|
||||||
|
.desc = "Remove window decoration from windowed subscreen",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Beatmania IIDX",
|
||||||
|
.category = "Graphics (Windowed)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// IIDXWindowedSubscreenAlwaysOnTop
|
||||||
|
.title = "IIDX Windowed Subscreen Always On Top",
|
||||||
|
.name = "iidxwsubtop",
|
||||||
|
.desc = "Keep windowed subscreen on top",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Beatmania IIDX",
|
||||||
|
.category = "Graphics (Windowed)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// spice2x_JubeatLegacyTouch
|
// spice2x_JubeatLegacyTouch
|
||||||
.title = "JB Legacy Touch Targets",
|
.title = "JB Legacy Touch Targets",
|
||||||
@@ -1874,7 +2007,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.desc = "For certain buggy ASIO drivers, force unload of ASIO driver when audio stream stops. "
|
.desc = "For certain buggy ASIO drivers, force unload of ASIO driver when audio stream stops. "
|
||||||
"Used for working around ASIO drivers that lock up after force quitting games",
|
"Used for working around ASIO drivers that lock up after force quitting games",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
.category = "Audio",
|
.category = "Audio (Hacks)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// spice2x_IIDXNoESpec
|
// spice2x_IIDXNoESpec
|
||||||
@@ -2049,15 +2182,17 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// SDVXFullscreenLandscape
|
// SDVXFullscreenLandscape
|
||||||
.title = "SDVX Landscape Mode (SDVX5+)",
|
.title = "(DISABLED) SDVX Landscape Mode (SDVX5+)",
|
||||||
.name = "sdvxlandscape",
|
.name = "sdvxlandscape",
|
||||||
.desc =
|
.desc =
|
||||||
|
"Option HIDDEN and DISABLED due to it affecting in-game camera angle for displaying lanes.\n\n"
|
||||||
"Allows you to play in landscape by transposing resolution and applying image scaling.\n\n"
|
"Allows you to play in landscape by transposing resolution and applying image scaling.\n\n"
|
||||||
"Works only for SDVX5 and above! This is identical to -forceresswap.\n\n"
|
"Works only for SDVX5 and above! This is identical to -forceresswap.\n\n"
|
||||||
"Will launch at 1080p by default; strongly consider combining this with -forceres option to render at monitor native resolution",
|
"Will launch at 1080p by default; strongly consider combining this with -forceres option to render at monitor native resolution",
|
||||||
.type = OptionType::Bool,
|
.type = OptionType::Bool,
|
||||||
|
.hidden = true,
|
||||||
.game_name = "Sound Voltex",
|
.game_name = "Sound Voltex",
|
||||||
.category = "Game Options"
|
.category = "Game Options",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// spice2x_EnableSMXStage
|
// spice2x_EnableSMXStage
|
||||||
@@ -2126,6 +2261,23 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.setting_name = "20",
|
.setting_name = "20",
|
||||||
.category = "I/O Options",
|
.category = "I/O Options",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// InputRequiresFocus
|
||||||
|
.title = "Input Requires Focus",
|
||||||
|
.name = "inputfocus",
|
||||||
|
.desc =
|
||||||
|
"Determine input behavior when game window is not in focus.\n\n"
|
||||||
|
"never: allow input regardless of focus\n"
|
||||||
|
"naive (default): only naive bindings check for window focus, rawinput binds are always allowed\n"
|
||||||
|
"always: only process input when window is in focus",
|
||||||
|
.type = OptionType::Enum,
|
||||||
|
.category = "I/O Options",
|
||||||
|
.elements = {
|
||||||
|
{"never", ""},
|
||||||
|
{"naive", ""},
|
||||||
|
{"always", ""},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// NostalgiaPoke
|
// NostalgiaPoke
|
||||||
.title = "Nost Screen Poke",
|
.title = "Nost Screen Poke",
|
||||||
@@ -2150,6 +2302,107 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
{"2", "double buffer"},
|
{"2", "double buffer"},
|
||||||
{"3", "triple buffer"},
|
{"3", "triple buffer"},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SDVXWindowedSubscreenSize
|
||||||
|
.title = "SDVX Windowed Subscreen Size",
|
||||||
|
.name = "sdvxwsubsize",
|
||||||
|
.desc = "Size of the subscreen window. Defaults to (1920,1080)",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "1920,1080",
|
||||||
|
.game_name = "Sound Voltex",
|
||||||
|
.category = "Graphics (Windowed)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SDVXWindowedSubscreenPosition
|
||||||
|
.title = "SDVX Windowed Subscreen Position",
|
||||||
|
.name = "sdvxwsubpos",
|
||||||
|
.desc = "Initial position of the subscreen window. Defaults to (0,0)",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "0,0",
|
||||||
|
.game_name = "Sound Voltex",
|
||||||
|
.category = "Graphics (Windowed)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SDVXWindowedSubscreenBorderless
|
||||||
|
.title = "SDVX Windowed Subscreen Borderless",
|
||||||
|
.name = "sdvxwsubborderless",
|
||||||
|
.desc = "Remove window decoration from windowed subscreen",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Sound Voltex",
|
||||||
|
.category = "Graphics (Windowed)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SDVXWindowedSubscreenAlwaysOnTop
|
||||||
|
.title = "SDVX Windowed Subscreen Always On Top",
|
||||||
|
.name = "sdvxwsubtop",
|
||||||
|
.desc = "Keep windowed subscreen on top",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Sound Voltex",
|
||||||
|
.category = "Graphics (Windowed)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LovePlusCamEnable
|
||||||
|
.title = "LovePlus Camera Enable",
|
||||||
|
.name = "lovepluscam",
|
||||||
|
.desc = "Allow game to access camera; camera must be compatible with game",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "LovePlus",
|
||||||
|
.category = "Game Options",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LovePlusPrinterOutputPath
|
||||||
|
.title = "LovePlus Printer Output Path",
|
||||||
|
.name = "lpprinterpath",
|
||||||
|
.desc = "Path to folder where images will be stored",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.game_name = "LovePlus",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "LovePlus Printer Output Clear",
|
||||||
|
.name = "lpprinterclear",
|
||||||
|
.desc = "Clean up saved images in the output directory on startup",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "LovePlus",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "LovePlus Printer Output Overwrite",
|
||||||
|
.name = "lpprinteroverwrite",
|
||||||
|
.desc = "Always overwrite the same file in output directory",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "LovePlus",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// LovePlusPrinterOutputFormat
|
||||||
|
.title = "LovePlus Printer Output Format",
|
||||||
|
.name = "lpprinterformat",
|
||||||
|
.desc = "File format for printer output",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "(png/bmp/tga/jpg)",
|
||||||
|
.game_name = "LovePlus",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "LovePlus Printer JPG Quality",
|
||||||
|
.name = "lpprinterjpgquality",
|
||||||
|
.desc = "Quality setting in percent if JPG format is used",
|
||||||
|
.type = OptionType::Integer,
|
||||||
|
.setting_name = "(0-100)",
|
||||||
|
.game_name = "LovePlus",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// OptionConflictResolution
|
||||||
|
.title = "Command Line Args Override",
|
||||||
|
.name = "cmdoverride",
|
||||||
|
.desc = "By default, option values in spicecfg take precedence over command-line args, for legacy compat.\n"
|
||||||
|
"When this is specified in command line, command-line args take precedence instead",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.category = "Development",
|
||||||
|
.disabled = true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2231,7 +2484,7 @@ std::unique_ptr<std::vector<Option>> launcher::parse_options(int argc, char *arg
|
|||||||
} else {
|
} else {
|
||||||
// validate it is an integer
|
// validate it is an integer
|
||||||
try {
|
try {
|
||||||
std::stoull(argv[i], nullptr, 16);
|
auto _ = std::stoull(argv[i], nullptr, 16);
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception &ex) {
|
||||||
log_fatal("options", "parameter for -{} is not a hex number: {}", alias, argv[i]);
|
log_fatal("options", "parameter for -{} is not a hex number: {}", alias, argv[i]);
|
||||||
}
|
}
|
||||||
@@ -2332,12 +2585,25 @@ std::vector<Option> launcher::merge_options(
|
|||||||
auto &new_option = merged.emplace_back(option.get_definition(), "");
|
auto &new_option = merged.emplace_back(option.get_definition(), "");
|
||||||
new_option.disabled = true;
|
new_option.disabled = true;
|
||||||
|
|
||||||
|
if (USE_CMD_OVERRIDE) {
|
||||||
|
// command-line arguments take precedence (opt-in)
|
||||||
|
for (auto &value : override.values()) {
|
||||||
|
new_option.value_add(value);
|
||||||
|
}
|
||||||
|
for (auto &value : option.values()) {
|
||||||
|
new_option.value_add(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// spicecfg options take precedence (default)
|
||||||
|
// this sucks, but it's the default for legacy spicetools compat
|
||||||
for (auto &value : option.values()) {
|
for (auto &value : option.values()) {
|
||||||
new_option.value_add(value);
|
new_option.value_add(value);
|
||||||
}
|
}
|
||||||
for (auto &value : override.values()) {
|
for (auto &value : override.values()) {
|
||||||
new_option.value_add(value);
|
new_option.value_add(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
new_option.conflicting = true;
|
||||||
} else {
|
} else {
|
||||||
auto &new_option = merged.emplace_back(override.get_definition(), "");
|
auto &new_option = merged.emplace_back(override.get_definition(), "");
|
||||||
new_option.disabled = true;
|
new_option.disabled = true;
|
||||||
@@ -2353,12 +2619,22 @@ std::vector<Option> launcher::merge_options(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string launcher::detect_bootstrap_release_code() {
|
std::string launcher::detect_bootstrap_release_code(const std::string& bootstrap_user) {
|
||||||
std::string bootstrap_path = "prop/bootstrap.xml";
|
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
|
// load XML
|
||||||
tinyxml2::XMLDocument bootstrap;
|
tinyxml2::XMLDocument bootstrap;
|
||||||
@@ -2381,7 +2657,7 @@ std::string launcher::detect_bootstrap_release_code() {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static launcher::GameVersion detect_gameversion_ident() {
|
static launcher::GameVersion detect_gameversion_ident(const std::string& bootstrap_user) {
|
||||||
|
|
||||||
// detect ea3-ident path
|
// detect ea3-ident path
|
||||||
std::string ident_path;
|
std::string ident_path;
|
||||||
@@ -2427,7 +2703,7 @@ static launcher::GameVersion detect_gameversion_ident() {
|
|||||||
auto node_ext = node_soft->FirstChildElement("ext");
|
auto node_ext = node_soft->FirstChildElement("ext");
|
||||||
if (node_ext) {
|
if (node_ext) {
|
||||||
version.ext = node_ext->GetText();
|
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) {
|
if (version.ext.size() != 10 && bootstrap_ext.size() == 10) {
|
||||||
version.ext = bootstrap_ext;
|
version.ext = bootstrap_ext;
|
||||||
} else if (bootstrap_ext.size() == 10) {
|
} else if (bootstrap_ext.size() == 10) {
|
||||||
@@ -2463,8 +2739,7 @@ static launcher::GameVersion detect_gameversion_ident() {
|
|||||||
return launcher::GameVersion();
|
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
|
// detect ea3-config path
|
||||||
std::string ea3_path;
|
std::string ea3_path;
|
||||||
if (!ea3_user.empty()) {
|
if (!ea3_user.empty()) {
|
||||||
@@ -2478,7 +2753,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
|||||||
}
|
}
|
||||||
if (ea3_path.empty()) {
|
if (ea3_path.empty()) {
|
||||||
log_warning("options", "unable to detect EA3 configuration file");
|
log_warning("options", "unable to detect EA3 configuration file");
|
||||||
return detect_gameversion_ident();
|
return detect_gameversion_ident(bootstrap_user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load XML
|
// load XML
|
||||||
@@ -2518,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 (ea3_config.Parse(xml_str.c_str()) != tinyxml2::XML_SUCCESS) {
|
||||||
// if we still failed, give up
|
// if we still failed, give up
|
||||||
log_warning("options", "unable to parse fixed xml");
|
log_warning("options", "unable to parse fixed xml");
|
||||||
return detect_gameversion_ident();
|
return detect_gameversion_ident(bootstrap_user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2549,7 +2824,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
|||||||
auto node_ext = node_soft->FirstChildElement("ext");
|
auto node_ext = node_soft->FirstChildElement("ext");
|
||||||
if (node_ext) {
|
if (node_ext) {
|
||||||
version.ext = node_ext->GetText();
|
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) {
|
if (version.ext.size() != 10 && bootstrap_ext.size() == 10) {
|
||||||
version.ext = bootstrap_ext;
|
version.ext = bootstrap_ext;
|
||||||
} else if (bootstrap_ext.size() == 10) {
|
} else if (bootstrap_ext.size() == 10) {
|
||||||
@@ -2582,5 +2857,5 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
|||||||
|
|
||||||
// error
|
// error
|
||||||
log_warning("options", "unable to find /ea3/soft/model in {}", ea3_path);
|
log_warning("options", "unable to find /ea3/soft/model in {}", ea3_path);
|
||||||
return detect_gameversion_ident();
|
return detect_gameversion_ident(bootstrap_user);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ namespace launcher {
|
|||||||
spice2x_SDVXSubRedraw,
|
spice2x_SDVXSubRedraw,
|
||||||
LoadDDRModule,
|
LoadDDRModule,
|
||||||
DDR43Mode,
|
DDR43Mode,
|
||||||
|
DDRSkipCodecRegisteration,
|
||||||
LoadPopnMusicModule,
|
LoadPopnMusicModule,
|
||||||
PopnMusicForceHDMode,
|
PopnMusicForceHDMode,
|
||||||
PopnMusicForceSDMode,
|
PopnMusicForceSDMode,
|
||||||
@@ -117,6 +118,7 @@ namespace launcher {
|
|||||||
LoadCCJModule,
|
LoadCCJModule,
|
||||||
LoadQKSModule,
|
LoadQKSModule,
|
||||||
LoadMFGModule,
|
LoadMFGModule,
|
||||||
|
LoadPCModule,
|
||||||
LoadMusecaModule,
|
LoadMusecaModule,
|
||||||
PathToModules,
|
PathToModules,
|
||||||
ScreenshotFolder,
|
ScreenshotFolder,
|
||||||
@@ -136,6 +138,8 @@ namespace launcher {
|
|||||||
APISerialBaud,
|
APISerialBaud,
|
||||||
APIPretty,
|
APIPretty,
|
||||||
APIDebugMode,
|
APIDebugMode,
|
||||||
|
APIScreenMirrorQuality,
|
||||||
|
APIScreenMirrorDivide,
|
||||||
EnableAllIOModules,
|
EnableAllIOModules,
|
||||||
EnableACIOModule,
|
EnableACIOModule,
|
||||||
EnableICCAModule,
|
EnableICCAModule,
|
||||||
@@ -184,6 +188,7 @@ namespace launcher {
|
|||||||
DebugCreateFile,
|
DebugCreateFile,
|
||||||
VerboseGraphicsLogging,
|
VerboseGraphicsLogging,
|
||||||
VerboseAVSLogging,
|
VerboseAVSLogging,
|
||||||
|
AllowEA3Verbose,
|
||||||
DisableColoredOutput,
|
DisableColoredOutput,
|
||||||
DisableACPHook,
|
DisableACPHook,
|
||||||
DisableSignalHandling,
|
DisableSignalHandling,
|
||||||
@@ -199,6 +204,9 @@ namespace launcher {
|
|||||||
MFGArgs,
|
MFGArgs,
|
||||||
MFGCabType,
|
MFGCabType,
|
||||||
MFGNoIO,
|
MFGNoIO,
|
||||||
|
PCArgs,
|
||||||
|
PCNoIO,
|
||||||
|
PCKnobMode,
|
||||||
spice2x_LightsOverallBrightness,
|
spice2x_LightsOverallBrightness,
|
||||||
spice2x_WindowBorder,
|
spice2x_WindowBorder,
|
||||||
spice2x_WindowSize,
|
spice2x_WindowSize,
|
||||||
@@ -207,6 +215,8 @@ namespace launcher {
|
|||||||
WindowForceScaling,
|
WindowForceScaling,
|
||||||
spice2x_IIDXWindowedSubscreenSize,
|
spice2x_IIDXWindowedSubscreenSize,
|
||||||
spice2x_IIDXWindowedSubscreenPosition,
|
spice2x_IIDXWindowedSubscreenPosition,
|
||||||
|
IIDXWindowedSubscreenBorderless,
|
||||||
|
IIDXWindowedSubscreenAlwaysOnTop,
|
||||||
spice2x_JubeatLegacyTouch,
|
spice2x_JubeatLegacyTouch,
|
||||||
spice2x_RBTouchScale,
|
spice2x_RBTouchScale,
|
||||||
spice2x_AsioForceUnload,
|
spice2x_AsioForceUnload,
|
||||||
@@ -229,8 +239,20 @@ namespace launcher {
|
|||||||
IIDXRecQuality,
|
IIDXRecQuality,
|
||||||
MidiAlgoVer,
|
MidiAlgoVer,
|
||||||
MidiNoteSustain,
|
MidiNoteSustain,
|
||||||
|
InputRequiresFocus,
|
||||||
NostalgiaPoke,
|
NostalgiaPoke,
|
||||||
ForceBackBufferCount,
|
ForceBackBufferCount,
|
||||||
|
SDVXWindowedSubscreenSize,
|
||||||
|
SDVXWindowedSubscreenPosition,
|
||||||
|
SDVXWindowedSubscreenBorderless,
|
||||||
|
SDVXWindowedSubscreenAlwaysOnTop,
|
||||||
|
LovePlusCamEnable,
|
||||||
|
LovePlusPrinterOutputPath,
|
||||||
|
LovePlusPrinterOutputClear,
|
||||||
|
LovePlusPrinterOutputOverwrite,
|
||||||
|
LovePlusPrinterOutputFormat,
|
||||||
|
LovePlusPrinterJPGQuality,
|
||||||
|
OptionConflictResolution,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class OptionsCategory {
|
enum class OptionsCategory {
|
||||||
@@ -242,6 +264,8 @@ namespace launcher {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern bool USE_CMD_OVERRIDE;
|
||||||
|
|
||||||
const std::vector<std::string> &get_categories(Options::OptionsCategory category);
|
const std::vector<std::string> &get_categories(Options::OptionsCategory category);
|
||||||
const std::vector<OptionDefinition> &get_option_definitions();
|
const std::vector<OptionDefinition> &get_option_definitions();
|
||||||
std::unique_ptr<std::vector<Option>> parse_options(int argc, char *argv[]);
|
std::unique_ptr<std::vector<Option>> parse_options(int argc, char *argv[]);
|
||||||
@@ -255,6 +279,6 @@ namespace launcher {
|
|||||||
std::string ext;
|
std::string ext;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string detect_bootstrap_release_code();
|
std::string detect_bootstrap_release_code(const std::string& bootstrap_user);
|
||||||
GameVersion detect_gameversion(const std::string& ea3_user);
|
GameVersion detect_gameversion(const std::string& ea3_user, const std::string& bootstrap_user);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ namespace richpresence {
|
|||||||
{"Busou Shinki: Armored Princess Battle Conductor", "1226739666741366916"},
|
{"Busou Shinki: Armored Princess Battle Conductor", "1226739666741366916"},
|
||||||
{"Chase Chase Jokers", "1226739863915593770"},
|
{"Chase Chase Jokers", "1226739863915593770"},
|
||||||
{"QuizKnock STADIUM", "1226739930328334478"},
|
{"QuizKnock STADIUM", "1226739930328334478"},
|
||||||
|
{"Mahjong Fight Girl", "1417371188342030468"},
|
||||||
|
{"Polaris Chord", "1417371592224407552"},
|
||||||
};
|
};
|
||||||
|
|
||||||
// state
|
// state
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "easrv/easrv.h"
|
#include "easrv/easrv.h"
|
||||||
#include "rawinput/rawinput.h"
|
#include "rawinput/rawinput.h"
|
||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
|
|
||||||
#include "launcher.h"
|
#include "launcher.h"
|
||||||
@@ -21,6 +22,9 @@ namespace launcher {
|
|||||||
// therefore, subsystems need to be guarded against multiple unload attempts
|
// therefore, subsystems need to be guarded against multiple unload attempts
|
||||||
log_info("launcher", "stopping subsystems");
|
log_info("launcher", "stopping subsystems");
|
||||||
|
|
||||||
|
// before shutting down logger, dump any deferred log messages
|
||||||
|
deferredlogs::dump_to_logger();
|
||||||
|
|
||||||
// flush/stop logger
|
// flush/stop logger
|
||||||
logger::stop();
|
logger::stop();
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
|
#include <future>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
|
#include "acio/acio.h"
|
||||||
#include "external/stackwalker/stackwalker.h"
|
#include "external/stackwalker/stackwalker.h"
|
||||||
#include "hooks/libraryhook.h"
|
#include "hooks/libraryhook.h"
|
||||||
#include "launcher/shutdown.h"
|
#include "launcher/shutdown.h"
|
||||||
|
#include "util/deferlog.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
@@ -97,6 +99,34 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
|
|||||||
// print signal
|
// print signal
|
||||||
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
|
log_warning("signal", "exception raised: {}", exception_code(ExceptionRecord));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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
|
// walk the exception chain
|
||||||
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
|
struct _EXCEPTION_RECORD *record_cause = ExceptionRecord->ExceptionRecord;
|
||||||
while (record_cause != nullptr) {
|
while (record_cause != nullptr) {
|
||||||
@@ -145,6 +175,9 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
|
|||||||
log_warning("signal", "minidump creation function not available, skipping");
|
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");
|
log_fatal("signal", "end");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace launcher::signal {
|
namespace launcher::signal {
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
extern bool DISABLE;
|
extern bool DISABLE;
|
||||||
extern bool USE_VEH_WORKAROUND;
|
extern bool USE_VEH_WORKAROUND;
|
||||||
|
|
||||||
//void print_stacktrace();
|
|
||||||
void attach();
|
void attach();
|
||||||
void init();
|
void init();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -659,6 +659,8 @@ void eamuse_autodetect_game() {
|
|||||||
eamuse_set_game("QuizKnock STADIUM");
|
eamuse_set_game("QuizKnock STADIUM");
|
||||||
else if (avs::game::is_model("VFG"))
|
else if (avs::game::is_model("VFG"))
|
||||||
eamuse_set_game("Mahjong Fight Girl");
|
eamuse_set_game("Mahjong Fight Girl");
|
||||||
|
else if (avs::game::is_model("XIF"))
|
||||||
|
eamuse_set_game("Polaris Chord");
|
||||||
else {
|
else {
|
||||||
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
||||||
eamuse_set_game("unknown");
|
eamuse_set_game("unknown");
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ static void __cdecl cardunit_update() {
|
|||||||
bool kb_insert_press = false;
|
bool kb_insert_press = false;
|
||||||
|
|
||||||
// eamio keypress
|
// 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
|
// update card inserts
|
||||||
if (eamuse_card_insert_consume((int) EXTDEV_CARDUNIT_COUNT, unit) ||
|
if (eamuse_card_insert_consume((int) EXTDEV_CARDUNIT_COUNT, unit) ||
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "touch/touch.h"
|
#include "touch/touch.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
|
||||||
#if !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) || \
|
#if !defined(IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS) || \
|
||||||
!defined(IMGUI_DISABLE_DEFAULT_ALLOCATORS) || \
|
!defined(IMGUI_DISABLE_DEFAULT_ALLOCATORS) || \
|
||||||
@@ -175,10 +176,22 @@ static void ImGui_ImplSpice_UpdateMousePos() {
|
|||||||
static_cast<int>(pos.y / io.DisplaySize.y * window_size.y));
|
static_cast<int>(pos.y / io.DisplaySize.y * window_size.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto active_window = ::GetForegroundWindow();
|
||||||
|
|
||||||
|
// if the main focus is a windowed subscreen, put the imgui cursor in a place that won't
|
||||||
|
// trigger any overlay, don't process anything else
|
||||||
|
const auto is_windowed_subscreen =
|
||||||
|
(GRAPHICS_IIDX_WSUB && active_window == TDJ_SUBSCREEN_WINDOW) ||
|
||||||
|
(active_window == SDVX_SUBSCREEN_WINDOW);
|
||||||
|
if (is_windowed_subscreen) {
|
||||||
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// set mouse position
|
// set mouse position
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
POINT pos;
|
POINT pos;
|
||||||
if (HWND active_window = ::GetForegroundWindow()) {
|
if (active_window) {
|
||||||
if (active_window == g_hWnd
|
if (active_window == g_hWnd
|
||||||
|| ::IsChild(active_window, g_hWnd)
|
|| ::IsChild(active_window, g_hWnd)
|
||||||
|| ::IsChild(g_hWnd, active_window)
|
|| ::IsChild(g_hWnd, active_window)
|
||||||
@@ -208,7 +221,7 @@ static void ImGui_ImplSpice_UpdateMousePos() {
|
|||||||
static size_t delay_touch = 0;
|
static size_t delay_touch = 0;
|
||||||
static size_t delay_touch_target = 2;
|
static size_t delay_touch_target = 2;
|
||||||
static DWORD last_touch_id = ~0u;
|
static DWORD last_touch_id = ~0u;
|
||||||
if (!touch_points.empty()) {
|
if (!touch_points.empty() && !is_windowed_subscreen) {
|
||||||
|
|
||||||
// use the first touch point
|
// use the first touch point
|
||||||
auto &tp = touch_points[0];
|
auto &tp = touch_points[0];
|
||||||
|
|||||||
@@ -174,18 +174,18 @@ void overlay::SpiceOverlay::init() {
|
|||||||
// https://github.com/ocornut/imgui/issues/707#issuecomment-760220280
|
// https://github.com/ocornut/imgui/issues/707#issuecomment-760220280
|
||||||
// r, g, b, a
|
// r, g, b, a
|
||||||
ImVec4* colors = ImGui::GetStyle().Colors;
|
ImVec4* colors = ImGui::GetStyle().Colors;
|
||||||
// colors[ImGuiCol_Text] = ImVec4(0.75f, 0.75f, 0.75f, 1.00f);
|
|
||||||
// colors[ImGuiCol_TextDisabled] = ImVec4(0.35f, 0.35f, 0.35f, 1.00f);
|
|
||||||
|
|
||||||
// colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.94f);
|
// note: also see bg_alpha value in each overlay window
|
||||||
// colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 1.0f);
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.f, 0.f, 0.94f);
|
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 1.0f);
|
||||||
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
|
colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
colors[ImGuiCol_FrameBg] = ImVec4(0.37f, 0.14f, 0.00f, 0.54f);
|
|
||||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.37f, 0.14f, 0.14f, 0.67f);
|
colors[ImGuiCol_FrameBg] = ImVec4(0.18f, 0.18f, 0.18f, 0.54f);
|
||||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.39f, 0.20f, 0.20f, 0.67f);
|
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.18f, 0.18f, 0.18f, 0.80f);
|
||||||
|
colors[ImGuiCol_FrameBgActive] = ImVec4(0.24f, 0.24f, 0.24f, 0.80f);
|
||||||
|
|
||||||
colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
|
colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
|
||||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
colors[ImGuiCol_TitleBgActive] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
||||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.48f, 0.16f, 0.16f, 1.00f);
|
||||||
@@ -194,16 +194,16 @@ void overlay::SpiceOverlay::init() {
|
|||||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
||||||
colors[ImGuiCol_CheckMark] = ImVec4(0.56f, 0.10f, 0.10f, 1.00f);
|
colors[ImGuiCol_CheckMark] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
||||||
colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
||||||
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
||||||
|
|
||||||
colors[ImGuiCol_Button] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
colors[ImGuiCol_Button] = ImVec4(1.00f, 0.19f, 0.19f, 0.40f);
|
||||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.80f, 0.17f, 0.00f, 1.00f);
|
colors[ImGuiCol_ButtonHovered] = ImVec4(0.80f, 0.17f, 0.00f, 1.00f);
|
||||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.89f, 0.00f, 0.19f, 1.00f);
|
colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.17f, 0.00f, 0.90f);
|
||||||
|
|
||||||
colors[ImGuiCol_Header] = ImVec4(0.33f, 0.35f, 0.36f, 0.53f);
|
colors[ImGuiCol_Header] = ImVec4(0.33f, 0.35f, 0.36f, 0.53f);
|
||||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.76f, 0.28f, 0.44f, 0.67f);
|
colors[ImGuiCol_HeaderHovered] = ImVec4(0.44f, 0.44f, 0.44f, 0.67f);
|
||||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.47f, 0.47f, 0.67f);
|
colors[ImGuiCol_HeaderActive] = ImVec4(0.47f, 0.47f, 0.47f, 0.67f);
|
||||||
colors[ImGuiCol_Separator] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
colors[ImGuiCol_Separator] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
||||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f);
|
||||||
@@ -228,7 +228,7 @@ void overlay::SpiceOverlay::init() {
|
|||||||
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
||||||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
||||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
||||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.04f);
|
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.02f);
|
||||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
||||||
@@ -270,13 +270,14 @@ void overlay::SpiceOverlay::init() {
|
|||||||
ImFontConfig config {};
|
ImFontConfig config {};
|
||||||
config.MergeMode = true;
|
config.MergeMode = true;
|
||||||
|
|
||||||
|
log_misc("overlay", "loading fonts, failures are not fatal");
|
||||||
add_font("simsun.ttc", &config, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
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("meiryu.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
||||||
add_font("meiryo.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
add_font("meiryo.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
||||||
add_font("gulim.ttc", &config, io.Fonts->GetGlyphRangesKorean());
|
add_font("gulim.ttc", &config, io.Fonts->GetGlyphRangesKorean());
|
||||||
add_font("cordia.ttc", &config, io.Fonts->GetGlyphRangesThai());
|
add_font("cordia.ttf", &config, io.Fonts->GetGlyphRangesThai());
|
||||||
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesVietnamese());
|
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesVietnamese());
|
||||||
|
|
||||||
// add special font
|
// add special font
|
||||||
if (avs::game::is_model("LDJ")) {
|
if (avs::game::is_model("LDJ")) {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace overlay {
|
|||||||
ImVec2 init_size = ImVec2(0, 0);
|
ImVec2 init_size = ImVec2(0, 0);
|
||||||
ImVec2 size_min = ImVec2(0, 0);
|
ImVec2 size_min = ImVec2(0, 0);
|
||||||
ImVec2 size_max = ImVec2(-1, -1);
|
ImVec2 size_max = ImVec2(-1, -1);
|
||||||
float bg_alpha = 0.8f;
|
float bg_alpha = 0.96f;
|
||||||
|
|
||||||
Window(SpiceOverlay *overlay);
|
Window(SpiceOverlay *overlay);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,8 +29,11 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->toggle_button = games::OverlayButtons::ToggleCardManager;
|
this->toggle_button = games::OverlayButtons::ToggleCardManager;
|
||||||
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_card_manager.json";
|
|
||||||
if (fileutils::file_exists(this->config_path)) {
|
bool file_exists = false;
|
||||||
|
this->config_path =
|
||||||
|
fileutils::get_config_file_path("cardmanager", "spicetools_card_manager.json", &file_exists);
|
||||||
|
if (file_exists) {
|
||||||
this->config_load();
|
this->config_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,8 +437,6 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::config_load() {
|
void CardManager::config_load() {
|
||||||
log_info("cardmanager", "loading config");
|
|
||||||
|
|
||||||
// clear cards
|
// clear cards
|
||||||
this->cards.clear();
|
this->cards.clear();
|
||||||
|
|
||||||
@@ -566,10 +567,10 @@ namespace overlay::windows {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(this->config_path, buffer.GetString())) {
|
if (fileutils::write_config_file("cardmanager", this->config_path, buffer.GetString())) {
|
||||||
this->config_dirty = false;
|
this->config_dirty = false;
|
||||||
} else {
|
} else {
|
||||||
log_warning("cardmanager", "unable to save config file to {}", this->config_path.string());
|
log_warning("cardmanager", "unable to save config file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "avs/ea3.h"
|
#include "avs/ea3.h"
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "launcher/shutdown.h"
|
|
||||||
#include "launcher/options.h"
|
#include "launcher/options.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
#include "overlay/imgui/extensions.h"
|
#include "overlay/imgui/extensions.h"
|
||||||
@@ -557,9 +556,16 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// disclaimer
|
// disclaimer
|
||||||
|
// note: distribution of modified version of this software without providing source is GPLv3 license violation.
|
||||||
ImGui::TextColored(
|
ImGui::TextColored(
|
||||||
ImVec4(1, 0.5f, 0.5f, 1.f),
|
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) {
|
void Config::build_buttons(const std::string &name, std::vector<Button> *buttons, int min, int max) {
|
||||||
@@ -2634,11 +2640,11 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
// check hidden option
|
// check hidden option
|
||||||
if (!this->options_show_hidden && option.value.empty()) {
|
if (!this->options_show_hidden && option.value.empty()) {
|
||||||
|
|
||||||
// skip hidden entries
|
// skip hidden entries
|
||||||
if (definition.hidden) {
|
if (definition.hidden) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check for game exclusivity
|
// check for game exclusivity
|
||||||
if (!definition.game_name.empty()) {
|
if (!definition.game_name.empty()) {
|
||||||
@@ -2646,7 +2652,6 @@ namespace overlay::windows {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// filter
|
// filter
|
||||||
if (filter != nullptr) {
|
if (filter != nullptr) {
|
||||||
@@ -2906,26 +2911,28 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Config::build_about() {
|
void Config::build_about() {
|
||||||
|
#ifndef SPICE_LINUX
|
||||||
ImGui::TextUnformatted(std::string(
|
ImGui::TextUnformatted(std::string(
|
||||||
"spice2x (a fork of SpiceTools)\r\n"
|
"spice2x (a fork of SpiceTools)\r\n"
|
||||||
"=========================\r\n" +
|
"=========================\r\n" +
|
||||||
to_string(VERSION_STRING)).c_str());
|
to_string(VERSION_STRING)).c_str());
|
||||||
|
#else
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
|
|
||||||
if (ImGui::Button(PROJECT_URL)) {
|
|
||||||
launch_shell(PROJECT_URL, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
ImGui::TextUnformatted(std::string(
|
ImGui::TextUnformatted(std::string(
|
||||||
resutil::load_file_string_crlf(IDR_README) +
|
"spice2x (a fork of SpiceTools) for Linux\r\n"
|
||||||
"\r\n" +
|
"=========================\r\n" +
|
||||||
"Changelog (Highlights):\r\n" +
|
to_string(VERSION_STRING)).c_str());
|
||||||
resutil::load_file_string_crlf(IDR_CHANGELOG)).c_str());
|
#endif
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("");
|
||||||
|
if (ImGui::TextLink(PROJECT_URL)) {
|
||||||
|
launch_shell(PROJECT_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::build_licenses() {
|
ImGui::TextUnformatted("");
|
||||||
|
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());
|
ImGui::TextUnformatted(resutil::load_file_string_crlf(IDR_LICENSES).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2978,32 +2985,26 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
void Config::build_menu(int *game_selected) {
|
void Config::build_menu(int *game_selected) {
|
||||||
bool about_popup = false;
|
bool about_popup = false;
|
||||||
bool licenses_popup = false;
|
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.14f, 0.14f, 0.14f, 1.0f));
|
||||||
bool shutdown_popup = false;
|
|
||||||
if (ImGui::BeginMenuBar()) {
|
if (ImGui::BeginMenuBar()) {
|
||||||
|
|
||||||
// [spice2x]
|
// [spice2x]
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImVec4(1.f, 0.f, 0.f, 1.f));
|
if (ImGui::BeginMenu("[spice2x]")) {
|
||||||
ImGui::BeginDisabled(!cfg::CONFIGURATOR_STANDALONE);
|
ImGui::PopStyleColor();
|
||||||
if (ImGui::MenuItem("[spice2x]")) {
|
if (ImGui::MenuItem("spice2x.github.io")) {
|
||||||
launch_shell(PROJECT_URL, nullptr);
|
launch_shell(PROJECT_URL);
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
if (ImGui::MenuItem("About")) {
|
||||||
|
about_popup = true;
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
} else {
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::PopStyleColor();
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// game selector
|
|
||||||
ImGui::PushItemWidth(MIN(580, MAX(80, ImGui::GetWindowSize().x - 520)));
|
|
||||||
ImGui::Combo("##game_selector", game_selected, games_names.data(), (int)games_list.size());
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// shortcuts
|
// shortcuts
|
||||||
if (ImGui::BeginMenu("Shortcuts", cfg::CONFIGURATOR_STANDALONE)) {
|
if (ImGui::BeginMenu("Shortcuts")) {
|
||||||
if (ImGui::MenuItem("USB Game Controllers")) {
|
if (ImGui::MenuItem("USB Game Controllers")) {
|
||||||
launch_shell("control.exe", "joy.cpl");
|
launch_shell("control.exe", "joy.cpl");
|
||||||
}
|
}
|
||||||
@@ -3016,32 +3017,25 @@ namespace overlay::windows {
|
|||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
// popup menus
|
// help
|
||||||
if (ImGui::MenuItem("Licenses")) {
|
if (ImGui::BeginMenu("Help")) {
|
||||||
licenses_popup = true;
|
if (ImGui::MenuItem("FAQ")) {
|
||||||
|
launch_shell("https://github.com/spice2x/spice2x.github.io/wiki/Known-issues");
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("About")) {
|
if (ImGui::MenuItem("Wiki")) {
|
||||||
about_popup = true;
|
launch_shell("https://github.com/spice2x/spice2x.github.io/wiki");
|
||||||
}
|
|
||||||
|
|
||||||
// power - only active in games
|
|
||||||
if (ImGui::BeginMenu("Power", !cfg::CONFIGURATOR_STANDALONE)) {
|
|
||||||
if (ImGui::MenuItem("Restart Game")) {
|
|
||||||
launcher::restart();
|
|
||||||
}
|
|
||||||
if (ImGui::MenuItem("Exit Game")) {
|
|
||||||
launcher::shutdown();
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::MenuItem("Shutdown PC")) {
|
|
||||||
shutdown_popup = true;
|
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
// game selector
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.34f, 0.14f, 0.14f, 0.54f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.34f, 0.14f, 0.14f, 0.54f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.34f, 0.14f, 0.14f, 0.64f));
|
||||||
|
ImGui::PushItemWidth(MIN(700, MAX(100, ImGui::GetWindowSize().x - 400)));
|
||||||
|
ImGui::Combo("##game_selector", game_selected, games_names.data(), (int)games_list.size());
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
if (!avs::game::is_model("000")) {
|
if (!avs::game::is_model("000")) {
|
||||||
@@ -3052,52 +3046,15 @@ namespace overlay::windows {
|
|||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(); // ImGuiCol_PopupBg
|
||||||
|
|
||||||
// workaround for popups triggered by menu, see https://github.com/ocornut/imgui/issues/331
|
// workaround for popups triggered by menu, see https://github.com/ocornut/imgui/issues/331
|
||||||
if (about_popup) {
|
if (about_popup) {
|
||||||
ImGui::OpenPopup("About##topbarpopup");
|
ImGui::OpenPopup("About##topbarpopup");
|
||||||
}
|
}
|
||||||
if (licenses_popup) {
|
|
||||||
ImGui::OpenPopup("Licenses##topbarpopup");
|
|
||||||
}
|
|
||||||
if (shutdown_popup) {
|
|
||||||
ImGui::OpenPopup("System##topbarpopup");
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw popups
|
// draw popups
|
||||||
{
|
{
|
||||||
// unused_open is needed for close button to appear on the popup
|
|
||||||
bool unused_open = true;
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupModal(
|
|
||||||
"System##topbarpopup",
|
|
||||||
&unused_open,
|
|
||||||
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize)) {
|
|
||||||
|
|
||||||
static bool force_shutdown = false;
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Checkbox("Force", &force_shutdown);
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
const ImVec2 button_size(100.f, 0.f);
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::Button("Shutdown PC", button_size)) {
|
|
||||||
this->shutdown_system(force_shutdown, false);
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::Button("Reboot PC", button_size)) {
|
|
||||||
this->shutdown_system(force_shutdown, true);
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Spacing();
|
|
||||||
if (ImGui::Button("Cancel", button_size)) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
const ImVec2 popup_size(
|
const ImVec2 popup_size(
|
||||||
std::min(ImGui::GetIO().DisplaySize.x * 0.9f, 800.f),
|
std::min(ImGui::GetIO().DisplaySize.x * 0.9f, 800.f),
|
||||||
std::min(ImGui::GetIO().DisplaySize.y * 0.9f, 800.f));
|
std::min(ImGui::GetIO().DisplaySize.y * 0.9f, 800.f));
|
||||||
@@ -3113,32 +3070,6 @@ namespace overlay::windows {
|
|||||||
this->build_about();
|
this->build_about();
|
||||||
ImGui::EndPopup();
|
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::shutdown_system(bool force, bool reboot_instead) {
|
|
||||||
if (!acquire_shutdown_privs()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UINT flags = 0;
|
|
||||||
if (force) {
|
|
||||||
flags |= EWX_FORCE;
|
|
||||||
}
|
|
||||||
if (reboot_instead) {
|
|
||||||
flags |= EWX_REBOOT;
|
|
||||||
} else {
|
|
||||||
flags |= EWX_SHUTDOWN | EWX_HYBRID_SHUTDOWN;
|
|
||||||
}
|
|
||||||
if (!ExitWindowsEx(flags, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
launcher::shutdown(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -93,9 +93,8 @@ namespace overlay::windows {
|
|||||||
void build_options(
|
void build_options(
|
||||||
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr);
|
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr);
|
||||||
void build_about();
|
void build_about();
|
||||||
void build_licenses();
|
|
||||||
void build_launcher();
|
void build_launcher();
|
||||||
void launch_shell(LPCSTR app, LPCSTR file);
|
void launch_shell(LPCSTR app, LPCSTR file=nullptr);
|
||||||
|
|
||||||
static void build_page_selector(int *page);
|
static void build_page_selector(int *page);
|
||||||
void build_menu(int *game_selected);
|
void build_menu(int *game_selected);
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ namespace overlay::windows {
|
|||||||
raw_input_view();
|
raw_input_view();
|
||||||
touch_view();
|
touch_view();
|
||||||
lcd_view();
|
lcd_view();
|
||||||
about_view();
|
|
||||||
ddr_timing_view();
|
ddr_timing_view();
|
||||||
iidx_effectors_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() {
|
void Control::ddr_timing_view() {
|
||||||
if (avs::game::is_model("MDX") && ImGui::CollapsingHeader("DDR Timing")) {
|
if (avs::game::is_model("MDX") && ImGui::CollapsingHeader("DDR Timing")) {
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace overlay::windows {
|
|||||||
| ImGuiWindowFlags_NoNavFocus
|
| ImGuiWindowFlags_NoNavFocus
|
||||||
| ImGuiWindowFlags_NoNavInputs
|
| ImGuiWindowFlags_NoNavInputs
|
||||||
| ImGuiWindowFlags_NoDocking;
|
| ImGuiWindowFlags_NoDocking;
|
||||||
this->bg_alpha = 0.4f;
|
this->bg_alpha = 0.5f;
|
||||||
this->start_time = std::chrono::system_clock::now();
|
this->start_time = std::chrono::system_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "avs/game.h"
|
||||||
#include "games/io.h"
|
#include "games/io.h"
|
||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
#include "hooks/graphics/backends/d3d9/d3d9_backend.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::touch_transform(const ImVec2 xy_in, LONG *x_out, LONG *y_out) {}
|
||||||
|
|
||||||
void GenericSubScreen::build_content() {
|
void GenericSubScreen::build_content() {
|
||||||
|
this->flags |= ImGuiWindowFlags_NoBackground;
|
||||||
|
|
||||||
if (this->disabled_message.has_value()) {
|
if (this->disabled_message.has_value()) {
|
||||||
this->flags &= ~ImGuiWindowFlags_NoBackground;
|
this->flags &= ~ImGuiWindowFlags_NoBackground;
|
||||||
ImGui::TextColored(YELLOW, "%s", this->disabled_message.value().c_str());
|
ImGui::TextColored(YELLOW, "%s", this->disabled_message.value().c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->draw_texture();
|
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 OVERLAYDBG
|
||||||
if (this->status_message.has_value()) {
|
if (this->status_message.has_value()) {
|
||||||
log_warning("sub::overlay", "{}", this->status_message.value().c_str());
|
log_warning("sub::overlay", "{}", this->status_message.value().c_str());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace overlay::windows {
|
|||||||
if (GRAPHICS_IIDX_WSUB) {
|
if (GRAPHICS_IIDX_WSUB) {
|
||||||
this->disabled_message =
|
this->disabled_message =
|
||||||
"Close this overlay and use the second window.\n"
|
"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;
|
this->draws_window = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ namespace overlay::windows {
|
|||||||
{"arkmmd.dll", {"gamemmd.dll"}},
|
{"arkmmd.dll", {"gamemmd.dll"}},
|
||||||
{"arkklp.dll", {"lpac.dll"}},
|
{"arkklp.dll", {"lpac.dll"}},
|
||||||
{"arknck.dll", {"weac.dll"}},
|
{"arknck.dll", {"weac.dll"}},
|
||||||
{"gdxg.dll", {"game.dll"}}
|
{"gdxg.dll", {"game.dll", "libshare-pj.dll", "boot.dll"}}
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t url_recent_idx = -1;
|
static size_t url_recent_idx = -1;
|
||||||
@@ -219,7 +219,8 @@ namespace overlay::windows {
|
|||||||
this->config_path = PATCH_MANAGER_CFG_PATH_OVERRIDE.value();
|
this->config_path = PATCH_MANAGER_CFG_PATH_OVERRIDE.value();
|
||||||
log_info("patchmanager", "using custom config file path: {}", this->config_path.string().c_str());
|
log_info("patchmanager", "using custom config file path: {}", this->config_path.string().c_str());
|
||||||
} else {
|
} else {
|
||||||
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_patch_manager.json";
|
this->config_path =
|
||||||
|
fileutils::get_config_file_path("patchmanager", "spicetools_patch_manager.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ldr_registered) {
|
if (!ldr_registered) {
|
||||||
@@ -229,7 +230,13 @@ namespace overlay::windows {
|
|||||||
auto const register_fn = reinterpret_cast<decltype(&LdrRegisterDllNotification)>
|
auto const register_fn = reinterpret_cast<decltype(&LdrRegisterDllNotification)>
|
||||||
(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "LdrRegisterDllNotification"));
|
(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "LdrRegisterDllNotification"));
|
||||||
|
|
||||||
auto callback = [] CALLBACK (ULONG reason, PCLDR_DLL_NOTIFICATION_DATA data, PVOID ctx) {
|
auto callback =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
static_cast<PLDR_DLL_NOTIFICATION_FUNCTION>([]
|
||||||
|
#else
|
||||||
|
[] CALLBACK
|
||||||
|
#endif
|
||||||
|
(ULONG reason, PCLDR_DLL_NOTIFICATION_DATA data, PVOID ctx) {
|
||||||
if (reason == LDR_DLL_NOTIFICATION_REASON_LOADED) {
|
if (reason == LDR_DLL_NOTIFICATION_REASON_LOADED) {
|
||||||
auto const dll = strtolower(std::filesystem::path({
|
auto const dll = strtolower(std::filesystem::path({
|
||||||
data->Loaded.FullDllName->Buffer,
|
data->Loaded.FullDllName->Buffer,
|
||||||
@@ -240,7 +247,11 @@ namespace overlay::windows {
|
|||||||
static_cast<PatchManager*>(ctx)->reload_local_patches(true);
|
static_cast<PatchManager*>(ctx)->reload_local_patches(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
if (register_fn && NT_SUCCESS(register_fn(0, callback, this, &ldr_notify_cookie))) {
|
if (register_fn && NT_SUCCESS(register_fn(0, callback, this, &ldr_notify_cookie))) {
|
||||||
log_info("patchmanager", "registered for DLL load notifications");
|
log_info("patchmanager", "registered for DLL load notifications");
|
||||||
@@ -1127,7 +1138,7 @@ namespace overlay::windows {
|
|||||||
doc.Accept(writer);
|
doc.Accept(writer);
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
if (fileutils::text_write(config_path, buffer.GetString())) {
|
if (fileutils::write_config_file("patchmanager", config_path, buffer.GetString())) {
|
||||||
config_dirty = false;
|
config_dirty = false;
|
||||||
} else {
|
} else {
|
||||||
log_warning("patchmanager", "unable to save config file");
|
log_warning("patchmanager", "unable to save config file");
|
||||||
@@ -1644,6 +1655,8 @@ namespace overlay::windows {
|
|||||||
std::string first_id = get_game_identifier(MODULE_PATH / firstDll);
|
std::string first_id = get_game_identifier(MODULE_PATH / firstDll);
|
||||||
std::filesystem::path firstPath = fmt::format("patches/{}.json", first_id);
|
std::filesystem::path firstPath = fmt::format("patches/{}.json", first_id);
|
||||||
|
|
||||||
|
log_misc("patchmanager", "patch identifier of {}: {}", firstDll, first_id);
|
||||||
|
|
||||||
auto extraDlls = getExtraDlls(firstDll);
|
auto extraDlls = getExtraDlls(firstDll);
|
||||||
std::erase_if(extraDlls, [](const std::string& dll) {
|
std::erase_if(extraDlls, [](const std::string& dll) {
|
||||||
auto identifier = get_game_identifier(MODULE_PATH / dll);
|
auto identifier = get_game_identifier(MODULE_PATH / dll);
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ namespace overlay::windows {
|
|||||||
scene.offset_y = 0;
|
scene.offset_y = 0;
|
||||||
scene.scale_x = 1.f;
|
scene.scale_x = 1.f;
|
||||||
scene.scale_y = 1.f;
|
scene.scale_y = 1.f;
|
||||||
|
scene.duplicate = cfg::ScreenDuplicateMode::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg::SCREENRESIZE->enable_window_resize = false;
|
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.");
|
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();
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,8 +185,8 @@ namespace overlay::windows {
|
|||||||
"Change window decoration. Resizable Window may not cause your mouse cursor to change, "
|
"Change window decoration. Resizable Window may not cause your mouse cursor to change, "
|
||||||
"but you can still drag to resize. Disabled for some games due to incompatibility.");
|
"but you can still drag to resize. Disabled for some games due to incompatibility.");
|
||||||
|
|
||||||
if (ImGui::Checkbox("Always on Top", &cfg::SCREENRESIZE->window_always_on_top) ) {
|
if (ImGui::Checkbox("Always On Top", &cfg::SCREENRESIZE->window_always_on_top) ) {
|
||||||
graphics_update_z_order(window);
|
graphics_update_z_order(window, cfg::SCREENRESIZE->window_always_on_top);
|
||||||
}
|
}
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
ImGui::Checkbox("Forced Render Scaling", &GRAPHICS_WINDOW_BACKBUFFER_SCALE);
|
ImGui::Checkbox("Forced Render Scaling", &GRAPHICS_WINDOW_BACKBUFFER_SCALE);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ namespace rawinput {
|
|||||||
int TOUCHSCREEN_RANGE_X = 0;
|
int TOUCHSCREEN_RANGE_X = 0;
|
||||||
int TOUCHSCREEN_RANGE_Y = 0;
|
int TOUCHSCREEN_RANGE_Y = 0;
|
||||||
bool DUMP_HID_DEVICES_TO_LOG = false;
|
bool DUMP_HID_DEVICES_TO_LOG = false;
|
||||||
|
bool NAIVE_REQUIRE_FOCUS = true;
|
||||||
|
bool RAWINPUT_REQUIRE_FOCUS = false;
|
||||||
|
|
||||||
// set this to something slightly longer than 16.67ms (60Hz) so that I/O can pick it up
|
// set this to something slightly longer than 16.67ms (60Hz) so that I/O can pick it up
|
||||||
// this may need to be adjusted for each game in the future if there is a game that polls less
|
// this may need to be adjusted for each game in the future if there is a game that polls less
|
||||||
@@ -494,7 +496,7 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
|||||||
// get string index
|
// get string index
|
||||||
ULONG string_index = 0;
|
ULONG string_index = 0;
|
||||||
if (button_caps.IsStringRange && button_caps.Range.StringMin != 0) {
|
if (button_caps.IsStringRange && button_caps.Range.StringMin != 0) {
|
||||||
string_index = button_caps.Range.StringMin + static_cast<ULONG>(button_output_caps_list.size()) - 1;
|
string_index = button_caps.Range.StringMin + static_cast<ULONG>(button_output_caps_names.size());
|
||||||
}
|
}
|
||||||
else if (!button_caps.IsStringRange && button_caps.NotRange.StringIndex != 0) {
|
else if (!button_caps.IsStringRange && button_caps.NotRange.StringIndex != 0) {
|
||||||
string_index = button_caps.NotRange.StringIndex;
|
string_index = button_caps.NotRange.StringIndex;
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ namespace rawinput {
|
|||||||
|
|
||||||
extern uint32_t MIDI_NOTE_SUSTAIN;
|
extern uint32_t MIDI_NOTE_SUSTAIN;
|
||||||
|
|
||||||
|
extern bool NAIVE_REQUIRE_FOCUS;
|
||||||
|
extern bool RAWINPUT_REQUIRE_FOCUS;
|
||||||
|
|
||||||
struct DeviceCallback {
|
struct DeviceCallback {
|
||||||
void *data;
|
void *data;
|
||||||
std::function<void(void*, Device*)> f;
|
std::function<void(void*, Device*)> f;
|
||||||
@@ -51,7 +54,6 @@ namespace rawinput {
|
|||||||
|
|
||||||
HotplugManager *hotplug;
|
HotplugManager *hotplug;
|
||||||
std::vector<Device> devices;
|
std::vector<Device> devices;
|
||||||
HWND input_hwnd = nullptr;
|
|
||||||
WNDCLASSEX input_hwnd_class {};
|
WNDCLASSEX input_hwnd_class {};
|
||||||
std::thread *input_thread = nullptr;
|
std::thread *input_thread = nullptr;
|
||||||
std::thread *flush_thread = nullptr;
|
std::thread *flush_thread = nullptr;
|
||||||
@@ -88,6 +90,8 @@ namespace rawinput {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
HWND input_hwnd = nullptr;
|
||||||
|
|
||||||
RawInputManager();
|
RawInputManager();
|
||||||
~RawInputManager();
|
~RawInputManager();
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user