Compare commits

...

9 Commits

Author SHA1 Message Date
sp2xdev 205cf29aff release build script and update changelog 2025-04-24 17:21:34 -07:00
bicarus-dev bf9074a76e launcher: complain when duplicate DLLs are detected (#306)
## Link to GitHub Issue, if one exists
#304 

## Description of change
Complain loudly about DLL conflicts. Show warnings for each DLL that
exists in both modules directory and the root.

This is not based on LoadLibrary hooks, just enumerating DLLs via
filesystem access.

Deliberately not using `log_fatal` since these are not necessarily going
to crash the game. Some people just love to have messy installs and if
the game booted fine before, it should continue to boot.

## Testing
Tested with/without `-modules`, with/without duplicate DLLs.
2025-04-24 10:35:34 -07:00
bicarus-dev 44e1edb50c avs: make max path check stricter (#305)
## Link to GitHub Issue, if one exists
n/a

## Description of change
The check to warn the user about potential MAX_PATH violation should be
stricter. Saw a user with 150 characters run into a crash during boot
for SDVX3.

## Testing
Tested paths under 130 / over 130, in both 32/64 bits.
2025-04-24 10:18:09 -07:00
bicarus-dev 41d0dce6e9 cfg: use %appdata%\spice2x for new config files (#300)
## Link to GitHub Issue, if one exists
n/a

## Description of change

For JSON config files of the following features:

* patch manager
* screen resize
* IIDX camera hook
* card manager

when saving a new file, store them in %appdata%\spice2x instead of
%appdata%.

On load:
1. If the JSON file exists in %appdata%\spice2x, use that (new path)
1. If the JSON file exists in %appdata%, continue to use that (legacy
path)

It's common for people to have mixed versions of spicetools/spice2x so
we'll continue to read from the %appdata% root if the files are there,
but with a preference for the new path. We will not forcibly move files.

spicetools.xml will continue to live in the %appdata% root. Moving this
will confuse a lot of people, so I'm avoiding this.

Also, this fixes `-patchcfgpath` and `-resizecfgpath` to create
directories as needed (previously the parent directory must have existed
first)

## Testing
Tested -

* existing config files are continued to be read from %appdata%
* new files get created in %appdata%\spice2x\... (both in spicecfg and
in overlay)
* can provide custom path for `-patchcfgpath` `-resizecfgpath` and
observe directories + file created in custom path, try absolute or local
relative paths
2025-04-22 00:35:10 -07:00
bicarus-dev 598422b701 build: large address aware variant of 32-bit spice.exe (#298)
## Link to GitHub Issue, if one exists
Fixes #280

## Description of change
Introduce a variant of 32bit spice.exe that is large address aware.

## Compiling
👍 

## Testing
Minimal testing has been done to see if the LAA variant can boot
existing 32 bit games.
2025-04-22 00:21:45 -07:00
bicarus-dev b58a1ccfcc sdvx: disable sdvx landscape option (#303)
## Link to GitHub Issue, if one exists
Fixes #277 

## Description of change
To avoid confusion, temporarily remove `-sdvxlandscape` because of the
issue described in the bug above.

`forceresswap` is still kept, so there is still a way to do exactly what
`-sdvxlandscape` used to do, if someone really wants it.

## Testing
Checked that `-sdvxlandscape` is ignored, and that `-sdvxlandscape`
continues to be honored.
2025-04-19 20:44:24 -07:00
ASleepyCat 60efd643d1 Add ccache support for faster incremental builds (#301)
## Description of change
Adds `ccache` support for local compiling and Github Actions
environments. This significantly speeds up incremental builds, but cold
starts will take a little longer to compile.

The build script now has an `-i` flag to ignore the build cache if
needed. You can also manually delete the `.ccache` folder to force a
fresh build too.

For the GA workflow, it uses the
[`ccache-action`](https://github.com/hendrikmuhs/ccache-action) action
to manage and store the cached build objects. This cache should be
accessible to all branches.

I also removed the `--no-cache` flag when building the
`spicetools/spice` image since Docker will automatically invalidate
`COPY` layers if it detects the copied files have changed.

### Compile times
Compiled with a 7800X3D, 32GB 6000MT/s RAM.
| `main` | `ccache` (fresh) | `ccache` (cached) | `ccache` (ignore
cache) |
|--------|--------|--------|--------|
| 2m46.047s | 3m8.886s | 0m32.638s | 2m45.148s |

## Testing
Tested incremental builds by using another branch that's rebased on top
of this.
2025-04-19 20:43:10 -07:00
sp2xdev 0596eeb6fe Update pull_request_template.md 2025-04-19 14:24:21 -07:00
ASleepyCat 3d5c64feb7 Fix button HID string ranges not being retrieved correctly (#299)
## Description of change
Currently, retrieving HID strings using string index minimum/maximum
ranges for buttons is broken as it uses the same index for each usage
cap.

Now it properly ranges over the minimum/maximum ranges.

Before:

![image](https://github.com/user-attachments/assets/da8d0162-07d9-4027-9933-2348fbf43a27)

After:

![image](https://github.com/user-attachments/assets/c00f81fe-d9d4-43f8-9bdd-d570ef298479)


## Compiling
Check CI.

## Testing
Tested with Beef Board firmware using string index ranges in the USB HID
descriptor.
2025-04-18 01:23:00 -07:00
26 changed files with 223 additions and 58 deletions
+5
View File
@@ -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: |
+1 -3
View File
@@ -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?*
+1
View File
@@ -2,3 +2,4 @@ bin/**
dist/** dist/**
docker/** docker/**
cmake-build* cmake-build*
.ccache/**
+2
View File
@@ -17,3 +17,5 @@ bin/*
dist/* dist/*
external/cv2pdb/* external/cv2pdb/*
.ccache/*
+17 -2
View File
@@ -607,6 +607,22 @@ 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 winscard winhttp
PRIVATE fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
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()
# spice64.exe # spice64.exe
############# #############
@@ -626,7 +642,6 @@ 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()
# spicecfg.exe # spicecfg.exe
############## ##############
@@ -732,7 +747,7 @@ set_target_properties(spicetools_cfg
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_stubs_kbt spicetools_stubs_kld
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"
+1 -1
View File
@@ -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"]
+11 -6
View File
@@ -76,18 +76,23 @@ 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"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\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());
} }
if (!fileutils::file_exists(dll_path)) { if (!fileutils::file_exists(dll_path)) {
+31 -1
View File
@@ -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")
@@ -41,7 +60,7 @@ 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_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_spice spicetools_spice_laa"
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"
# determine build type # determine build type
@@ -74,6 +93,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..."
@@ -155,6 +183,7 @@ 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
mkdir -p ${OUTDIR}/extras/largeaddressaware
if false # ((DEBUG > 0)) if false # ((DEBUG > 0))
then then
# debug files # debug files
@@ -175,6 +204,7 @@ 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/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/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
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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 "$@"
+2
View File
@@ -0,0 +1,2 @@
del /s /q .ccache
call build_docker.bat
+10 -12
View File
@@ -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();
if (fileutils::file_exists(this->config_path)) {
log_info("ScreenResize", "loading config from: {}", this->config_path.string());
file_exists = true;
}
} else { } else {
this->config_path = std::filesystem::path(_wgetenv(L"APPDATA")) / L"spicetools_screen_resize.json"; this->config_path =
fileutils::get_config_file_path("ScreenResize", "spicetools_screen_resize.json", &file_exists);
} }
if (fileutils::file_exists(this->config_path)) { 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");
@@ -170,8 +170,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()) {
@@ -221,10 +219,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");
} }
} }
} }
+5
View File
@@ -1,3 +1,8 @@
04/25/2025 [spice2x]
LargeAddressAware variant of spice.exe for Metal Gear
Save new JSON config files to %appdata%/spice2x
Various bug fixes
04/08/2025 [spice2x] 04/08/2025 [spice2x]
Ensure rawinput touch is default for all games (-wintouch to override) Ensure rawinput touch is default for all games (-wintouch to override)
Various overlay UI fixes and improvements, update ImGui library Various overlay UI fixes and improvements, update ImGui library
+2 -1
View File
@@ -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"
+1 -1
View File
@@ -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
View File
@@ -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)
+5 -4
View File
@@ -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;
+16 -7
View File
@@ -1118,6 +1118,8 @@ int main_implementation(int argc, char *argv[]) {
// log // log
#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
@@ -1170,13 +1172,17 @@ 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; //
#else // if (options[launcher::Options::SDVXFullscreenLandscape].value_bool() && !GRAPHICS_WINDOWED) {
log_warning("launcher", "-sdvxlandscape is not supported in 32-bit SDVX, ignoring..."); // #if SPICE64
#endif // 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;
} }
@@ -1800,6 +1806,9 @@ int main_implementation(int argc, char *argv[]) {
exit(spicecfg_run(sextet_devices)); exit(spicecfg_run(sextet_devices));
} }
// 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();
+8 -5
View File
@@ -228,7 +228,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)"
}, },
@@ -1087,7 +1088,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.title = "Screen Resize Config Path", .title = "Screen Resize Config Path",
.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 = "Paths",
}, },
@@ -1096,7 +1097,7 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.title = "Patch Manager Config Path", .title = "Patch Manager Config Path",
.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 = "Paths",
}, },
@@ -2049,15 +2050,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
+7 -6
View File
@@ -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");
} }
} }
@@ -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) {
@@ -1127,7 +1128,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");
+1 -1
View File
@@ -494,7 +494,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;
+50
View File
@@ -264,3 +264,53 @@ std::vector<uint8_t> *fileutils::bin_read(const std::filesystem::path &path) {
} }
return contents; return contents;
} }
std::filesystem::path fileutils::get_config_file_path(const std::string module, const std::string filename, bool* file_exists) {
// try %appdata%\spice2x path first, if it exists
const auto appdata_spice2x = std::filesystem::path(_wgetenv(L"APPDATA")) / "spice2x" / filename;
if (fileutils::file_exists(appdata_spice2x)) {
log_info(module, "loading config from %appdata%\\spice2x\\{}", filename);
if (file_exists) {
*file_exists = true;
}
return appdata_spice2x;
}
// fallback to older %appdata% path (older spice2x or mainline spicetools), if it exists
const auto appdata = std::filesystem::path(_wgetenv(L"APPDATA")) / filename;
if (fileutils::file_exists(appdata)) {
log_info(module, "loading config from %appdata%\\{}", filename);
if (file_exists) {
*file_exists = true;
}
return appdata;
}
// prefer new path if no existing file found
if (file_exists) {
*file_exists = false;
}
return appdata_spice2x;
}
bool fileutils::write_config_file(const std::string_view &module, const std::filesystem::path path, std::string text) {
// attempt to undo %appdata% expansion to hide user name
const auto appdata = std::filesystem::path(_wgetenv(L"APPDATA")).string();
auto censored = path.string();
const auto substr_offset = censored.find(appdata);
if (substr_offset != std::string::npos) {
censored.replace(substr_offset, appdata.length(), "%appdata%");
}
// create directory path up to where the config file lives
if (!path.parent_path().empty() && !std::filesystem::exists(path.parent_path())) {
log_misc(module, "creating directory path to config file: {}", censored);
if (!fileutils::dir_create_recursive(path.parent_path())) {
return false;
}
}
// save file
log_info(module, "saving config file: {}", censored);
return fileutils::text_write(path, text);
}
+3
View File
@@ -33,4 +33,7 @@ namespace fileutils {
std::string text_read(const std::filesystem::path &file_path); std::string text_read(const std::filesystem::path &file_path);
bool bin_write(const std::filesystem::path &path, uint8_t *data, size_t len); bool bin_write(const std::filesystem::path &path, uint8_t *data, size_t len);
std::vector<uint8_t> *bin_read(const std::filesystem::path &path); std::vector<uint8_t> *bin_read(const std::filesystem::path &path);
std::filesystem::path get_config_file_path(const std::string module, const std::string filename, bool* file_exists=nullptr);
bool write_config_file(const std::string_view &module, const std::filesystem::path path, std::string text);
} }
+33
View File
@@ -7,6 +7,7 @@
#include "logging.h" #include "logging.h"
#include "utils.h" #include "utils.h"
#include "peb.h" #include "peb.h"
#include "util/fileutils.h"
std::filesystem::path libutils::module_file_name(HMODULE module) { std::filesystem::path libutils::module_file_name(HMODULE module) {
std::wstring buf; std::wstring buf;
@@ -323,3 +324,35 @@ intptr_t libutils::offset2rva(const std::filesystem::path &path, intptr_t offset
return rva; return rva;
} }
void libutils::check_duplicate_dlls() {
const auto &spice_bin_path = libutils::module_file_name(nullptr).parent_path();
if (MODULE_PATH == spice_bin_path) {
return;
}
for (const auto &file : std::filesystem::directory_iterator(MODULE_PATH)) {
const auto &filename = file.path().filename();
const auto extension = strtolower(filename.extension().string());
if (extension == ".dll" &&
fileutils::file_exists(spice_bin_path / filename)) {
log_warning(
"libutils",
"DLL CONFLICT WARNING\n\n\n"
"-------------------------------------------------------------------\n"
"WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"{} exists in BOTH of these directories:\n\n"
" 1. {}\n"
" 2. {}\n\n"
"due to Windows DLL load order rules, #1 will load instead of #2.\n"
"this has unintended consequences and may crash your game!\n"
"resolve the conflict by deleting the stale copy of the DLL\n"
"-------------------------------------------------------------------\n\n\n",
filename.string(),
(spice_bin_path / filename).string(),
(MODULE_PATH / filename).string());
}
}
}
+2
View File
@@ -24,6 +24,8 @@ namespace libutils {
return try_library(module_name.c_str()); return try_library(module_name.c_str());
} }
void check_duplicate_dlls();
// get module handle helpers // get module handle helpers
HMODULE get_module(const char *module_name); HMODULE get_module(const char *module_name);
HMODULE try_module(const char *module_name); HMODULE try_module(const char *module_name);