mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 61c97ccaab | |||
| 12d6a88c60 | |||
| 984b41a1ae | |||
| d06b8bd731 | |||
| 0dad96b876 | |||
| def296095b | |||
| 750b1fea80 | |||
| 4c87078807 | |||
| 052698afa3 | |||
| 9e2b04d5db | |||
| 5641e06a19 | |||
| 88ec6dbcee | |||
| 1b614c94a7 | |||
| 37c5913f69 | |||
| 2eca668593 | |||
| aec1da9d16 | |||
| 548b441f1f | |||
| 98bc285d98 | |||
| 553c180bee | |||
| 537252440e | |||
| 13a0877d38 | |||
| 50691b79f1 | |||
| ad229dabdb | |||
| bdff33a420 | |||
| 4b21821aa4 | |||
| 6b47b5db50 | |||
| a10ca5236b | |||
| be2dab9a1a | |||
| 02711cdee1 |
@@ -357,12 +357,12 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
||||
external/cardio/cardio_runner.cpp
|
||||
|
||||
# external misc
|
||||
external/scard/scard.cpp
|
||||
external/stackwalker/stackwalker.cpp
|
||||
external/tinyxml2/tinyxml2.cpp
|
||||
external/http-parser/http_parser.c
|
||||
external/usbhidusage/usb-hid-usage.c
|
||||
external/toojpeg/toojpeg.cpp
|
||||
external/scard/scard.cpp
|
||||
|
||||
# games
|
||||
games/game.cpp
|
||||
@@ -622,8 +622,9 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Source Files" FILES ${SOUR
|
||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
||||
add_executable(spicetools_spice ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
target_link_libraries(spicetools_spice
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
target_link_libraries(spicetools_spice PUBLIC winscard)
|
||||
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_spice PROPERTIES OUTPUT_NAME "spice")
|
||||
|
||||
@@ -637,8 +638,9 @@ endif()
|
||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
||||
add_executable(spicetools_spice_laa ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
target_link_libraries(spicetools_spice_laa
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
target_link_libraries(spicetools_spice_laa PUBLIC winscard)
|
||||
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_spice_laa PROPERTIES OUTPUT_NAME "spice_laa")
|
||||
target_compile_definitions(spicetools_spice_laa PRIVATE SPICE32_LARGE_ADDRESS_AWARE=1)
|
||||
@@ -647,6 +649,22 @@ IF(NOT MSVC)
|
||||
set_target_properties(spicetools_spice_laa PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32 -Wl,--large-address-aware")
|
||||
endif()
|
||||
|
||||
# spice_linux.exe
|
||||
###########
|
||||
|
||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
||||
add_executable(spicetools_spice_linux ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
target_link_libraries(spicetools_spice_linux
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
set_target_properties(spicetools_spice_linux PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_spice_linux PROPERTIES OUTPUT_NAME "spice_linux")
|
||||
target_compile_definitions(spicetools_spice_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
||||
|
||||
IF(NOT MSVC)
|
||||
set_target_properties(spicetools_spice_linux PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||
endif()
|
||||
|
||||
# spice64.exe
|
||||
#############
|
||||
|
||||
@@ -655,9 +673,9 @@ add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
|
||||
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
||||
target_link_libraries(spicetools_spice64
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp mfuuid strmiids dxva2
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
|
||||
target_link_libraries(spicetools_spice64 PUBLIC winscard)
|
||||
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
||||
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
||||
@@ -666,6 +684,25 @@ IF(NOT MSVC)
|
||||
set_target_properties(spicetools_spice64 PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||
endif()
|
||||
|
||||
# spice64_linux.exe
|
||||
#############
|
||||
|
||||
set(RESOURCE_FILES build/manifest.manifest build/manifest64.rc build/icon.rc cfg/Win32D.rc)
|
||||
add_executable(spicetools_spice64_linux ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
|
||||
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
||||
target_link_libraries(spicetools_spice64_linux
|
||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
set_target_properties(spicetools_spice64_linux PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_spice64_linux PROPERTIES OUTPUT_NAME "spice64_linux")
|
||||
target_compile_definitions(spicetools_spice64_linux PRIVATE SPICE64=1)
|
||||
target_compile_definitions(spicetools_spice64_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
||||
|
||||
IF(NOT MSVC)
|
||||
set_target_properties(spicetools_spice64_linux PROPERTIES COMPILE_FLAGS "-m64" LINK_FLAGS "-m64")
|
||||
endif()
|
||||
|
||||
# spicecfg.exe
|
||||
##############
|
||||
|
||||
@@ -673,8 +710,9 @@ set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
|
||||
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
||||
add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
target_link_libraries(spicetools_cfg
|
||||
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winscard winhttp strmiids
|
||||
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
target_link_libraries(spicetools_cfg PUBLIC winscard)
|
||||
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
||||
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
||||
@@ -683,6 +721,24 @@ if(NOT MSVC)
|
||||
set_target_properties(spicetools_cfg PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||
endif()
|
||||
|
||||
# spicecfg_linux.exe
|
||||
##############
|
||||
|
||||
set(SOURCE_FILES ${SOURCE_FILES} launcher/options.h launcher/options.cpp)
|
||||
set(RESOURCE_FILES cfg/manifest.manifest cfg/manifest.rc cfg/icon.rc cfg/Win32D.rc)
|
||||
add_executable(spicetools_cfg_linux WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||
target_link_libraries(spicetools_cfg_linux
|
||||
PUBLIC ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
||||
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||
set_target_properties(spicetools_cfg_linux PROPERTIES PREFIX "")
|
||||
set_target_properties(spicetools_cfg_linux PROPERTIES OUTPUT_NAME "spicecfg_linux")
|
||||
target_compile_definitions(spicetools_cfg_linux PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
||||
target_compile_definitions(spicetools_cfg_linux PRIVATE NO_SCARD=1 PRIVATE SPICE_LINUX=1)
|
||||
|
||||
if(NOT MSVC)
|
||||
set_target_properties(spicetools_cfg_linux PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||
endif()
|
||||
|
||||
# stubs
|
||||
#######
|
||||
|
||||
@@ -776,19 +832,19 @@ endif()
|
||||
####################
|
||||
|
||||
# output config
|
||||
set_target_properties(spicetools_cfg
|
||||
set_target_properties(spicetools_cfg spicetools_cfg_linux
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools")
|
||||
|
||||
# output 32bit
|
||||
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
|
||||
set_target_properties(spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_kbt spicetools_stubs_kld spicetools_stubs_cpusbxpkm
|
||||
PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive32"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/32")
|
||||
|
||||
# output 64bit
|
||||
set_target_properties(spicetools_spice64 spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64
|
||||
set_target_properties(spicetools_spice64 spicetools_spice64_linux spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvcuda spicetools_stubs_nvcuvid spicetools_stubs_nvEncodeAPI64
|
||||
PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/archive64"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/spicetools/64"
|
||||
|
||||
@@ -1503,7 +1503,8 @@ namespace avs {
|
||||
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
|
||||
"\n"
|
||||
, DLL_NAME, MODULE_PATH.string()) };
|
||||
log_fatal("avs-ea3", "{}", info_str);
|
||||
log_warning("avs-ea3", "{}", info_str);
|
||||
log_fatal("avs-ea3", "Failed to find critical avs DLL on disk (avs2-core.dll OR {})", DLL_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,9 @@ namespace avs {
|
||||
" * Do NOT copy over random DLLs from another game installation; DLL must match game version\n"
|
||||
"\n"
|
||||
, DLL_NAME, MODULE_PATH.string()) };
|
||||
log_fatal("avs-ea3", "{}", info_str);
|
||||
|
||||
log_warning("avs-ea3", "{}", info_str);
|
||||
log_fatal("avs-ea3", "Failed to find critical ea3 DLL on disk (avs2-ea3.dll OR {})", DLL_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace avs {
|
||||
|
||||
// ddr gamemdx.dll user error
|
||||
if (avs::game::is_model("MDX") && DLL_NAME == "gamemdx.dll") {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"ddr",
|
||||
"BAD GAME DLL ERROR\n\n"
|
||||
"!!! !!!\n"
|
||||
@@ -107,6 +107,7 @@ namespace avs {
|
||||
"!!! remove -exec argument and try again. !!!\n"
|
||||
"!!! !!!\n"
|
||||
);
|
||||
log_fatal("ddr", "BAD GAME DLL ERROR (don't use -exec gamemdx.dll, that's the wrong DLL)");
|
||||
}
|
||||
|
||||
// file not found on disk
|
||||
|
||||
@@ -49,6 +49,7 @@ BUILDDIR_64_RELEASE="./cmake-build-release-64"
|
||||
BUILDDIR_64_DEBUG="./cmake-build-debug-64"
|
||||
DEBUG=0
|
||||
OUTDIR="./bin/spice2x"
|
||||
OUTDIR_EXTRAS="./bin/spice2x/extras"
|
||||
|
||||
# disabled UPX since it tends to falsely trigger malware detection
|
||||
UPX_ENABLE=0
|
||||
@@ -59,9 +60,10 @@ INCLUDE_SRC=1
|
||||
DIST_ENABLE=1
|
||||
DIST_FOLDER="./dist"
|
||||
DIST_NAME="spice2x-$(date +%y)-$(date +%m)-$(date +%d).zip"
|
||||
DIST_NAME_EXTRAS="spice2x-$(date +%y)-$(date +%m)-$(date +%d)-full.zip"
|
||||
DIST_COMMENT=${DIST_NAME}$'\n'"$GIT_BRANCH - $GIT_HEAD"$'\nThank you for playing.'
|
||||
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice spicetools_spice_laa spicetools_stubs_cpusbxpkm"
|
||||
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64"
|
||||
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_cfg_linux spicetools_spice spicetools_spice_laa spicetools_spice_linux spicetools_stubs_cpusbxpkm"
|
||||
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda spicetools_spice64 spicetools_spice64_linux"
|
||||
|
||||
# determine build type
|
||||
BUILD_TYPE="Release"
|
||||
@@ -179,11 +181,17 @@ fi
|
||||
|
||||
# copy to output directory
|
||||
echo "Copy files to output directory..."
|
||||
|
||||
rm -rf ${OUTDIR}
|
||||
mkdir -p ${OUTDIR}
|
||||
mkdir -p ${OUTDIR}/stubs/32
|
||||
mkdir -p ${OUTDIR}/stubs/64
|
||||
mkdir -p ${OUTDIR}/extras/largeaddressaware
|
||||
|
||||
rm -rf ${OUTDIR_EXTRAS}
|
||||
mkdir -p ${OUTDIR_EXTRAS}
|
||||
mkdir -p ${OUTDIR_EXTRAS}/largeaddressaware
|
||||
mkdir -p ${OUTDIR_EXTRAS}/linux
|
||||
|
||||
if false # ((DEBUG > 0))
|
||||
then
|
||||
# debug files
|
||||
@@ -204,11 +212,14 @@ then
|
||||
else
|
||||
# release files
|
||||
cp ${BUILDDIR_32}/spicetools/spicecfg.exe ${OUTDIR} 2>/dev/null
|
||||
cp ${BUILDDIR_32}/spicetools/spicecfg_linux.exe ${OUTDIR_EXTRAS}/linux/spicecfg.exe 2>/dev/null
|
||||
cp ${BUILDDIR_32}/spicetools/32/spice.exe ${OUTDIR} 2>/dev/null
|
||||
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR}/extras/largeaddressaware/spice.exe 2>/dev/null
|
||||
cp ${BUILDDIR_32}/spicetools/32/spice_laa.exe ${OUTDIR_EXTRAS}/largeaddressaware/spice.exe 2>/dev/null
|
||||
cp ${BUILDDIR_32}/spicetools/32/spice_linux.exe ${OUTDIR_EXTRAS}/linux/spice.exe 2>/dev/null
|
||||
#cp ${BUILDDIR_32}/spicetools/32/kbt.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||
#cp ${BUILDDIR_32}/spicetools/32/kld.dll ${OUTDIR}/stubs/32 2>/dev/null
|
||||
cp ${BUILDDIR_64}/spicetools/64/spice64.exe ${OUTDIR} 2>/dev/null
|
||||
cp ${BUILDDIR_64}/spicetools/64/spice64_linux.exe ${OUTDIR_EXTRAS}/linux/spice64.exe 2>/dev/null
|
||||
#cp ${BUILDDIR_64}/spicetools/64/kbt.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||
#cp ${BUILDDIR_64}/spicetools/64/kld.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||
cp ${BUILDDIR_64}/spicetools/64/nvEncodeAPI64.dll ${OUTDIR}/stubs/64 2>/dev/null
|
||||
@@ -228,10 +239,10 @@ then
|
||||
fi
|
||||
|
||||
# copy resources
|
||||
rm -rf ${OUTDIR}/api
|
||||
mkdir ${OUTDIR}/api
|
||||
rm -rf ${OUTDIR_EXTRAS}/api
|
||||
mkdir ${OUTDIR_EXTRAS}/api
|
||||
find ./api/resources/python -name "__pycache__" -exec rm -rf {} +
|
||||
cp -r ./api/resources/* ${OUTDIR}/api
|
||||
cp -r ./api/resources/* ${OUTDIR_EXTRAS}/api
|
||||
|
||||
# build distribution archive
|
||||
if ((DIST_ENABLE > 0))
|
||||
@@ -240,7 +251,9 @@ then
|
||||
mkdir -p ${DIST_FOLDER}
|
||||
rm -rf ${DIST_FOLDER}/${DIST_NAME}
|
||||
pushd ${OUTDIR}/.. > /dev/null
|
||||
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME} . -z <<< "$DIST_COMMENT"
|
||||
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME} spice2x -x "spice2x/extras/*" -z <<< "$DIST_COMMENT"
|
||||
echo "Building extras..."
|
||||
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME_EXTRAS} spice2x -z <<< "$DIST_COMMENT"
|
||||
popd > /dev/null
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
del /s /q .ccache
|
||||
del /s /q dist
|
||||
call build_docker.bat
|
||||
@@ -87,6 +87,10 @@ namespace cfg {
|
||||
load_float_value(doc, root + prefix + "scale_x", scene.scale_x);
|
||||
load_float_value(doc, root + prefix + "scale_y", scene.scale_y);
|
||||
load_bool_value(doc, root + prefix + "keep_aspect_ratio", scene.keep_aspect_ratio);
|
||||
|
||||
int duplicate = 0;
|
||||
load_int_value(doc, root + prefix + "duplicate", duplicate);
|
||||
scene.duplicate = static_cast<cfg::ScreenDuplicateMode>(duplicate);
|
||||
}
|
||||
|
||||
// windowed settings are always under game settings
|
||||
@@ -201,6 +205,7 @@ namespace cfg {
|
||||
rapidjson::Pointer(root + prefix + "scale_x").Set(doc, scene.scale_x);
|
||||
rapidjson::Pointer(root + prefix + "scale_y").Set(doc, scene.scale_y);
|
||||
rapidjson::Pointer(root + prefix + "keep_aspect_ratio").Set(doc, scene.keep_aspect_ratio);
|
||||
rapidjson::Pointer(root + prefix + "duplicate").Set(doc, scene.duplicate);
|
||||
}
|
||||
|
||||
// windowed mode settings
|
||||
|
||||
@@ -14,12 +14,19 @@ namespace cfg {
|
||||
ResizableFrame = 2
|
||||
};
|
||||
|
||||
enum ScreenDuplicateMode {
|
||||
None = 0,
|
||||
CopyLeft = 1,
|
||||
CopyRight = 2,
|
||||
};
|
||||
|
||||
struct fullscreen_setting {
|
||||
int offset_x = 0;
|
||||
int offset_y = 0;
|
||||
float scale_x = 1.0;
|
||||
float scale_y = 1.0;
|
||||
bool keep_aspect_ratio = true;
|
||||
ScreenDuplicateMode duplicate = ScreenDuplicateMode::None;
|
||||
};
|
||||
|
||||
extern std::optional<std::string> SCREEN_RESIZE_CFG_PATH_OVERRIDE;
|
||||
|
||||
Vendored
+3
@@ -23,6 +23,7 @@
|
||||
* Modified version.
|
||||
*/
|
||||
|
||||
#ifndef NO_SCARD
|
||||
|
||||
#include "scard.h"
|
||||
#include <windows.h>
|
||||
@@ -409,3 +410,5 @@ void scard_threadstart() {
|
||||
void scard_fini() {
|
||||
should_exit = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace games::ddr {
|
||||
|
||||
void DDRGame::pre_attach() {
|
||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDX")) {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"ddr",
|
||||
"BAD MODEL NAME ERROR\n\n\n"
|
||||
"!!! model name set to TDX, this is WRONG and will break your game !!!\n"
|
||||
@@ -136,6 +136,8 @@ namespace games::ddr {
|
||||
"!!! !!!\n"
|
||||
"!!! model name set to TDX, this is WRONG and will break your game !!!\n\n\n"
|
||||
);
|
||||
|
||||
log_fatal("ddr", "BAD MODEL NAME ERROR - TDX specified, should be MDX instead");
|
||||
}
|
||||
|
||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::DEST[0] == 'U') {
|
||||
|
||||
@@ -22,35 +22,31 @@
|
||||
static std::filesystem::path dll_path;
|
||||
static HMODULE iidx_module;
|
||||
static uintptr_t addr_hook_a = 0;
|
||||
static uintptr_t addr_hook_b = 0;
|
||||
static uintptr_t addr_textures = 0;
|
||||
static uintptr_t addr_camera_manager = 0;
|
||||
static uintptr_t addr_device_offset = 0;
|
||||
static uintptr_t addr_afp_texture_offset = 0;
|
||||
|
||||
typedef void **(__fastcall *camera_hook_a_t)(PBYTE);
|
||||
typedef LPDIRECT3DTEXTURE9 (*camera_hook_b_t)(void*, int);
|
||||
static camera_hook_a_t camera_hook_a_orig = nullptr;
|
||||
static camera_hook_b_t camera_hook_b_orig = nullptr;
|
||||
auto static hook_a_init = std::once_flag {};
|
||||
|
||||
static LPDIRECT3DDEVICE9EX device;
|
||||
static LPDIRECT3DTEXTURE9 *texture_a = nullptr;
|
||||
static LPDIRECT3DTEXTURE9 *texture_b = nullptr;
|
||||
static LPDIRECT3DTEXTURE9 *camera_texture_a = nullptr;
|
||||
static LPDIRECT3DTEXTURE9 *camera_texture_b = nullptr;
|
||||
static LPDIRECT3DTEXTURE9 *preview_texture_a = nullptr;
|
||||
static LPDIRECT3DTEXTURE9 *preview_texture_b = nullptr;
|
||||
|
||||
struct PredefinedHook {
|
||||
std::string pe_identifier;
|
||||
uintptr_t hook_a;
|
||||
uintptr_t hook_b;
|
||||
uintptr_t hook_textures;
|
||||
uintptr_t hook_camera_manager;
|
||||
uintptr_t hook_device_offset;
|
||||
uintptr_t hook_afp_texture_offset;
|
||||
};
|
||||
|
||||
PredefinedHook g_predefinedHooks[] =
|
||||
{
|
||||
// 27 003
|
||||
{ "5f713b52_6d4090", 0x005971b0, 0x005fb2c0, 0x04e49898, 0x000000d0 },
|
||||
// 27 010
|
||||
{ "5f713946_7f52b0", 0x006b89e0, 0x0071c950, 0x04fd08b8, 0x000000d0 },
|
||||
};
|
||||
PredefinedHook g_predefinedHooks[] = {};
|
||||
|
||||
const DWORD g_predefinedHooksLength = ARRAYSIZE(g_predefinedHooks);
|
||||
|
||||
@@ -75,8 +71,8 @@ namespace games::iidx {
|
||||
|
||||
if (sscanf(
|
||||
s.c_str(),
|
||||
"%i,%i,%i,%i",
|
||||
(int*)&addr_hook_a, (int*)&addr_hook_b, (int*)&addr_textures, (int*)&addr_device_offset) == 4) {
|
||||
"%i,%i,%i,%i,%i",
|
||||
(int*)&addr_hook_a, (int*)&addr_textures, (int*)&addr_camera_manager, (int*)&addr_device_offset, (int*)&addr_afp_texture_offset) == 5) {
|
||||
|
||||
return true;
|
||||
|
||||
@@ -101,8 +97,8 @@ namespace games::iidx {
|
||||
|
||||
// there are three different ways we try to hook the camera entry points
|
||||
// 1) user-provided override via cmd line
|
||||
// 2) predefined offsets using PE header matching (needed for iidx27 and few others)
|
||||
// 3) signature match (should work for most iidx28-31)
|
||||
// 2) predefined offsets using PE header matching
|
||||
// 3) signature match (should work for most iidx27-33)
|
||||
|
||||
// method 1: user provided
|
||||
if (TDJ_CAMERA_OVERRIDE.has_value() && parse_cmd_params()) {
|
||||
@@ -117,10 +113,11 @@ namespace games::iidx {
|
||||
for (DWORD i = 0; i < g_predefinedHooksLength; i++) {
|
||||
if (pe.compare(g_predefinedHooks[i].pe_identifier) == 0) {
|
||||
log_misc("iidx:camhook", "Found predefined addresses");
|
||||
addr_hook_a = g_predefinedHooks[i].hook_a;
|
||||
addr_hook_b = g_predefinedHooks[i].hook_b;
|
||||
addr_textures = g_predefinedHooks[i].hook_textures;
|
||||
addr_device_offset = g_predefinedHooks[i].hook_device_offset;
|
||||
addr_hook_a = g_predefinedHooks[i].hook_a;
|
||||
addr_textures = g_predefinedHooks[i].hook_textures;
|
||||
addr_camera_manager = g_predefinedHooks[i].hook_camera_manager;
|
||||
addr_device_offset = g_predefinedHooks[i].hook_device_offset;
|
||||
addr_afp_texture_offset = g_predefinedHooks[i].hook_afp_texture_offset;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -131,8 +128,8 @@ namespace games::iidx {
|
||||
// --- addr_hook_a ---
|
||||
uint8_t *addr_hook_a_ptr = reinterpret_cast<uint8_t *>(find_pattern(
|
||||
iidx_module,
|
||||
"488BC4565741564883EC5048C740D8FEFFFFFF",
|
||||
"XXXXXXXXXXXXXXXXXXX",
|
||||
"E800000000488B8F0000000048894D",
|
||||
"X????XXX????XXX",
|
||||
0, 0));
|
||||
|
||||
if (addr_hook_a_ptr == nullptr) {
|
||||
@@ -141,24 +138,10 @@ namespace games::iidx {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addr_hook_a = (uint64_t) (addr_hook_a_ptr - (uint8_t*) iidx_module);
|
||||
|
||||
// addr_hook_b
|
||||
uint8_t* addr_hook_b_ptr = reinterpret_cast<uint8_t *>(find_pattern(
|
||||
iidx_module,
|
||||
"E8000000004885C07439E8",
|
||||
"X????XXXXXX",
|
||||
0, 0));
|
||||
|
||||
if (addr_hook_b_ptr == nullptr) {
|
||||
log_warning("iidx:camhook", "failed to find hook: addr_hook_b");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// displace with the content of wildcard bytes
|
||||
int32_t disp_b = *((int32_t *) (addr_hook_b_ptr + 1));
|
||||
int32_t disp_a = *((int32_t *) (addr_hook_a_ptr + 1));
|
||||
|
||||
addr_hook_b = (addr_hook_b_ptr - (uint8_t*) iidx_module) + disp_b + 5;
|
||||
addr_hook_a = (addr_hook_a_ptr - (uint8_t*) iidx_module) + disp_a + 5;
|
||||
|
||||
// --- addr_textures ---
|
||||
uint8_t* addr_textures_ptr = reinterpret_cast<uint8_t *>(find_pattern(
|
||||
@@ -194,6 +177,28 @@ namespace games::iidx {
|
||||
|
||||
addr_textures = (addr_textures_ptr - (uint8_t*) iidx_module) + disp_textures + 7;
|
||||
|
||||
// --- addr_camera_manager ---
|
||||
uint8_t *addr_camera_manager_ptr = reinterpret_cast<uint8_t *>(find_pattern(
|
||||
iidx_module,
|
||||
"E80000000033FF488B58",
|
||||
"X????XXXXX",
|
||||
0, 0));
|
||||
|
||||
if (addr_camera_manager_ptr == nullptr) {
|
||||
log_warning("iidx:camhook", "failed to find hook: addr_get_camera_manager");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// displace with the content of wildcard bytes
|
||||
int32_t disp_camera_manager = *((int32_t *) (addr_camera_manager_ptr + 1));
|
||||
|
||||
addr_camera_manager_ptr = addr_camera_manager_ptr + disp_camera_manager + 5;
|
||||
|
||||
// once more to get the final address
|
||||
disp_camera_manager = *((int32_t *) (addr_camera_manager_ptr + 3));
|
||||
|
||||
addr_camera_manager = (addr_camera_manager_ptr - (uint8_t*) iidx_module) + disp_camera_manager + 7;
|
||||
|
||||
// addr_device_offset
|
||||
search_from = (addr_hook_a_ptr - (uint8_t*) iidx_module);
|
||||
uint8_t *addr_device_ptr = reinterpret_cast<uint8_t *>(find_pattern_from(
|
||||
@@ -201,39 +206,47 @@ namespace games::iidx {
|
||||
"488B89",
|
||||
"XXX",
|
||||
3, 0, search_from));
|
||||
addr_device_offset = *addr_device_ptr;
|
||||
|
||||
if (addr_textures_ptr == nullptr) {
|
||||
log_warning("iidx:camhook", "failed to find hook: addr_textures (part 3)");
|
||||
if (addr_device_ptr == nullptr) {
|
||||
log_warning("iidx:camhook", "failed to find hook: addr_device_ptr");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addr_device_offset = *addr_device_ptr;
|
||||
|
||||
// --- addr_afp_texture_offset ---
|
||||
uint8_t *addr_afp_texture_ptr = reinterpret_cast<uint8_t *>(find_pattern(
|
||||
iidx_module,
|
||||
"488B41004885C07400488D5424",
|
||||
"XXX?XXXX?XXXX",
|
||||
0, 0));
|
||||
|
||||
if (addr_afp_texture_ptr == nullptr) {
|
||||
log_warning("iidx:camhook", "failed to find hook: addr_afp_texture_offset");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addr_afp_texture_offset = *(addr_afp_texture_ptr + 3);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void **__fastcall camera_hook_a(PBYTE a1) {
|
||||
std::call_once(hook_a_init, [&]{
|
||||
device = *reinterpret_cast<LPDIRECT3DDEVICE9EX*>(a1 + addr_device_offset);
|
||||
auto const textures = *reinterpret_cast<LPDIRECT3DTEXTURE9**>((uint8_t*)iidx_module + addr_textures);
|
||||
auto const preview = *reinterpret_cast<LPDIRECT3DTEXTURE9**>((uint8_t*)iidx_module + addr_textures);
|
||||
auto const manager = reinterpret_cast<Camera::CCameraManager2*>((uint8_t*)iidx_module + addr_camera_manager);
|
||||
|
||||
texture_a = textures;
|
||||
texture_b = textures + 2;
|
||||
camera_texture_a = manager->cameras->a->d3d9_texture(addr_afp_texture_offset);
|
||||
camera_texture_b = manager->cameras->b->d3d9_texture(addr_afp_texture_offset);
|
||||
preview_texture_a = preview;
|
||||
preview_texture_b = preview + 2;
|
||||
|
||||
init_local_camera();
|
||||
});
|
||||
return camera_hook_a_orig(a1);
|
||||
}
|
||||
|
||||
static LPDIRECT3DTEXTURE9 camera_hook_b(void* a1, int idx) {
|
||||
if (idx == 0 && top_camera) {
|
||||
return top_camera->GetTexture();
|
||||
}
|
||||
if (idx == 1 && front_camera) {
|
||||
return front_camera->GetTexture();
|
||||
}
|
||||
return camera_hook_b_orig(a1, idx);
|
||||
}
|
||||
|
||||
bool create_hooks() {
|
||||
auto *hook_a_ptr = reinterpret_cast<uint16_t *>(
|
||||
reinterpret_cast<intptr_t>(iidx_module) + addr_hook_a);
|
||||
@@ -246,17 +259,6 @@ namespace games::iidx {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
auto *hook_b_ptr = reinterpret_cast<uint16_t *>(
|
||||
reinterpret_cast<intptr_t>(iidx_module) + addr_hook_b);
|
||||
|
||||
if (!detour::trampoline(
|
||||
reinterpret_cast<camera_hook_b_t>(hook_b_ptr),
|
||||
camera_hook_b,
|
||||
&camera_hook_b_orig)) {
|
||||
log_warning("iidx:camhook", "failed to trampoline hook_b");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -443,7 +445,7 @@ namespace games::iidx {
|
||||
}
|
||||
|
||||
IIDXLocalCamera* add_top_camera(IMFActivate* pActivate) {
|
||||
auto top_camera = new IIDXLocalCamera("top", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, texture_a);
|
||||
auto top_camera = new IIDXLocalCamera("top", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, camera_texture_a, preview_texture_a);
|
||||
if (top_camera->m_initialized) {
|
||||
LOCAL_CAMERA_LIST.push_back(top_camera);
|
||||
} else {
|
||||
@@ -454,7 +456,7 @@ namespace games::iidx {
|
||||
}
|
||||
|
||||
IIDXLocalCamera* add_front_camera(IMFActivate* pActivate) {
|
||||
auto front_camera = new IIDXLocalCamera("front", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, texture_b);
|
||||
auto front_camera = new IIDXLocalCamera("front", TDJ_CAMERA_PREFER_16_9, pActivate, s_pD3DManager, device, camera_texture_b, preview_texture_b);
|
||||
if (front_camera->m_initialized) {
|
||||
LOCAL_CAMERA_LIST.push_back(front_camera);
|
||||
} else {
|
||||
@@ -469,8 +471,8 @@ namespace games::iidx {
|
||||
if (result) {
|
||||
log_misc(
|
||||
"iidx:camhook",
|
||||
"found hooks:\n hook_a 0x{:x}\n hook_b 0x{:x}\n textures 0x{:x}\n device_offset 0x{:x}",
|
||||
addr_hook_a, addr_hook_b, addr_textures, addr_device_offset);
|
||||
"found hooks:\n hook_a 0x{:x}\n textures 0x{:x}\n camera_manager 0x{:x}\n device_offset 0x{:x}\n afp_texture_offset 0x{:x}",
|
||||
addr_hook_a, addr_textures, addr_camera_manager, addr_device_offset, addr_afp_texture_offset);
|
||||
result = create_hooks();
|
||||
if (result) {
|
||||
init_mf_library();
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace games::iidx {
|
||||
|
||||
// settings
|
||||
bool FLIP_CAMS = false;
|
||||
bool DISABLE_CAMS = false;
|
||||
std::optional<bool> DISABLE_CAMS;
|
||||
bool TDJ_CAMERA = false;
|
||||
bool TDJ_CAMERA_PREFER_16_9 = true;
|
||||
bool TDJ_MODE = false;
|
||||
@@ -334,11 +334,6 @@ namespace games::iidx {
|
||||
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
|
||||
wintouchemu::hook_title_ends("beatmania IIDX", "main", avs::game::DLL_INSTANCE);
|
||||
}
|
||||
|
||||
// prevent crash on TDJ mode without correct DLL
|
||||
if (!GetModuleHandle("nvcuda.dll")) {
|
||||
DISABLE_CAMS = true;
|
||||
}
|
||||
}
|
||||
|
||||
// insert BI2X hooks
|
||||
@@ -399,37 +394,44 @@ namespace games::iidx {
|
||||
"RegQueryValueExA", RegQueryValueExA_hook, avs::game::DLL_INSTANCE);
|
||||
|
||||
// check if cam hook should be enabled
|
||||
if (!DISABLE_CAMS) {
|
||||
if (!DISABLE_CAMS.has_value()) {
|
||||
log_fatal("iidx", "assertion failure - DISABLE_CAMS not set during attach");
|
||||
}
|
||||
if (!DISABLE_CAMS.value()) {
|
||||
init_legacy_camera_hook(FLIP_CAMS);
|
||||
}
|
||||
|
||||
// init cfgmgr32 hooks
|
||||
cfgmgr32hook_init(avs::game::DLL_INSTANCE);
|
||||
|
||||
// report common errors on iidx31 and above
|
||||
if (avs::game::is_ext(2023091500, MAXINT) && GRAPHICS_9_ON_12_STATE == DX9ON12_FORCE_ON) {
|
||||
deferredlogs::defer_error_messages({
|
||||
"common incompatibility with DX 9on12 + IIDX 31 and above",
|
||||
" IIDX31+ is known to be incompatible with DX 9on12, leading to blank screen or crashes"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void IIDXGame::pre_attach() {
|
||||
Game::pre_attach();
|
||||
auto options = games::get_options(eamuse_get_game());
|
||||
|
||||
// environment variables must be set before the DLL is loaded as the VC++ runtime copies all
|
||||
// environment variables at startup
|
||||
if (DISABLE_CAMS) {
|
||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||
}
|
||||
|
||||
if (SCREEN_MODE.has_value()) {
|
||||
log_misc("iidx", "SCREEN_MODE env var set to {}", SCREEN_MODE.value().c_str());
|
||||
SetEnvironmentVariable("SCREEN_MODE", SCREEN_MODE.value().c_str());
|
||||
}
|
||||
|
||||
// check for cab camera access for the second time (first time was in launcher.cpp)
|
||||
// this time, we are inside -iidx module hook, which means the user is likely NOT on a cab
|
||||
// therefore, start with cams OFF by default, and allow user to forcibly override to ON
|
||||
if (!games::iidx::DISABLE_CAMS.has_value()) {
|
||||
games::iidx::DISABLE_CAMS = true;
|
||||
if (options->at(launcher::Options::IIDXCabCamAccess).is_active() &&
|
||||
options->at(launcher::Options::IIDXCabCamAccess).value_text() == "on") {
|
||||
games::iidx::DISABLE_CAMS = false;
|
||||
}
|
||||
if (games::iidx::DISABLE_CAMS.value()) {
|
||||
log_misc("iidx", "CONNECT_CAMERA env var set to 0");
|
||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||
}
|
||||
}
|
||||
|
||||
// windowed subscreen, enabled by default, unless turned off by user
|
||||
auto options = games::get_options(eamuse_get_game());
|
||||
if (GRAPHICS_WINDOWED && !options->at(launcher::Options::spice2x_IIDXNoSub).value_bool()) {
|
||||
GRAPHICS_IIDX_WSUB = true;
|
||||
}
|
||||
@@ -440,7 +442,7 @@ namespace games::iidx {
|
||||
|
||||
// check bad model name
|
||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("TDJ")) {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"iidx",
|
||||
"BAD MODEL NAME ERROR\n\n\n"
|
||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n"
|
||||
@@ -458,6 +460,8 @@ namespace games::iidx {
|
||||
"!!! !!!\n"
|
||||
"!!! model name set to TDJ, this is WRONG and will break your game !!!\n\n\n"
|
||||
);
|
||||
|
||||
log_fatal("iidx", "BAD MODEL NAME ERROR - TDJ specified, must be LDJ instead");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace games::iidx {
|
||||
// settings
|
||||
|
||||
extern bool FLIP_CAMS;
|
||||
extern bool DISABLE_CAMS;
|
||||
extern std::optional<bool> DISABLE_CAMS;
|
||||
extern bool TDJ_CAMERA;
|
||||
extern bool TDJ_CAMERA_PREFER_16_9;
|
||||
extern std::optional<std::string> TDJ_CAMERA_OVERRIDE;
|
||||
|
||||
@@ -213,6 +213,8 @@ namespace games::iidx {
|
||||
}
|
||||
|
||||
void init_legacy_camera_hook(bool flip_cams) {
|
||||
log_info("iidx::cam", "initializing legacy camera hook");
|
||||
|
||||
should_flip_cams = flip_cams;
|
||||
|
||||
// camera media framework hook
|
||||
|
||||
@@ -46,14 +46,17 @@ namespace games::iidx {
|
||||
IMFActivate *pActivate,
|
||||
IDirect3DDeviceManager9 *pD3DManager,
|
||||
LPDIRECT3DDEVICE9EX device,
|
||||
LPDIRECT3DTEXTURE9 *texture_target
|
||||
LPDIRECT3DTEXTURE9 *camera_texture_target,
|
||||
LPDIRECT3DTEXTURE9 *preview_texture_target
|
||||
):
|
||||
m_nRefCount(1),
|
||||
m_name(name),
|
||||
m_prefer_16_by_9(prefer_16_by_9),
|
||||
m_device(device),
|
||||
m_texture_target(texture_target),
|
||||
m_texture_original(*texture_target)
|
||||
m_camera_texture_target(camera_texture_target),
|
||||
m_preview_texture_target(preview_texture_target),
|
||||
m_camera_texture_original(*camera_texture_target),
|
||||
m_preview_texture_original(*preview_texture_target)
|
||||
{
|
||||
InitializeCriticalSection(&m_critsec);
|
||||
|
||||
@@ -691,7 +694,8 @@ namespace games::iidx {
|
||||
if (FAILED(hr)) { goto done; }
|
||||
|
||||
// Make the game use this new texture as camera stream source
|
||||
*m_texture_target = m_texture;
|
||||
*m_camera_texture_target = m_texture;
|
||||
*m_preview_texture_target = m_texture;
|
||||
m_active = TRUE;
|
||||
|
||||
// Create texture for colour conversion
|
||||
@@ -860,7 +864,8 @@ namespace games::iidx {
|
||||
|
||||
ULONG uCount = InterlockedDecrement(&m_nRefCount);
|
||||
|
||||
*m_texture_target = m_texture_original;
|
||||
*m_camera_texture_target = m_camera_texture_original;
|
||||
*m_preview_texture_target = m_preview_texture_original;
|
||||
|
||||
for (size_t i = 0; i < m_mediaTypeInfos.size(); i++) {
|
||||
SafeRelease(&(m_mediaTypeInfos.at(i).p_mediaType));
|
||||
|
||||
@@ -66,6 +66,25 @@ extern std::string CAMERA_CONTROL_LABELS[];
|
||||
extern std::string DRAW_MODE_LABELS[];
|
||||
|
||||
namespace games::iidx {
|
||||
namespace Camera {
|
||||
struct PlayVideoCamera {
|
||||
IDirect3DTexture9** d3d9_texture(const uintptr_t offset) {
|
||||
auto const afp_texture = *reinterpret_cast<uint8_t**>
|
||||
(reinterpret_cast<uint8_t*>(this) + offset);
|
||||
return reinterpret_cast<IDirect3DTexture9**>(afp_texture + 0x8);
|
||||
}
|
||||
};
|
||||
|
||||
struct CCameraManager2 {
|
||||
using camera_pointers = struct {
|
||||
PlayVideoCamera* a;
|
||||
PlayVideoCamera* b;
|
||||
};
|
||||
void* vftbl;
|
||||
camera_pointers* cameras;
|
||||
};
|
||||
}
|
||||
|
||||
class IIDXLocalCamera {
|
||||
protected:
|
||||
virtual ~IIDXLocalCamera() {};
|
||||
@@ -98,8 +117,9 @@ namespace games::iidx {
|
||||
// DirectX9 DeviceEx
|
||||
LPDIRECT3DDEVICE9EX m_device;
|
||||
|
||||
// Address to hook camera texture onto the game
|
||||
LPDIRECT3DTEXTURE9 *m_texture_target = nullptr;
|
||||
// Address to hook camera textures onto the game
|
||||
LPDIRECT3DTEXTURE9 *m_camera_texture_target = nullptr;
|
||||
LPDIRECT3DTEXTURE9 *m_preview_texture_target = nullptr;
|
||||
|
||||
// Target texture (to be shown in the game)
|
||||
LPDIRECT3DTEXTURE9 m_texture = nullptr;
|
||||
@@ -117,8 +137,9 @@ namespace games::iidx {
|
||||
LPDIRECT3DTEXTURE9 m_transformResultTexture = nullptr;
|
||||
IDirect3DSurface9 *m_pTransformResultSurf = nullptr;
|
||||
|
||||
// Storing original texture for clean up
|
||||
LPDIRECT3DTEXTURE9 m_texture_original = nullptr;
|
||||
// Storing original textures for clean up
|
||||
LPDIRECT3DTEXTURE9 m_camera_texture_original = nullptr;
|
||||
LPDIRECT3DTEXTURE9 m_preview_texture_original = nullptr;
|
||||
|
||||
IAMCameraControl *m_pCameraControl = nullptr;
|
||||
|
||||
@@ -154,7 +175,8 @@ namespace games::iidx {
|
||||
IMFActivate *pActivate,
|
||||
IDirect3DDeviceManager9 *pD3DManager,
|
||||
LPDIRECT3DDEVICE9EX device,
|
||||
LPDIRECT3DTEXTURE9 *texture_target
|
||||
LPDIRECT3DTEXTURE9 *camera_texture_target,
|
||||
LPDIRECT3DTEXTURE9 *preview_texture_target
|
||||
);
|
||||
LPDIRECT3DTEXTURE9 GetTexture();
|
||||
ULONG Release();
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace games::jb {
|
||||
const auto current_path = std::filesystem::current_path();
|
||||
log_misc("jubeat", "current working directory: {}", current_path.string());
|
||||
if (current_path.parent_path() == current_path.root_path()) {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"jubeat",
|
||||
"\n\nInvalid path error; jubeat cannot run from a directory in the drive root\n"
|
||||
"The game will overflow the stack and silently fail to boot\n\n"
|
||||
@@ -179,6 +179,10 @@ namespace games::jb {
|
||||
"To fix this, create a new directory and move ALL game files there.\n\n"
|
||||
"Your current working directory: {}\n",
|
||||
current_path.string());
|
||||
|
||||
log_fatal(
|
||||
"jubeat",
|
||||
"Invalid path error; jubeat cannot run from a directory in the drive root");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "avs/game.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "touch/touch.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/libutils.h"
|
||||
@@ -32,6 +33,8 @@ namespace games::mfc {
|
||||
static uint8_t CARD_TYPE = 0;
|
||||
static uint8_t CARD_UID[8];
|
||||
|
||||
bool HG_MODE = false;
|
||||
|
||||
typedef int (__cdecl *inifile_param_num_t)(const char *, int *);
|
||||
static inifile_param_num_t inifile_param_num_real;
|
||||
|
||||
@@ -50,8 +53,10 @@ namespace games::mfc {
|
||||
static void __cdecl touch_init(int width, int height) {
|
||||
log_info("mfc", "call touch_init(width: {}, height: {})", width, height);
|
||||
|
||||
// attach touch module
|
||||
if (!TOUCH_ATTACHED) {
|
||||
if (HG_MODE) {
|
||||
wintouchemu::ADD_TOUCH_FLAG_PRIMARY = true;
|
||||
wintouchemu::hook("MFC9", avs::game::DLL_INSTANCE);
|
||||
} else if (!TOUCH_ATTACHED) { // attach touch module
|
||||
|
||||
// store touch size specification
|
||||
TOUCH_MAX_X = width;
|
||||
@@ -288,6 +293,21 @@ namespace games::mfc {
|
||||
MFCGame::MFCGame() : Game("Mahjong Fight Club") {
|
||||
}
|
||||
|
||||
static bool spam_remover(void *user, const std::string &data, logger::Style style, std::string &out) {
|
||||
if (data.empty() || data[0] != '[') {
|
||||
return false;
|
||||
}
|
||||
if (data.find("W:mutex: lock: mid 00000000 != AVS_DTYPE_MUTEX") != std::string::npos) {
|
||||
out = "";
|
||||
return true;
|
||||
}
|
||||
if (data.find("W:mutex: unlock: mid 00000000 != AVS_DTYPE_MUTEX") != std::string::npos) {
|
||||
out = "";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MFCGame::attach() {
|
||||
Game::attach();
|
||||
|
||||
@@ -308,6 +328,17 @@ namespace games::mfc {
|
||||
auto allinone_module = libutils::try_module("allinone.dll");
|
||||
auto system_module = libutils::try_module("system.dll");
|
||||
|
||||
// Mahjong Fight Club - 2025?
|
||||
// they removed allinone.dll and moved i/o into system.dll
|
||||
if (allinone_module == nullptr) {
|
||||
log_misc("mfc", "using system.dll instead of allinone.dll for i/o hooks");
|
||||
allinone_module = system_module;
|
||||
|
||||
if (avs::game::SPEC[0] == 'F') {
|
||||
HG_MODE = true;
|
||||
}
|
||||
}
|
||||
|
||||
// network fix
|
||||
detour::iat_try("?nic_dhcp_maybe_exist@@YAEXZ", nic_dhcp_maybe_exist, system_module);
|
||||
|
||||
@@ -378,5 +409,7 @@ namespace games::mfc {
|
||||
detour::inline_hook((void *) mouse_utl_step, libutils::try_proc(
|
||||
allinone_module, "?mouse_utl_step@@YAXXZ"));
|
||||
}
|
||||
|
||||
logger::hook_add(spam_remover, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
namespace games::mfc {
|
||||
|
||||
extern bool HG_MODE;
|
||||
|
||||
struct joystick_state {
|
||||
bool up = false;
|
||||
bool down = false;
|
||||
|
||||
@@ -106,8 +106,8 @@ namespace games::sdvx {
|
||||
if (ENABLE_COM_PORT_SCAN_HOOK &&
|
||||
lpSubKey != nullptr && phkResult != nullptr &&
|
||||
_stricmp(lpSubKey, "HARDWARE\\DEVICEMAP\\SERIALCOMM") == 0) {
|
||||
log_info("sdvx::io", "failing HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
|
||||
return 2; //ERROR_FILE_NOT_FOUND
|
||||
log_info("sdvx::io", "hook access to HKLM\\HARDWARE\\DEVICEMAP\\SERIALCOMM to force COM1 ICCA");
|
||||
return 2; // ERROR_FILE_NOT_FOUND
|
||||
}
|
||||
|
||||
return RegOpenKeyExA_orig(hKey, lpSubKey, ulOptions, samDesired, phkResult);
|
||||
@@ -215,6 +215,15 @@ namespace games::sdvx {
|
||||
deferredlogs::defer_error_messages(deferredlogs::SUPERSTEP_SOUND_ERROR_MESSAGE);
|
||||
return false;
|
||||
}
|
||||
if (data.find("W:ea3-pos: ea3_report_posev: no such node:") != std::string::npos) {
|
||||
deferredlogs::defer_error_messages({
|
||||
"bad prop\\ea3-config.xml detected by game",
|
||||
std::string(" ") + data,
|
||||
" this will most likely cause Server Busy errors in certain conditions",
|
||||
" follow the FAQ to fix your ea3-config.xml and try again"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -268,7 +277,7 @@ namespace games::sdvx {
|
||||
AUTO_INSERT_CARD_COOLDOWN = 15.f;
|
||||
// check bad model name
|
||||
if (!cfg::CONFIGURATOR_STANDALONE && avs::game::is_model("UFC")) {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"sdvx",
|
||||
"BAD MODEL NAME ERROR\n\n\n"
|
||||
"!!! model name set to UFC, this is WRONG and will break your game !!!\n"
|
||||
@@ -278,6 +287,9 @@ namespace games::sdvx {
|
||||
"!!! !!!\n"
|
||||
"!!! model name set to UFC, this is WRONG and will break your game !!!\n\n\n"
|
||||
);
|
||||
log_fatal(
|
||||
"sdvx",
|
||||
"BAD MODEL NAME ERROR - model name set to UFC, must be KFC instead");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "cfg/screen_resize.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "games/sdvx/sdvx.h"
|
||||
#include "games/mfc/mfc.h"
|
||||
#include "games/io.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
#include "launcher/launcher.h"
|
||||
@@ -238,14 +239,17 @@ static void log_create_device_failure(HRESULT hresult) {
|
||||
}
|
||||
|
||||
static bool is_dx9_on_12_enabled() {
|
||||
bool result = false;
|
||||
switch (GRAPHICS_9_ON_12_STATE) {
|
||||
case DX9ON12_FORCE_OFF:
|
||||
log_info("graphics::d3d9", "DirectX 9on12: forced OFF by user (-dx9on12)");
|
||||
return false;
|
||||
result = false;
|
||||
break;
|
||||
|
||||
case DX9ON12_FORCE_ON:
|
||||
log_info("graphics::d3d9", "DirectX 9on12: forced ON by user (-9on12 or -dx9on12)");
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case DX9ON12_AUTO:
|
||||
default:
|
||||
@@ -253,14 +257,33 @@ static bool is_dx9_on_12_enabled() {
|
||||
log_info(
|
||||
"graphics::d3d9",
|
||||
"DirectX 9on12: enabled automatically for current game (tip: use -dx9on12 to force on or off)");
|
||||
return true;
|
||||
result = true;
|
||||
} else {
|
||||
log_info(
|
||||
"graphics::d3d9",
|
||||
"DirectX 9on12: disabled by default, using DX9 (tip: use -dx9on12 to force on or off)");
|
||||
return false;
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (GRAPHICS_9_ON_12_STATE == DX9ON12_FORCE_ON) {
|
||||
if (avs::game::is_model("LDJ") && avs::game::is_ext(2023091500, MAXINT)) {
|
||||
deferredlogs::defer_error_messages({
|
||||
"dx9on12 was force enabled by user (-dx9on12)",
|
||||
" IIDX31+ is known to be incompatible with DX 9on12, leading to blank screen or crashes",
|
||||
" try again with -dx9on12 option set to default value"
|
||||
});
|
||||
} else {
|
||||
deferredlogs::defer_error_messages({
|
||||
"dx9on12 was force enabled by user (-dx9on12)",
|
||||
" not very game is compatible with this, and can lead to crashes",
|
||||
" try without force enabling this if you are seeing issues"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static IDirect3D9 *WINAPI Direct3DCreate9_hook(UINT SDKVersion) {
|
||||
@@ -1338,6 +1361,11 @@ void graphics_d3d9_on_present(
|
||||
graphics_d3d9_ldj_on_present(wrapped_device);
|
||||
}
|
||||
|
||||
const bool is_mfc = avs::game::is_model("KK9") && games::mfc::HG_MODE;
|
||||
if (is_mfc) {
|
||||
wintouchemu::update();
|
||||
}
|
||||
|
||||
// check screenshot key
|
||||
static bool trigger_last = false;
|
||||
auto buttons = games::get_buttons_overlay(eamuse_get_game());
|
||||
|
||||
@@ -733,6 +733,16 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
||||
const int rectTop = param.BackBufferHeight;
|
||||
const int w = param.BackBufferWidth;
|
||||
const int h = param.BackBufferHeight;
|
||||
|
||||
if (cfg::SCREENRESIZE->enable_screen_resize) {
|
||||
RECT rect {
|
||||
0,
|
||||
0,
|
||||
(LONG)topSurface_width,
|
||||
(LONG)topSurface_height,
|
||||
};
|
||||
pReal->ColorFill(topSurface, &rect, D3DCOLOR_XRGB(0, 0, 0));
|
||||
}
|
||||
|
||||
D3DLOCKED_RECT rect;
|
||||
HRESULT hr;
|
||||
@@ -750,6 +760,7 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
||||
(LONG)(rectLeft + w),
|
||||
(LONG)(rectTop + h),
|
||||
};
|
||||
|
||||
if (GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||
originRect.left = (topSurface_width / 2) - (GRAPHICS_FS_ORIGINAL_WIDTH / 2);
|
||||
originRect.top = (topSurface_height / 2) - (GRAPHICS_FS_ORIGINAL_HEIGHT / 2);
|
||||
@@ -757,6 +768,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
||||
originRect.bottom = originRect.top + GRAPHICS_FS_ORIGINAL_HEIGHT;
|
||||
}
|
||||
|
||||
bool duplicate = false;
|
||||
RECT originRect2 = originRect;
|
||||
if (cfg::SCREENRESIZE->enable_screen_resize) {
|
||||
auto& scene = cfg::SCREENRESIZE->scene_settings[cfg::SCREENRESIZE->screen_resize_current_scene];
|
||||
if (scene.duplicate == cfg::ScreenDuplicateMode::CopyLeft) {
|
||||
duplicate = true;
|
||||
originRect2.right = originRect.left;
|
||||
originRect2.left = (LONG)(originRect2.left - (originRect.right - originRect.left));
|
||||
} else if (scene.duplicate == cfg::ScreenDuplicateMode::CopyRight) {
|
||||
duplicate = true;
|
||||
originRect2.left = originRect.right;
|
||||
originRect2.right = (LONG)(originRect2.left + (originRect.right - originRect.left));
|
||||
}
|
||||
}
|
||||
|
||||
// log_misc(
|
||||
// "graphics::d3d9", "originRect: {} {} {} {}",
|
||||
// originRect.left, originRect.top, originRect.right, originRect.bottom);
|
||||
@@ -768,9 +794,21 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
||||
if (hr != D3D_OK) {
|
||||
log_warning(
|
||||
"graphics::d3d9",
|
||||
"SurfaceHook - StretchRect backbuffer failed, rect: {} {} {} {}",
|
||||
"SurfaceHook - StretchRect backbuffer failed for main image, rect: {} {} {} {}",
|
||||
originRect.left, originRect.top, originRect.right, originRect.bottom);
|
||||
}
|
||||
if (duplicate) {
|
||||
hr = pReal->StretchRect(
|
||||
backbuffer, nullptr,
|
||||
topSurface, &originRect2,
|
||||
D3DTEXF_LINEAR);
|
||||
if (hr != D3D_OK) {
|
||||
log_warning(
|
||||
"graphics::d3d9",
|
||||
"SurfaceHook - StretchRect backbuffer failed for the duplicate, rect: {} {} {} {}",
|
||||
originRect2.left, originRect2.top, originRect2.right, originRect2.bottom);
|
||||
}
|
||||
}
|
||||
topSurface->UnlockRect();
|
||||
|
||||
// phase 2 - viewport calculation - do the actual zoom / offset math
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <ntstatus.h>
|
||||
|
||||
#include "avs/game.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/utils.h"
|
||||
@@ -22,6 +23,7 @@ static decltype(GetLocaleInfoEx) *GetLocaleInfoEx_orig = nullptr;
|
||||
|
||||
#ifdef SPICE64
|
||||
static decltype(GetSystemDefaultLCID) *GetSystemDefaultLCID_orig = nullptr;
|
||||
static decltype(IsDBCSLeadByte) *IsDBCSLeadByte_orig = nullptr;
|
||||
#endif
|
||||
|
||||
static NTSTATUS NTAPI RtlMultiByteToUnicodeN_hook(
|
||||
@@ -162,6 +164,17 @@ static int WINAPI GetLocaleInfoEx_hook (
|
||||
return GetLocaleInfoEx_orig(lpLocaleName, LCType, lpLCData, cchData);
|
||||
}
|
||||
|
||||
#ifdef SPICE64
|
||||
|
||||
static BOOL WINAPI IsDBCSLeadByte_hook (
|
||||
BYTE TestChar
|
||||
)
|
||||
{
|
||||
return IsDBCSLeadByteEx(CODEPAGE_SHIFT_JIS, TestChar);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void hooks::lang::early_init() {
|
||||
log_info("hooks::lang", "early initialization");
|
||||
|
||||
@@ -189,6 +202,19 @@ void hooks::lang::early_init() {
|
||||
GetLocaleInfoEx_hook,
|
||||
&GetLocaleInfoEx_orig);
|
||||
}
|
||||
|
||||
#ifdef SPICE64
|
||||
// for TDJ subscreen search keyboard
|
||||
if (avs::game::is_model("LDJ") && games::iidx::TDJ_MODE) {
|
||||
log_info("hooks::lang", "hooking IsDBCSLeadByte");
|
||||
detour::trampoline_try(
|
||||
"kernel32.dll",
|
||||
"IsDBCSLeadByte",
|
||||
IsDBCSLeadByte_hook,
|
||||
&IsDBCSLeadByte_orig);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void hooks::lang::init() {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <assert.h>
|
||||
#include <shlwapi.h>
|
||||
#include <cfg/configurator.h>
|
||||
|
||||
@@ -20,7 +21,9 @@
|
||||
#include "cfg/screen_resize.h"
|
||||
#include "easrv/easrv.h"
|
||||
#include "external/cardio/cardio_runner.h"
|
||||
#ifndef NO_SCARD
|
||||
#include "external/scard/scard.h"
|
||||
#endif
|
||||
#include "games/game.h"
|
||||
#include "games/io.h"
|
||||
#include "games/bbc/bbc.h"
|
||||
@@ -263,7 +266,8 @@ int main_implementation(int argc, char *argv[]) {
|
||||
|
||||
// detect model used to load option overrides
|
||||
auto options_version = launcher::detect_gameversion(
|
||||
LAUNCHER_OPTIONS->at(launcher::Options::PathToEa3Config).value
|
||||
LAUNCHER_OPTIONS->at(launcher::Options::PathToEa3Config).value,
|
||||
LAUNCHER_OPTIONS->at(launcher::Options::PathToBootstrap).value
|
||||
);
|
||||
if (!options_version.model.empty() && options_version.model.size() < 4) {
|
||||
if (options_version.dest.size() == 1) {
|
||||
@@ -297,25 +301,13 @@ int main_implementation(int argc, char *argv[]) {
|
||||
cfg_run = true;
|
||||
}
|
||||
|
||||
// -ea, but ignored if -url is set
|
||||
if (options[launcher::Options::EAmusementEmulation].value_bool() &&
|
||||
options[launcher::Options::ServiceURL].is_active() &&
|
||||
!cfg::CONFIGURATOR_STANDALONE) {
|
||||
log_fatal(
|
||||
"launcher",
|
||||
"BAD EAMUSE SETTINGS ERROR\n\n\n"
|
||||
"-------------------------------------------------------------------\n"
|
||||
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
|
||||
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
|
||||
"A service URL is set **AND** E-Amusement emulation is enabled.\n"
|
||||
"Either remove the service URL, or disable E-Amusement emulation.\n"
|
||||
"Otherwise you may experience problems logging in.\n"
|
||||
"-------------------------------------------------------------------\n\n\n"
|
||||
);
|
||||
}
|
||||
if (options[launcher::Options::EAmusementEmulation].value_bool()) {
|
||||
!options[launcher::Options::ServiceURL].is_active()) {
|
||||
avs::ea3::URL_SLASH = 1;
|
||||
easrv_port = 8080;
|
||||
}
|
||||
|
||||
if (options[launcher::Options::SmartEAmusement].value_bool()) {
|
||||
easrv_smart = true;
|
||||
}
|
||||
@@ -471,14 +463,26 @@ int main_implementation(int argc, char *argv[]) {
|
||||
if (options[launcher::Options::IIDXCameraOrderFlip].value_bool()) {
|
||||
games::iidx::FLIP_CAMS = true;
|
||||
}
|
||||
|
||||
// IIDX CONNECT_CAMERA logic here for cases where user is running without -iidx module
|
||||
// for now, we assume that user may be running on a cab
|
||||
// (games::iidx::DISABLE_CAMS starts out as false unless user overrides)
|
||||
// we will check again in IIDX module with a different default
|
||||
assert(!games::iidx::DISABLE_CAMS.has_value());
|
||||
if (options[launcher::Options::IIDXDisableCameras].value_bool()) {
|
||||
games::iidx::DISABLE_CAMS = true;
|
||||
}
|
||||
if (options[launcher::Options::IIDXCabCamAccess].is_active() &&
|
||||
options[launcher::Options::IIDXCabCamAccess].value_text() == "off") {
|
||||
games::iidx::DISABLE_CAMS = true;
|
||||
}
|
||||
if (options[launcher::Options::IIDXCamHook].value_bool()) {
|
||||
games::iidx::TDJ_CAMERA = true;
|
||||
// Disable legacy behaviour to avoid conflict
|
||||
games::iidx::DISABLE_CAMS = true;
|
||||
}
|
||||
// CONNECT_CAMERA env var will be set once logging is enabled
|
||||
|
||||
if (options[launcher::Options::IIDXCamHookOverride].is_active()) {
|
||||
games::iidx::TDJ_CAMERA_OVERRIDE = options[launcher::Options::IIDXCamHookOverride].value_text();
|
||||
}
|
||||
@@ -816,6 +820,7 @@ int main_implementation(int argc, char *argv[]) {
|
||||
for (auto &sextet : options[launcher::Options::SextetStreamPort].values_text()) {
|
||||
sextet_devices.emplace_back(sextet);
|
||||
}
|
||||
#ifndef NO_SCARD
|
||||
if (options[launcher::Options::HIDSmartCard].value_bool()) {
|
||||
WINSCARD_CONFIG.cardinfo_callback = eamuse_scard_callback;
|
||||
scard_threadstart();
|
||||
@@ -835,6 +840,7 @@ int main_implementation(int argc, char *argv[]) {
|
||||
WINSCARD_CONFIG.add_padding_to_felica = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (options[launcher::Options::CardIOHIDReaderOrderFlip].value_bool()) {
|
||||
CARDIO_RUNNER_FLIP = true;
|
||||
}
|
||||
@@ -938,6 +944,11 @@ int main_implementation(int argc, char *argv[]) {
|
||||
}
|
||||
if (options[launcher::Options::DisableAudioHooks].value_bool()) {
|
||||
hooks::audio::ENABLED = false;
|
||||
deferredlogs::defer_error_messages({
|
||||
"audio hooks are forcibly disabled by user (-audiohookdisable)",
|
||||
" having hooks disabled means some required audio fixes are not being applied",
|
||||
" if you have audio-related crashes, you should try again after clearing this option"
|
||||
});
|
||||
}
|
||||
if (options[launcher::Options::spice2x_DisableVolumeHook].value_bool()) {
|
||||
hooks::audio::VOLUME_HOOK_ENABLED = false;
|
||||
@@ -1200,15 +1211,28 @@ int main_implementation(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
// log
|
||||
#ifdef SPICE64
|
||||
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
||||
#elif SPICE32_LARGE_ADDRESS_AWARE
|
||||
log_info("launcher", "SpiceTools Bootstrap (x32) (Large Address Aware) (spice2x)");
|
||||
#ifndef SPICE_LINUX
|
||||
#ifdef SPICE64
|
||||
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x)");
|
||||
#elif SPICE32_LARGE_ADDRESS_AWARE
|
||||
log_info("launcher", "SpiceTools Bootstrap (x32 - Large Address Aware) (spice2x)");
|
||||
#else
|
||||
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
||||
#endif
|
||||
#else
|
||||
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x)");
|
||||
#ifdef SPICE64
|
||||
log_info("launcher", "SpiceTools Bootstrap (x64) (spice2x) for Linux");
|
||||
#else
|
||||
log_info("launcher", "SpiceTools Bootstrap (x32) (spice2x) for Linux");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
log_info("launcher", "{}", VERSION_STRING);
|
||||
|
||||
// note: distribution of modified version of this software without providing source is GPLv3 license violation.
|
||||
log_info("launcher", "spice2x is free & open source; if you paid money for it, you got scammed");
|
||||
log_info("launcher", "visit https://spice2x.github.io to download the latest version for free");
|
||||
|
||||
// log command line arguments
|
||||
std::ostringstream arguments;
|
||||
for (auto &root_option : options) {
|
||||
@@ -1252,18 +1276,19 @@ int main_implementation(int argc, char *argv[]) {
|
||||
for (const auto &option : options) {
|
||||
if (option.conflicting && option.get_definition().type != OptionType::Bool) {
|
||||
conflicts += 1;
|
||||
const auto& value = option.get_definition().sensitive ? "*****" : option.value;
|
||||
if (launcher::USE_CMD_OVERRIDE) {
|
||||
log_warning(
|
||||
"launcher",
|
||||
"multiple values for -{}, command line args take precedence: {}",
|
||||
option.get_definition().name,
|
||||
option.value);
|
||||
value);
|
||||
} else {
|
||||
log_warning(
|
||||
"launcher",
|
||||
"multiple values for -{}, spicecfg values take precedence: {}",
|
||||
option.get_definition().name,
|
||||
option.value);
|
||||
value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1303,7 +1328,7 @@ int main_implementation(int argc, char *argv[]) {
|
||||
|
||||
// SDVXFullscreenLandscape disabled due to it messing with in-game camera angle
|
||||
// FullscreenOrientationFlip continues to live on, however.
|
||||
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool()) {
|
||||
if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
|
||||
log_fatal("launcher", "-sdvxlandscape removed due to a camera bug in SDVX!");
|
||||
}
|
||||
// if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
|
||||
@@ -1318,8 +1343,15 @@ int main_implementation(int argc, char *argv[]) {
|
||||
GRAPHICS_FS_ORIENTATION_SWAP = true;
|
||||
}
|
||||
|
||||
if (games::iidx::DISABLE_CAMS.has_value() &&
|
||||
games::iidx::DISABLE_CAMS.value() &&
|
||||
!cfg::CONFIGURATOR_STANDALONE) {
|
||||
log_misc("launcher", "CONNECT_CAMERA env var set to 0");
|
||||
SetEnvironmentVariable("CONNECT_CAMERA", "0");
|
||||
}
|
||||
|
||||
// deleted options
|
||||
if (options[launcher::Options::OpenKFControl].value_bool()) {
|
||||
if (options[launcher::Options::OpenKFControl].value_bool() && !cfg::CONFIGURATOR_STANDALONE) {
|
||||
log_fatal("launcher", "KFControl has been removed from spice2x; please use an older version.");
|
||||
}
|
||||
if (options[launcher::Options::VREnable].value_bool()) {
|
||||
@@ -1647,6 +1679,14 @@ int main_implementation(int argc, char *argv[]) {
|
||||
attach_io = true;
|
||||
attach_mfc = true;
|
||||
break;
|
||||
|
||||
// Mahjong Fight Club - 2025?
|
||||
// they removed allinone.dll and moved i/o into system.dll
|
||||
} else if (check_dll("system.dll") && fileutils::file_exists("data/mfc.ini")) {
|
||||
avs::game::DLL_NAME = "system.dll";
|
||||
attach_io = true;
|
||||
attach_mfc = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// FutureTomTom
|
||||
@@ -1791,7 +1831,7 @@ int main_implementation(int argc, char *argv[]) {
|
||||
// usage error
|
||||
if (!cfg::CONFIGURATOR_STANDALONE
|
||||
&& (!CHECK_DLL_IGNORE_ARCH)) {
|
||||
log_fatal(
|
||||
log_warning(
|
||||
"launcher",
|
||||
"module auto detection failed!\n\n"
|
||||
"This usually means one of the following:\n\n"
|
||||
@@ -1799,6 +1839,8 @@ int main_implementation(int argc, char *argv[]) {
|
||||
" 2. XML files in prop directory are malformed or missing, or\n"
|
||||
" 3. You passed in invalid options (usually, path overrides like -exec)\n\n"
|
||||
);
|
||||
|
||||
log_fatal("launcher", "module auto detection failed, see log.txt for troubleshooting");
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2314,8 +2356,10 @@ int main_implementation(int argc, char *argv[]) {
|
||||
// debug hook
|
||||
debughook::detach();
|
||||
|
||||
#ifndef NO_SCARD
|
||||
// scard
|
||||
scard_fini();
|
||||
#endif
|
||||
|
||||
// stop reader thread in case it was running
|
||||
stop_reader_thread();
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#ifdef NO_SCARD
|
||||
#define WITH_SCARD 0
|
||||
#else
|
||||
#define WITH_SCARD 1
|
||||
#endif
|
||||
|
||||
static const std::vector<std::string> CATEGORY_ORDER_API = {
|
||||
"SpiceCompanion and API",
|
||||
"API (Serial)",
|
||||
@@ -450,13 +456,30 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.category = "Game Options (Advanced)",
|
||||
},
|
||||
{
|
||||
.title = "IIDX Disable Cameras",
|
||||
// IIDXDisableCameras
|
||||
.title = "IIDX Disable Cameras (DEPRECATED - no longer needed)",
|
||||
.name = "iidxdisablecams",
|
||||
.desc = "Disables cameras",
|
||||
.type = OptionType::Bool,
|
||||
.hidden = true,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options",
|
||||
},
|
||||
{
|
||||
// IIDXCabCamAccess
|
||||
.title = "IIDX Use Official AC Cams",
|
||||
.name = "iidxcabcams",
|
||||
.desc = "For IIDX25+, allow direct access to cameras from real arcade cabinets. "
|
||||
"Only turn this on if you have OFFICIAL arcade cameras connected to the correct USB ports. Default: auto",
|
||||
.type = OptionType::Enum,
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
.elements = {
|
||||
{"auto", ""},
|
||||
{"off", ""},
|
||||
{"on", ""}
|
||||
},
|
||||
},
|
||||
{
|
||||
// IIDXCamHook
|
||||
.title = "IIDX Cam Hook",
|
||||
@@ -491,10 +514,10 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.display_name = "iidxcamhookoffset",
|
||||
.aliases = "iidxcamhookoffset",
|
||||
.desc = "Override DLL offsets for camera hook; "
|
||||
"format: 4 hex values separated by commas "
|
||||
"(offset_hook_a, offset_hook_b, offset_textures, offset_d3d_device)",
|
||||
"format: 5 hex values separated by commas "
|
||||
"(offset_hook_a, offset_textures, offset_camera_manager, offset_d3d_device, offset_afp_texture)",
|
||||
.type = OptionType::Text,
|
||||
.setting_name = "0x5817a0,0x5ea3b0,0x6fffbd8,0xe0",
|
||||
.setting_name = "0x5817a0,0x6fffbd8,0xbbae40,0xe0,0x30",
|
||||
.game_name = "Beatmania IIDX",
|
||||
.category = "Game Options (Advanced)",
|
||||
},
|
||||
@@ -1385,21 +1408,27 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
.name = "scard",
|
||||
.desc = "Detects and uses HID smart card readers for card input. Developed for ACR122U reader",
|
||||
.type = OptionType::Bool,
|
||||
.hidden = !WITH_SCARD,
|
||||
.category = "NFC Card Readers",
|
||||
.disabled = !WITH_SCARD,
|
||||
},
|
||||
{
|
||||
.title = "HID SmartCard Order Flip",
|
||||
.name = "scardflip",
|
||||
.desc = "Flips the order of detection for P1/P2",
|
||||
.type = OptionType::Bool,
|
||||
.hidden = !WITH_SCARD,
|
||||
.category = "NFC Card Readers",
|
||||
.disabled = !WITH_SCARD,
|
||||
},
|
||||
{
|
||||
.title = "HID SmartCard Order Toggle",
|
||||
.name = "scardtoggle",
|
||||
.desc = "Toggles reader between P1/P2 using the NumLock key state",
|
||||
.type = OptionType::Bool,
|
||||
.hidden = !WITH_SCARD,
|
||||
.category = "NFC Card Readers",
|
||||
.disabled = !WITH_SCARD,
|
||||
},
|
||||
{
|
||||
// HIDSmartCardIdConvert
|
||||
@@ -1413,12 +1442,14 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
||||
"For example, abcd56780123 is converted to e00401abcd567801 on card in. This results in different card numbers so "
|
||||
"be careful when connecting to servers!",
|
||||
.type = OptionType::Enum,
|
||||
.hidden = !WITH_SCARD,
|
||||
.category = "NFC Card Readers",
|
||||
.elements = {
|
||||
{"legacy", "Use cards as-is"},
|
||||
{"fix", "Fix bad cards only"},
|
||||
{"all", "Force all cards"},
|
||||
},
|
||||
.disabled = !WITH_SCARD,
|
||||
},
|
||||
{
|
||||
// SextetStreamPort
|
||||
@@ -2608,8 +2639,19 @@ std::vector<Option> launcher::merge_options(
|
||||
return merged;
|
||||
}
|
||||
|
||||
std::string launcher::detect_bootstrap_release_code() {
|
||||
std::string bootstrap_path = "prop/bootstrap.xml";
|
||||
std::string launcher::detect_bootstrap_release_code(const std::string& bootstrap_user) {
|
||||
std::string bootstrap_path;
|
||||
|
||||
if (!bootstrap_user.empty()) {
|
||||
bootstrap_path = bootstrap_user;
|
||||
} else if (fileutils::file_exists("prop/bootstrap.xml")) {
|
||||
bootstrap_path = "prop/bootstrap.xml";
|
||||
}
|
||||
|
||||
if (bootstrap_path.empty()) {
|
||||
log_warning("options", "unable to detect bootstrap.xml file");
|
||||
return "";
|
||||
}
|
||||
|
||||
// load XML
|
||||
tinyxml2::XMLDocument bootstrap;
|
||||
@@ -2632,7 +2674,7 @@ std::string launcher::detect_bootstrap_release_code() {
|
||||
return "";
|
||||
}
|
||||
|
||||
static launcher::GameVersion detect_gameversion_ident() {
|
||||
static launcher::GameVersion detect_gameversion_ident(const std::string& bootstrap_user) {
|
||||
|
||||
// detect ea3-ident path
|
||||
std::string ident_path;
|
||||
@@ -2678,7 +2720,7 @@ static launcher::GameVersion detect_gameversion_ident() {
|
||||
auto node_ext = node_soft->FirstChildElement("ext");
|
||||
if (node_ext) {
|
||||
version.ext = node_ext->GetText();
|
||||
auto bootstrap_ext = launcher::detect_bootstrap_release_code();
|
||||
auto bootstrap_ext = launcher::detect_bootstrap_release_code(bootstrap_user);
|
||||
if (version.ext.size() != 10 && bootstrap_ext.size() == 10) {
|
||||
version.ext = bootstrap_ext;
|
||||
} else if (bootstrap_ext.size() == 10) {
|
||||
@@ -2714,8 +2756,7 @@ static launcher::GameVersion detect_gameversion_ident() {
|
||||
return launcher::GameVersion();
|
||||
}
|
||||
|
||||
launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user) {
|
||||
|
||||
launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user, const std::string& bootstrap_user) {
|
||||
// detect ea3-config path
|
||||
std::string ea3_path;
|
||||
if (!ea3_user.empty()) {
|
||||
@@ -2729,7 +2770,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
||||
}
|
||||
if (ea3_path.empty()) {
|
||||
log_warning("options", "unable to detect EA3 configuration file");
|
||||
return detect_gameversion_ident();
|
||||
return detect_gameversion_ident(bootstrap_user);
|
||||
}
|
||||
|
||||
// load XML
|
||||
@@ -2769,7 +2810,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
||||
if (ea3_config.Parse(xml_str.c_str()) != tinyxml2::XML_SUCCESS) {
|
||||
// if we still failed, give up
|
||||
log_warning("options", "unable to parse fixed xml");
|
||||
return detect_gameversion_ident();
|
||||
return detect_gameversion_ident(bootstrap_user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2800,7 +2841,7 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
||||
auto node_ext = node_soft->FirstChildElement("ext");
|
||||
if (node_ext) {
|
||||
version.ext = node_ext->GetText();
|
||||
auto bootstrap_ext = launcher::detect_bootstrap_release_code();
|
||||
auto bootstrap_ext = launcher::detect_bootstrap_release_code(bootstrap_user);
|
||||
if (version.ext.size() != 10 && bootstrap_ext.size() == 10) {
|
||||
version.ext = bootstrap_ext;
|
||||
} else if (bootstrap_ext.size() == 10) {
|
||||
@@ -2833,5 +2874,5 @@ launcher::GameVersion launcher::detect_gameversion(const std::string &ea3_user)
|
||||
|
||||
// error
|
||||
log_warning("options", "unable to find /ea3/soft/model in {}", ea3_path);
|
||||
return detect_gameversion_ident();
|
||||
return detect_gameversion_ident(bootstrap_user);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace launcher {
|
||||
LoadIIDXModule,
|
||||
IIDXCameraOrderFlip,
|
||||
IIDXDisableCameras,
|
||||
IIDXCabCamAccess,
|
||||
IIDXCamHook,
|
||||
IIDXCamHookRatio,
|
||||
IIDXCamHookOverride,
|
||||
@@ -279,6 +280,6 @@ namespace launcher {
|
||||
std::string ext;
|
||||
};
|
||||
|
||||
std::string detect_bootstrap_release_code();
|
||||
GameVersion detect_gameversion(const std::string& ea3_user);
|
||||
std::string detect_bootstrap_release_code(const std::string& bootstrap_user);
|
||||
GameVersion detect_gameversion(const std::string& ea3_user, const std::string& bootstrap_user);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "signal.h"
|
||||
|
||||
#include <future>
|
||||
#include <exception>
|
||||
|
||||
#include <windows.h>
|
||||
@@ -174,6 +175,9 @@ static LONG WINAPI TopLevelExceptionFilter(struct _EXCEPTION_POINTERS *Exception
|
||||
log_warning("signal", "minidump creation function not available, skipping");
|
||||
}
|
||||
|
||||
// this will stall all UI threads for this process
|
||||
show_popup_for_crash();
|
||||
|
||||
log_fatal("signal", "end");
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace wintouchemu {
|
||||
bool FORCE = false;
|
||||
bool INJECT_MOUSE_AS_WM_TOUCH = false;
|
||||
bool LOG_FPS = false;
|
||||
bool ADD_TOUCH_FLAG_PRIMARY = false;
|
||||
|
||||
static inline bool is_emu_enabled() {
|
||||
return FORCE || !is_touch_available("wintouchemu::is_emu_enabled") || GRAPHICS_SHOW_CURSOR;
|
||||
@@ -187,16 +188,28 @@ namespace wintouchemu {
|
||||
switch (touch_event->type) {
|
||||
case TOUCH_DOWN:
|
||||
if (valid) {
|
||||
if (ADD_TOUCH_FLAG_PRIMARY) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
|
||||
}
|
||||
|
||||
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
|
||||
}
|
||||
break;
|
||||
case TOUCH_MOVE:
|
||||
if (valid) {
|
||||
if (ADD_TOUCH_FLAG_PRIMARY) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
|
||||
}
|
||||
|
||||
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
|
||||
}
|
||||
break;
|
||||
case TOUCH_UP:
|
||||
// don't check valid so that this touch ID can be released
|
||||
if (ADD_TOUCH_FLAG_PRIMARY) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
|
||||
}
|
||||
|
||||
touch_input->dwFlags |= TOUCHEVENTF_UP;
|
||||
break;
|
||||
}
|
||||
@@ -238,16 +251,28 @@ namespace wintouchemu {
|
||||
switch (mouse_state.touch_event) {
|
||||
case TOUCHEVENTF_DOWN:
|
||||
if (valid) {
|
||||
if (ADD_TOUCH_FLAG_PRIMARY) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
|
||||
}
|
||||
|
||||
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
|
||||
}
|
||||
break;
|
||||
case TOUCHEVENTF_MOVE:
|
||||
if (valid) {
|
||||
if (ADD_TOUCH_FLAG_PRIMARY) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
|
||||
}
|
||||
|
||||
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
|
||||
}
|
||||
break;
|
||||
case TOUCHEVENTF_UP:
|
||||
// don't check valid so that this touch ID can be released
|
||||
if (ADD_TOUCH_FLAG_PRIMARY) {
|
||||
touch_input->dwFlags |= TOUCHEVENTF_PRIMARY;
|
||||
}
|
||||
|
||||
touch_input->dwFlags |= TOUCHEVENTF_UP;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace wintouchemu {
|
||||
extern bool FORCE;
|
||||
extern bool INJECT_MOUSE_AS_WM_TOUCH;
|
||||
extern bool LOG_FPS;
|
||||
extern bool ADD_TOUCH_FLAG_PRIMARY;
|
||||
|
||||
void hook(const char *window_title, HMODULE module = nullptr, int delay_in_s=0);
|
||||
void hook_title_ends(
|
||||
|
||||
@@ -270,13 +270,14 @@ void overlay::SpiceOverlay::init() {
|
||||
ImFontConfig config {};
|
||||
config.MergeMode = true;
|
||||
|
||||
log_misc("overlay", "loading fonts, failures are not fatal");
|
||||
add_font("simsun.ttc", &config, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesCyrillic());
|
||||
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesCyrillic());
|
||||
add_font("meiryu.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
||||
add_font("meiryo.ttc", &config, io.Fonts->GetGlyphRangesJapanese());
|
||||
add_font("gulim.ttc", &config, io.Fonts->GetGlyphRangesKorean());
|
||||
add_font("cordia.ttc", &config, io.Fonts->GetGlyphRangesThai());
|
||||
add_font("arial.ttc", &config, io.Fonts->GetGlyphRangesVietnamese());
|
||||
add_font("cordia.ttf", &config, io.Fonts->GetGlyphRangesThai());
|
||||
add_font("arial.ttf", &config, io.Fonts->GetGlyphRangesVietnamese());
|
||||
|
||||
// add special font
|
||||
if (avs::game::is_model("LDJ")) {
|
||||
|
||||
@@ -556,9 +556,16 @@ namespace overlay::windows {
|
||||
}
|
||||
|
||||
// disclaimer
|
||||
// note: distribution of modified version of this software without providing source is GPLv3 license violation.
|
||||
ImGui::TextColored(
|
||||
ImVec4(1, 0.5f, 0.5f, 1.f),
|
||||
"Do NOT stream or upload game data anywhere public! Support arcades when you can. Thanks.");
|
||||
"spice2x is free & open source; if you paid money for it, you got scammed.");
|
||||
if (cfg::CONFIGURATOR_STANDALONE) {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::TextLink(PROJECT_URL)) {
|
||||
launch_shell(PROJECT_URL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Config::build_buttons(const std::string &name, std::vector<Button> *buttons, int min, int max) {
|
||||
@@ -2821,7 +2828,10 @@ namespace overlay::windows {
|
||||
std::string current_item = option.value_text();
|
||||
for (auto &element : definition.elements) {
|
||||
if (element.first == current_item) {
|
||||
current_item += fmt::format(" ({})", element.second);
|
||||
if (!element.second.empty()) {
|
||||
current_item += fmt::format(" ({})", element.second);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (current_item.empty()) {
|
||||
@@ -2829,11 +2839,12 @@ namespace overlay::windows {
|
||||
}
|
||||
if (ImGui::BeginCombo("##combo", current_item.c_str(), 0)) {
|
||||
for (auto &element : definition.elements) {
|
||||
bool selected = current_item == element.first;
|
||||
std::string label = element.first;
|
||||
if (!element.second.empty()) {
|
||||
label += fmt::format(" ({})", element.second);
|
||||
}
|
||||
|
||||
bool selected = current_item == label;
|
||||
if (ImGui::Selectable(label.c_str(), selected)) {
|
||||
this->options_dirty = true;
|
||||
option.value = element.first;
|
||||
@@ -2904,13 +2915,20 @@ namespace overlay::windows {
|
||||
}
|
||||
|
||||
void Config::build_about() {
|
||||
#ifndef SPICE_LINUX
|
||||
ImGui::TextUnformatted(std::string(
|
||||
"spice2x (a fork of SpiceTools)\r\n"
|
||||
"=========================\r\n" +
|
||||
to_string(VERSION_STRING)).c_str());
|
||||
#else
|
||||
ImGui::TextUnformatted(std::string(
|
||||
"spice2x (a fork of SpiceTools) for Linux\r\n"
|
||||
"=========================\r\n" +
|
||||
to_string(VERSION_STRING)).c_str());
|
||||
#endif
|
||||
|
||||
ImGui::TextUnformatted("");
|
||||
if (ImGui::Button(PROJECT_URL)) {
|
||||
if (ImGui::TextLink(PROJECT_URL)) {
|
||||
launch_shell(PROJECT_URL);
|
||||
}
|
||||
|
||||
@@ -2971,6 +2989,7 @@ namespace overlay::windows {
|
||||
|
||||
void Config::build_menu(int *game_selected) {
|
||||
bool about_popup = false;
|
||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.14f, 0.14f, 0.14f, 1.0f));
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
|
||||
// [spice2x]
|
||||
@@ -3031,6 +3050,8 @@ namespace overlay::windows {
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor(); // ImGuiCol_PopupBg
|
||||
|
||||
// workaround for popups triggered by menu, see https://github.com/ocornut/imgui/issues/331
|
||||
if (about_popup) {
|
||||
ImGui::OpenPopup("About##topbarpopup");
|
||||
|
||||
@@ -288,6 +288,12 @@ namespace overlay::windows {
|
||||
this->reload_local_patches();
|
||||
}
|
||||
|
||||
if (avs::game::DLL_NAME == "kamunity.dll") {
|
||||
ImGui::TextColored(ImVec4(1.f, 0.f, 0.f, 1.f), "Patches are not supported for Unity-based games.");
|
||||
ImGui::TextColored(ImVec4(1.f, 0.f, 0.f, 1.f), "Instead, look for downloads of pre-patched DLLs.");
|
||||
return;
|
||||
}
|
||||
|
||||
// game code info
|
||||
std::string identifiers;
|
||||
identifiers += avs::game::get_identifier() + "\n\n";
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace overlay::windows {
|
||||
scene.offset_y = 0;
|
||||
scene.scale_x = 1.f;
|
||||
scene.scale_y = 1.f;
|
||||
scene.duplicate = cfg::ScreenDuplicateMode::None;
|
||||
}
|
||||
|
||||
cfg::SCREENRESIZE->enable_window_resize = false;
|
||||
@@ -149,6 +150,17 @@ namespace overlay::windows {
|
||||
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||
}
|
||||
|
||||
static const char* dupe_items[] = { "None", "Copy Left", "Copy Right" };
|
||||
ImGui::Combo(
|
||||
"Duplicate",
|
||||
reinterpret_cast<int *>(&scene.duplicate),
|
||||
dupe_items,
|
||||
ARRAYSIZE(dupe_items));
|
||||
ImGui::SameLine();
|
||||
ImGui::HelpMarker(
|
||||
"Show an identical copy of the image on the left or right, allowing you to achieve "
|
||||
"wrap-around effect when an offset is set.");
|
||||
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
|
||||
@@ -347,40 +347,38 @@ void rawinput::RawInputManager::devices_scan_rawinput(RAWINPUTDEVICELIST *device
|
||||
if (hid_handle != INVALID_HANDLE_VALUE) {
|
||||
|
||||
// check manufacturer string
|
||||
std::wstring man_ws;
|
||||
std::string man_ws;
|
||||
wchar_t man_str_buffer[256] {};
|
||||
if (HidD_GetManufacturerString(hid_handle, man_str_buffer, sizeof(man_str_buffer))) {
|
||||
man_ws = std::wstring(man_str_buffer);
|
||||
man_ws = wchar_to_u8(man_str_buffer);
|
||||
}
|
||||
|
||||
// get product string
|
||||
std::wstring prod_ws;
|
||||
std::string prod_ws;
|
||||
wchar_t prod_str_buffer[256] {};
|
||||
if (HidD_GetProductString(hid_handle, prod_str_buffer, sizeof(prod_str_buffer))) {
|
||||
prod_ws = std::wstring(prod_str_buffer);
|
||||
prod_ws = wchar_to_u8(prod_str_buffer);
|
||||
}
|
||||
|
||||
// For Bluetooth LE HID devices (e.g., newer Xbox controllers) HidD_GetProductString
|
||||
// and HidD_GetManufacturerString will return blank strings.
|
||||
// https://docs.microsoft.com/en-us/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html
|
||||
if (man_ws.empty() && prod_ws.empty()) {
|
||||
prod_ws = s2ws(device_description);
|
||||
prod_ws = device_description;
|
||||
}
|
||||
|
||||
// build desc string
|
||||
std::wstring desc_ws;
|
||||
std::string desc_ws;
|
||||
if (string_begins_with(prod_ws, man_ws)) {
|
||||
desc_ws = prod_ws;
|
||||
} else {
|
||||
desc_ws = man_ws;
|
||||
if (!man_ws.empty() && !prod_ws.empty()) {
|
||||
desc_ws += L" ";
|
||||
desc_ws += " ";
|
||||
}
|
||||
desc_ws += prod_ws;
|
||||
}
|
||||
|
||||
// convert to normal string
|
||||
new_device.desc = ws2s(desc_ws);
|
||||
new_device.desc = desc_ws;
|
||||
|
||||
// get attributes
|
||||
if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
|
||||
@@ -1148,7 +1146,7 @@ std::string rawinput::RawInputManager::rawinput_get_device_description(const raw
|
||||
|
||||
// get property
|
||||
DWORD desc_size = 0;
|
||||
if (SetupDiGetDeviceRegistryProperty(
|
||||
if (SetupDiGetDeviceRegistryPropertyW(
|
||||
devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, nullptr, 0, &desc_size))
|
||||
{
|
||||
continue;
|
||||
@@ -1160,14 +1158,14 @@ std::string rawinput::RawInputManager::rawinput_get_device_description(const raw
|
||||
// allocate buffer
|
||||
auto desc_data = std::make_unique<BYTE[]>(desc_size);
|
||||
|
||||
if (!SetupDiGetDeviceRegistryProperty(
|
||||
if (!SetupDiGetDeviceRegistryPropertyW(
|
||||
devinfo, &devinfo_data, SPDRP_DEVICEDESC, nullptr, desc_data.get(), desc_size, nullptr))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// kthxbye
|
||||
device_description = std::string(reinterpret_cast<char *>(desc_data.get()));
|
||||
device_description = wchar_to_u8(reinterpret_cast<PWCHAR>(desc_data.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ developers when you can. Sources should be included, have fun!
|
||||
|
||||
spice2x fork maintainers:
|
||||
* sp2xdev team
|
||||
* the lab
|
||||
|
||||
SpiceTools original contributors:
|
||||
* cube, felix, dinsfire, nolm, s2, crazyredmachine (jotaro44), mon, nibs
|
||||
|
||||
@@ -49,8 +49,10 @@ namespace deferredlogs {
|
||||
|
||||
if (is_crash) {
|
||||
msg += " the game has crashed\n";
|
||||
msg += " share this entire log file with someone for troubleshooting (log.txt)\n";
|
||||
msg += " spice will also attempt to create a minidump (minidump.dmp)\n";
|
||||
msg += " * share this entire log file with someone for troubleshooting (log.txt)\n";
|
||||
msg += " * spice will also attempt to create a minidump (minidump.dmp)\n";
|
||||
msg += " minidump should only be shared with people you trust as it may contain\n";
|
||||
msg += " sensitive data (PCBID, card ID, etc)\n";
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace {
|
||||
{
|
||||
"msvcr100.dll",
|
||||
"Visual Studio 2010 (VC++ 10.0) SP1 Redistributable",
|
||||
"Download and install VisualCppRedist_AIO_x86_x64.exe from https://github.com/abbodi1406/vcredist/releases/latest",
|
||||
"Download and install from https://github.com/spice2x/spice2x.github.io/wiki/Visual-Cpp-Redistributable-Runtimes",
|
||||
},
|
||||
{
|
||||
"d3dx9_43.dll",
|
||||
|
||||
@@ -43,7 +43,8 @@ static inline void load_library_fail(const std::string &file_name, bool fatal) {
|
||||
" b. http://www.dependencywalker.com/ (for old OS) \n"
|
||||
, file_name) };
|
||||
if (fatal) {
|
||||
log_fatal("libutils", "{}", info_str);
|
||||
log_warning("libutils", "{}", info_str);
|
||||
log_fatal("libutils", "DLL failed to load: {}, see log.txt for troubleshooting", file_name);
|
||||
} else {
|
||||
log_warning("libutils", "{}", info_str);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
|
||||
#include "logging.h"
|
||||
#include "build/defs.h"
|
||||
#include "hooks/graphics/graphics.h"
|
||||
|
||||
std::string_view log_get_datetime() {
|
||||
return log_get_datetime(time(nullptr));
|
||||
@@ -12,3 +18,66 @@ std::string_view log_get_datetime(std::time_t now) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void show_popup(const std::string text) {
|
||||
static std::once_flag shown;
|
||||
std::call_once(shown, [text]() {
|
||||
|
||||
// minimize all windows
|
||||
// only needed because in multi-monitor full screen games, MessageBox fails to show above the game
|
||||
for (auto &hwnd : GRAPHICS_WINDOWS) {
|
||||
ShowWindow(hwnd, SW_FORCEMINIMIZE);
|
||||
}
|
||||
|
||||
// schedule a worker to terminate the game in 30 seconds in case user can't dismiss UI
|
||||
std::atomic_bool cancel_popup = false;
|
||||
auto worker = std::async(std::launch::async, [&cancel_popup]{
|
||||
for (int ms = 300; ms > 0; ms--) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (cancel_popup) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
launcher::stop_subsystems();
|
||||
launcher::kill();
|
||||
std::terminate();
|
||||
});
|
||||
|
||||
// MessageBox will block until user presses OK
|
||||
const std::string title = "spice2x (" + to_string(VERSION_STRING_CFG) + ")";
|
||||
MessageBox(
|
||||
nullptr,
|
||||
text.c_str(),
|
||||
title.c_str(),
|
||||
MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);
|
||||
|
||||
// cancel the worker since the user acknowledged the popup
|
||||
cancel_popup = true;
|
||||
});
|
||||
}
|
||||
|
||||
void show_popup_for_crash() {
|
||||
std::string text;
|
||||
text += "Game has crashed.\n\n";
|
||||
text += "Check log.txt and look for error messages near the end of file.\n\n";
|
||||
text += "Unsure what to do next?\n";
|
||||
text += " * update spice2x to the latest version\n";
|
||||
text += " * check the FAQ on spice2x github wiki\n";
|
||||
text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n";
|
||||
text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds.";
|
||||
show_popup(text);
|
||||
}
|
||||
|
||||
void show_popup_for_fatal_error(std::string message) {
|
||||
std::string text;
|
||||
text += "A fatal error was encountered. For details, check log.txt.\n\n";
|
||||
text += "----------------------------------------------------------\n";
|
||||
text += message;
|
||||
text += "----------------------------------------------------------\n\n";
|
||||
text += "Unsure what to do next?\n";
|
||||
text += " * update spice2x to the latest version\n";
|
||||
text += " * check the FAQ on spice2x github wiki\n";
|
||||
text += " * do NOT screenshot this, instead, share log.txt with someone and ask for help\n\n";
|
||||
text += "Press Enter, Esc, Alt+F4, or click OK to exit. Otherwise, game will close in 30 seconds.";
|
||||
show_popup(text);
|
||||
}
|
||||
@@ -71,20 +71,28 @@ struct fmt::formatter<fmt_hresult> {
|
||||
}
|
||||
};
|
||||
|
||||
void show_popup_for_crash();
|
||||
void show_popup_for_fatal_error(std::string message);
|
||||
|
||||
// misc log
|
||||
#define LOG_FORMAT(level, module, fmt_str, ...) fmt::format(FMT_COMPILE("{}" fmt_str "\n"), \
|
||||
fmt_log { std::time(nullptr), level, module }, ## __VA_ARGS__)
|
||||
|
||||
#define LOG_FORMAT_POPUP(module, fmt_str, ...) fmt::format(FMT_COMPILE("{}: " fmt_str "\n"), module, ## __VA_ARGS__)
|
||||
|
||||
#define log_misc(module, format_str, ...) logger::push( \
|
||||
LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY)
|
||||
|
||||
#define log_info(module, format_str, ...) logger::push( \
|
||||
LOG_FORMAT("I", module, format_str, ## __VA_ARGS__), logger::Style::DEFAULT)
|
||||
|
||||
#define log_warning(module, format_str, ...) logger::push( \
|
||||
LOG_FORMAT("W", module, format_str, ## __VA_ARGS__), logger::Style::YELLOW)
|
||||
|
||||
#define log_fatal(module, format_str, ...) { \
|
||||
logger::push(LOG_FORMAT("F", module, format_str, ## __VA_ARGS__), logger::Style::RED); \
|
||||
logger::push(LOG_FORMAT("F", "spice", "encountered a fatal error, you can close the window or press ctrl + c"), logger::Style::RED); \
|
||||
show_popup_for_fatal_error(LOG_FORMAT_POPUP(module, format_str, ## __VA_ARGS__)); \
|
||||
launcher::stop_subsystems(); \
|
||||
Sleep(10000); \
|
||||
launcher::kill(); \
|
||||
std::terminate(); \
|
||||
} ((void) 0 )
|
||||
|
||||
@@ -339,4 +339,14 @@ static inline bool parse_width_height(const std::string wh, std::pair<uint32_t,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline std::string wchar_to_u8(const wchar_t* wstr) {
|
||||
int size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (size <= 1) {
|
||||
return "";
|
||||
}
|
||||
std::string out(size - 1, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, out.data(), size - 1, nullptr, nullptr);
|
||||
return out;
|
||||
}
|
||||
Reference in New Issue
Block a user