Compare commits
74
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
079bb35b1f | ||
|
|
95051b6525 | ||
|
|
ce2f93d234 | ||
|
|
13a171f199 | ||
|
|
3da352488e | ||
|
|
2386047c2f | ||
|
|
baa550037a | ||
|
|
ec3ca1a055 | ||
|
|
da77f60b71 | ||
|
|
0c1998abe4 | ||
|
|
64260623bf | ||
|
|
3ddd34d51d | ||
|
|
ce0344742e | ||
|
|
a7723148bc | ||
|
|
78621e5dca | ||
|
|
1d7fe00703 | ||
|
|
e923b7918f | ||
|
|
0834646097 | ||
|
|
82439962d6 | ||
|
|
97cca85bc8 | ||
|
|
bb0fd62ec3 | ||
|
|
734c762bd6 | ||
|
|
1cb5b7b52a | ||
|
|
244f4aa56a | ||
|
|
26bc8fdda5 | ||
|
|
f13c9d0e50 | ||
|
|
aa9ea9204b | ||
|
|
ea5d566218 | ||
|
|
56e8e7456b | ||
|
|
7f63b77ab3 | ||
|
|
42689377e6 | ||
|
|
3f7dcd72bb | ||
|
|
e15c689061 | ||
|
|
6561ea9230 | ||
|
|
2b3071c9a1 | ||
|
|
04fc516d47 | ||
|
|
652ad41845 | ||
|
|
2c188f2ac4 | ||
|
|
7b5d86fe65 | ||
|
|
127d07ed31 | ||
|
|
7ceeda8bca | ||
|
|
cd709f0a55 | ||
|
|
07249ebb1c | ||
|
|
f0855d9b53 | ||
|
|
0b6986e12c | ||
|
|
d72f4b780a | ||
|
|
5075efc6dc | ||
|
|
88a19a8811 | ||
|
|
4a45f4d9c4 | ||
|
|
a34014876a | ||
|
|
74ef5237ad | ||
|
|
933dcf72a9 | ||
|
|
8a5f1b5017 | ||
|
|
c70e12ff07 | ||
|
|
359716b850 | ||
|
|
c94de456b5 | ||
|
|
e72da8ad5f | ||
|
|
3da7aa5be0 | ||
|
|
40a755173a | ||
|
|
04dee88276 | ||
|
|
572cf9d12c | ||
|
|
6c53848ea4 | ||
|
|
32f4f1871d | ||
|
|
f6f62e0e9d | ||
|
|
15cd228b8d | ||
|
|
5951a550bb | ||
|
|
a0e44f9e4b | ||
|
|
90ebf58554 | ||
|
|
a3f2d56a9e | ||
|
|
d03cca1fe2 | ||
|
|
8957d9d446 | ||
|
|
6c914266d9 | ||
|
|
b7a60638a4 | ||
|
|
14215af0d1 |
+12
-10
@@ -13,20 +13,22 @@ jobs:
|
|||||||
working-directory: ./src/spice2x
|
working-directory: ./src/spice2x
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5
|
- uses: actions/checkout@v5
|
||||||
- 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.23
|
|
||||||
- name: Calculate commit SHA
|
- name: Calculate commit SHA
|
||||||
id: vars
|
id: vars
|
||||||
run: |
|
run: |
|
||||||
calculatedSha=$(git rev-parse --short ${{ github.sha }})
|
calculatedSha=$(git rev-parse --short ${{ github.sha }})
|
||||||
echo "COMMIT_SHORT_SHA=$calculatedSha" >> $GITHUB_ENV
|
echo "sha=$calculatedSha" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "bin=${{ github.workspace }}/src/spice2x/bin" >> "$GITHUB_OUTPUT"
|
||||||
- name: Compile
|
- name: Compile
|
||||||
run: ./build_docker.sh
|
run: |
|
||||||
- uses: actions/upload-artifact@v6
|
docker build --pull "$PWD/external/docker" -t spicetools/deps --platform linux/x86_64
|
||||||
|
docker build --build-context gitroot="$PWD/../../.git" . -t spicetools/spice:latest
|
||||||
|
docker run --name spice-build spicetools/spice:latest
|
||||||
|
mkdir -p "$PWD/bin"
|
||||||
|
docker cp spice-build:/src/src/spice2x/bin/. "$PWD/bin"
|
||||||
|
docker rm spice-build
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: spice2x-ci-${{ env.COMMIT_SHORT_SHA }}
|
name: spice2x-ci-${{ steps.vars.outputs.sha }}
|
||||||
path: src/spice2x/bin
|
path: ${{ steps.vars.outputs.bin }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
+14
-1
@@ -1,7 +1,6 @@
|
|||||||
.vscode/*
|
.vscode/*
|
||||||
|
|
||||||
# JetBrains IDEs
|
# JetBrains IDEs
|
||||||
.idea
|
|
||||||
.idea_modules
|
.idea_modules
|
||||||
*.iws
|
*.iws
|
||||||
|
|
||||||
@@ -11,3 +10,17 @@ cmake-build*
|
|||||||
# user config
|
# user config
|
||||||
build_all.local.sh
|
build_all.local.sh
|
||||||
build_docker.local.sh
|
build_docker.local.sh
|
||||||
|
|
||||||
|
# output from build script
|
||||||
|
bin/*
|
||||||
|
dist/*
|
||||||
|
build/*.dll
|
||||||
|
|
||||||
|
external/cv2pdb/*
|
||||||
|
|
||||||
|
.ccache/*
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
.vs
|
||||||
|
out
|
||||||
|
CMakeSettings.json
|
||||||
|
|||||||
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Unnecessary plugin data
|
||||||
|
/markdown-navigator.xml
|
||||||
Generated
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeSharedSettings">
|
||||||
|
<configurations>
|
||||||
|
<configuration PROFILE_NAME="Release_x64[WIN_32]" ENABLED="true" GENERATION_DIR="bin/build/x64/Release" CONFIG_NAME="Release" TOOLCHAIN_NAME="MinGW [Crosscompile]" GENERATION_OPTIONS="-G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="external/cmake-various/toolchain/toolchain-mingw_nix-win-x64.cmake"" />
|
||||||
|
<configuration PROFILE_NAME="Release_x86[WIN_32]" ENABLED="true" GENERATION_DIR="bin/build/x86/Release" CONFIG_NAME="Release" TOOLCHAIN_NAME="MinGW [Crosscompile]" GENERATION_OPTIONS="-G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="external/cmake-various/toolchain/toolchain-mingw_nix-win-x86.cmake"" />
|
||||||
|
<configuration PROFILE_NAME="Debug_x64[WIN_32]" ENABLED="true" GENERATION_DIR="bin/build/x64/Debug" CONFIG_NAME="Debug" TOOLCHAIN_NAME="MinGW [Crosscompile]" GENERATION_OPTIONS="-G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="external/cmake-various/toolchain/toolchain-mingw_nix-win-x64.cmake"" />
|
||||||
|
<configuration PROFILE_NAME="Debug_x86[WIN_32]" ENABLED="true" GENERATION_DIR="bin/build/x86/Debug" CONFIG_NAME="Debug" TOOLCHAIN_NAME="MinGW [Crosscompile]" GENERATION_OPTIONS="-G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE="external/cmake-various/toolchain/toolchain-mingw_nix-win-x86.cmake"" />
|
||||||
|
</configurations>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+350
@@ -0,0 +1,350 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="BackendCodeEditorSettings">
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstexprIfDiscardedBranch/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefinitionsOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOverrideWithDifferentVisibility/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReferenceToOverriddenVirtualFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseDesignatedInitializers/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseInternalLinkage/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_PTR_IN_NESTED_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBER/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_METHOD/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBER/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_METHOD/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BETWEEN_CLOSING_ANGLE_BRACKETS_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="ConstantConditionsOC" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="DuplicatedCode" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyBroadExceptionInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ourVersions">
|
||||||
|
<value>
|
||||||
|
<list size="4">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="2.7" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="3.7" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="3.8" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="3.9" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyDefaultArgumentInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredErrors">
|
||||||
|
<list>
|
||||||
|
<option value="E266" />
|
||||||
|
<option value="E701" />
|
||||||
|
<option value="E265" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredErrors">
|
||||||
|
<list>
|
||||||
|
<option value="N806" />
|
||||||
|
<option value="N803" />
|
||||||
|
<option value="N802" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyTypeCheckerInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PyUnusedLocalInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="ShellCheck" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<shellcheck_settings value="SC2164" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="Simplify" enabled="false" level="WARNING" enabled_by_default="false">
|
||||||
|
<option name="clangTidyCheckOptions">
|
||||||
|
<list>
|
||||||
|
<ClangTidyCheckOption>
|
||||||
|
<option name="optionName" value="clion-simplify.SimplifyConstantConditions" />
|
||||||
|
<option name="optionValue" value="1" />
|
||||||
|
</ClangTidyCheckOption>
|
||||||
|
<ClangTidyCheckOption>
|
||||||
|
<option name="optionName" value="clion-simplify.SimplifyIfWithReturn" />
|
||||||
|
<option name="optionValue" value="0" />
|
||||||
|
</ClangTidyCheckOption>
|
||||||
|
<ClangTidyCheckOption>
|
||||||
|
<option name="optionName" value="clion-simplify.SimplifyEqualToTrueFalse" />
|
||||||
|
<option name="optionValue" value="1" />
|
||||||
|
</ClangTidyCheckOption>
|
||||||
|
<ClangTidyCheckOption>
|
||||||
|
<option name="optionName" value="clion-simplify.SimplifyTernaryWithConstantBranch" />
|
||||||
|
<option name="optionValue" value="1" />
|
||||||
|
</ClangTidyCheckOption>
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SpellCheckingInspection" enabled="true" level="TYPO" enabled_by_default="true">
|
||||||
|
<option name="processCode" value="false" />
|
||||||
|
<option name="processLiterals" value="true" />
|
||||||
|
<option name="processComments" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MarkdownEnhProjectSettings">
|
||||||
|
<AnnotatorSettings targetHasSpaces="true" linkCaseMismatch="true" wikiCaseMismatch="true" wikiLinkHasDashes="true" notUnderWikiHome="true" targetNotWikiPageExt="true" notUnderSourceWikiHome="true" targetNameHasAnchor="true" targetPathHasAnchor="true" wikiLinkHasSlash="true" wikiLinkHasSubdir="true" wikiLinkHasOnlyAnchor="true" linkTargetsWikiHasExt="true" linkTargetsWikiHasBadExt="true" notUnderSameRepo="true" targetNotUnderVcs="false" linkNeedsExt="true" linkHasBadExt="true" linkTargetNeedsExt="true" linkTargetHasBadExt="true" wikiLinkNotInWiki="true" imageTargetNotInRaw="true" repoRelativeAcrossVcsRoots="true" multipleWikiTargetsMatch="true" unresolvedLinkReference="true" linkIsIgnored="true" anchorIsIgnored="true" anchorIsUnresolved="true" anchorLineReferenceIsUnresolved="true" anchorLineReferenceFormat="true" anchorHasDuplicates="true" abbreviationDuplicates="true" abbreviationNotUsed="true" attributeIdDuplicateDefinition="true" attributeIdNotUsed="true" footnoteDuplicateDefinition="true" footnoteUnresolved="true" footnoteDuplicates="true" footnoteNotUsed="true" macroDuplicateDefinition="true" macroUnresolved="true" macroDuplicates="true" macroNotUsed="true" referenceDuplicateDefinition="true" referenceUnresolved="true" referenceDuplicates="true" referenceNotUsed="true" referenceUnresolvedNumericId="true" enumRefDuplicateDefinition="true" enumRefUnresolved="true" enumRefDuplicates="true" enumRefNotUsed="true" enumRefLinkUnresolved="true" enumRefLinkDuplicates="true" simTocUpdateNeeded="true" simTocTitleSpaceNeeded="true" />
|
||||||
|
<HtmlExportSettings updateOnSave="false" parentDir="" targetDir="" cssDir="css" scriptDir="js" plainHtml="false" imageDir="" copyLinkedImages="false" imagePathType="0" targetPathType="2" targetExt="" useTargetExt="false" noCssNoScripts="false" useElementStyleAttribute="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" linkFormatType="HTTP_ABSOLUTE" />
|
||||||
|
<LinkMapSettings>
|
||||||
|
<textMaps />
|
||||||
|
</LinkMapSettings>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+71
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="FlexmarkProjectSettings">
|
||||||
|
<FlexmarkHtmlSettings flexmarkSpecExampleRendering="0" flexmarkSpecExampleRenderHtml="false">
|
||||||
|
<flexmarkSectionLanguages>
|
||||||
|
<option name="1" value="Markdown" />
|
||||||
|
<option name="2" value="HTML" />
|
||||||
|
<option name="3" value="flexmark-ast:1" />
|
||||||
|
</flexmarkSectionLanguages>
|
||||||
|
</FlexmarkHtmlSettings>
|
||||||
|
</component>
|
||||||
|
<component name="MarkdownProjectSettings">
|
||||||
|
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.0" maxImageWidth="0" synchronizePreviewPosition="true" highlightPreviewType="LINE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="true" showSelectionInPreview="true" lastLayoutSetsDefault="false">
|
||||||
|
<PanelProvider>
|
||||||
|
<provider providerId="com.vladsch.md.nav.editor.swing.html.panel" providerName="Default - Swing" />
|
||||||
|
</PanelProvider>
|
||||||
|
</PreviewSettings>
|
||||||
|
<ParserSettings gitHubSyntaxChange="false" correctedInvalidSettings="false" emojiShortcuts="1" emojiImages="0">
|
||||||
|
<PegdownExtensions>
|
||||||
|
<option name="ATXHEADERSPACE" value="true" />
|
||||||
|
<option name="FENCED_CODE_BLOCKS" value="true" />
|
||||||
|
<option name="INTELLIJ_DUMMY_IDENTIFIER" value="true" />
|
||||||
|
<option name="RELAXEDHRULES" value="true" />
|
||||||
|
<option name="STRIKETHROUGH" value="true" />
|
||||||
|
<option name="TABLES" value="true" />
|
||||||
|
<option name="TASKLISTITEMS" value="true" />
|
||||||
|
</PegdownExtensions>
|
||||||
|
<ParserOptions>
|
||||||
|
<option name="COMMONMARK_LISTS" value="true" />
|
||||||
|
<option name="EMOJI_SHORTCUTS" value="true" />
|
||||||
|
<option name="GFM_TABLE_RENDERING" value="true" />
|
||||||
|
<option name="PRODUCTION_SPEC_PARSER" value="true" />
|
||||||
|
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
||||||
|
</ParserOptions>
|
||||||
|
</ParserSettings>
|
||||||
|
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" addPageHeader="false" addAnchorLinks="false" anchorLinksWrapText="false" imageUriSerials="false" addDocTypeHtml="true" noParaTags="false" defaultUrlTitle="false" migratedPlantUml="true" migratedAnchorLinks="true" plantUmlConversion="0">
|
||||||
|
<GeneratorProvider>
|
||||||
|
<provider providerId="com.vladsch.md.nav.editor.text.html.generator" providerName="Unmodified HTML Generator" />
|
||||||
|
</GeneratorProvider>
|
||||||
|
<headerTop />
|
||||||
|
<headerBottom />
|
||||||
|
<bodyTop />
|
||||||
|
<bodyBottom />
|
||||||
|
<fencedCodeConversions>
|
||||||
|
<option name="c4plantuml" value="NONE" />
|
||||||
|
<option name="ditaa" value="NONE" />
|
||||||
|
<option name="erd" value="NONE" />
|
||||||
|
<option name="graphviz" value="NONE" />
|
||||||
|
<option name="latex" value="KATEX" />
|
||||||
|
<option name="math" value="KATEX" />
|
||||||
|
<option name="mermaid" value="NONE" />
|
||||||
|
<option name="nomnoml" value="NONE" />
|
||||||
|
<option name="plantuml" value="NONE" />
|
||||||
|
<option name="puml" value="NONE" />
|
||||||
|
<option name="svgbob" value="NONE" />
|
||||||
|
<option name="umlet" value="NONE" />
|
||||||
|
<option name="vega" value="NONE" />
|
||||||
|
<option name="vegalite" value="NONE" />
|
||||||
|
<option name="wavedrom" value="NONE" />
|
||||||
|
</fencedCodeConversions>
|
||||||
|
</HtmlSettings>
|
||||||
|
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssUriSerial="true" isCssTextEnabled="false" isDynamicPageWidth="true">
|
||||||
|
<StylesheetProvider>
|
||||||
|
<provider providerId="com.vladsch.md.nav.editor.text.html.css" providerName="No Stylesheet" />
|
||||||
|
</StylesheetProvider>
|
||||||
|
<ScriptProviders />
|
||||||
|
<cssText />
|
||||||
|
<cssUriHistory />
|
||||||
|
</CssSettings>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakePythonSetting">
|
||||||
|
<option name="pythonIntegrationState" value="YES" />
|
||||||
|
</component>
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$/src/spice2x">
|
||||||
|
<contentRoot DIR="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/spicetools.iml" filepath="$PROJECT_DIR$/.idea/spicetools.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Clion[Init]" type="ShConfigurationType" activateToolWindowBeforeRun="false">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="clion init" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/src/spice2x/" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Deploy[Debug_x64]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="true" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Clion[Init]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="spicetools_spice64" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Debug_x64[WIN_32]" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Deploy[Debug_x86]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="true" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Clion[Init]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="spicetools_cfg" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Debug_x86[WIN_32]" />
|
||||||
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="spicetools_spice" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Debug_x86[WIN_32]" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Deploy[Extra_x64]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="false" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="spicetools_stubs_nvEncodeAPI64" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x64[WIN_32]" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="spicetools_stubs_nvcuda" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x64[WIN_32]" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="spicetools_stubs_nvcuvid" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x64[WIN_32]" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Deploy[Extra_x86]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="false" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="spicetools_stubs_cpusbxpkm" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x86[WIN_32]" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="spicetools_spice_laa" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x86[WIN_32]" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Deploy[Release_x64]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="false" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Clion[Init]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="spicetools_spice64" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x64[WIN_32]" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Deploy[Release_x86]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="deploy all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="false" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Clion[Init]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="spicetools_cfg" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x86[WIN_32]" />
|
||||||
|
<option name="RunConfigurationTask" enabled="false" run_configuration_name="spicetools_spice" run_configuration_type="CMakeRunConfiguration" run_configuration_target="CMakeBuildProfile:Release_x86[WIN_32]" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Distribute[Release]" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/src/spice2x/cmake.sh" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="distribute all" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="/usr/bin/bash" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="EXECUTE_IN_TERMINAL" value="false" />
|
||||||
|
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="_G_clean" value="false" />
|
||||||
|
<env name="_G_debug" value="false" />
|
||||||
|
</envs>
|
||||||
|
<method v="2">
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Deploy[Release_x64]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Deploy[Release_x86]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Deploy[Extra_x64]" run_configuration_type="ShConfigurationType" />
|
||||||
|
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Deploy[Extra_x86]" run_configuration_type="ShConfigurationType" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_cfg" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_cfg" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_spice" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_spice" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_spice64" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_spice64" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt64" />
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld64" />
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_spice_laa" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_spice_laa" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kbt" />
|
||||||
|
<option name="CMake.Explicit.Target" predefinedTargetName="spicetools_stubs_kld" />
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_stubs_cpusbxpkm" type="CMakeRunConfiguration" factoryName="Application" folderName="32" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_cpusbxpkm" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_stubs_nvEncodeAPI64" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_nvEncodeAPI64" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_stubs_nvcuda" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_nvcuda" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="spicetools_stubs_nvcuvid" type="CMakeRunConfiguration" factoryName="Application" folderName="64" activateToolWindowBeforeRun="false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Project" TARGET_NAME="spicetools_stubs_nvcuvid" CONFIG_NAME="Release_x64[WIN_32]" RUN_PATH="/bin/true">
|
||||||
|
<method v="2">
|
||||||
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
Generated
+2
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module classpath="CIDR" type="CPP_MODULE" version="4" />
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -124,8 +124,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|||||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static")
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static")
|
||||||
else()
|
else()
|
||||||
|
|
||||||
# warnings as errors
|
|
||||||
set(CMAKE_COMPILE_WARNING_AS_ERROR ON)
|
|
||||||
|
|
||||||
# warnings
|
# warnings
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") # enable stuff
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") # enable stuff
|
||||||
@@ -273,7 +271,20 @@ set_source_files_properties(cfg/manifest.rc PROPERTIES LANGUAGE RC)
|
|||||||
set_source_files_properties(cfg/icon.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(cfg/icon.rc PROPERTIES LANGUAGE RC)
|
||||||
set_source_files_properties(cfg/Win32D.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(cfg/Win32D.rc PROPERTIES LANGUAGE RC)
|
||||||
set_source_files_properties(build/manifest64.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(build/manifest64.rc PROPERTIES LANGUAGE RC)
|
||||||
|
set_source_files_properties(build/blob.rc PROPERTIES LANGUAGE RC)
|
||||||
set_source_files_properties(stubs/manifest.rc PROPERTIES LANGUAGE RC)
|
set_source_files_properties(stubs/manifest.rc PROPERTIES LANGUAGE RC)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT build/dsdmo.i686.dll
|
||||||
|
COMMAND sh -c "wget -qO- 'https://web.archive.org/web/20260212204718if_/https://download.zip.dll-files.com/d01cab97ad497201c4ad99eb6e4182b3/dsdmo.zip?token=f7cVie5KOSz-hnFUYC37Ow&expires=1770974229' | bsdtar -xvf - -C '${CMAKE_SOURCE_DIR}/build' -s '/dsdmo.dll/dsdmo.i686.dll/' dsdmo.dll"
|
||||||
|
COMMENT "Fetching dsdmo.dll blob (i686)"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT build/dsdmo.x86_64.dll
|
||||||
|
COMMAND sh -c "wget -qO- 'https://web.archive.org/web/20260212203516if_/https://download.zip.dll-files.com/2627c69b89807078f5fdf63ee104dddf/dsdmo.zip?token=1rLcDAA2LFA6YRyinX0GXg&expires=1770973374' | bsdtar -xvf - -C '${CMAKE_SOURCE_DIR}/build' -s '/dsdmo.dll/dsdmo.x86_64.dll/' dsdmo.dll"
|
||||||
|
COMMENT "Fetching dsdmo.dll blob (x86_64)"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
# sources
|
# sources
|
||||||
#########
|
#########
|
||||||
@@ -332,6 +343,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
api/modules/control.cpp
|
api/modules/control.cpp
|
||||||
api/modules/touch.cpp
|
api/modules/touch.cpp
|
||||||
api/modules/iidx.cpp
|
api/modules/iidx.cpp
|
||||||
|
api/modules/sdvx.cpp
|
||||||
api/serial.cpp
|
api/serial.cpp
|
||||||
api/modules/drs.cpp
|
api/modules/drs.cpp
|
||||||
api/modules/lcd.cpp
|
api/modules/lcd.cpp
|
||||||
@@ -525,6 +537,11 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
hooks/audio/backends/wasapi/util.cpp
|
hooks/audio/backends/wasapi/util.cpp
|
||||||
hooks/audio/implementations/asio.cpp
|
hooks/audio/implementations/asio.cpp
|
||||||
hooks/audio/implementations/wave_out.cpp
|
hooks/audio/implementations/wave_out.cpp
|
||||||
|
hooks/audio/implementations/none.cpp
|
||||||
|
hooks/audio/implementations/pipewire.cpp
|
||||||
|
hooks/develhook.cpp
|
||||||
|
hooks/sndbhook.cpp
|
||||||
|
hooks/wmischook.cpp
|
||||||
hooks/avshook.cpp
|
hooks/avshook.cpp
|
||||||
hooks/cfgmgr32hook.cpp
|
hooks/cfgmgr32hook.cpp
|
||||||
hooks/debughook.cpp
|
hooks/debughook.cpp
|
||||||
@@ -535,6 +552,7 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
hooks/graphics/nvapi_hook.cpp
|
hooks/graphics/nvapi_hook.cpp
|
||||||
hooks/graphics/nvenc_hook.cpp
|
hooks/graphics/nvenc_hook.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_backend.cpp
|
hooks/graphics/backends/d3d9/d3d9_backend.cpp
|
||||||
|
hooks/graphics/backends/d3d9/d3d9_screenshot.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_device.cpp
|
hooks/graphics/backends/d3d9/d3d9_device.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_gfdm.cpp
|
hooks/graphics/backends/d3d9/d3d9_gfdm.cpp
|
||||||
hooks/graphics/backends/d3d9/d3d9_live2d.cpp
|
hooks/graphics/backends/d3d9/d3d9_live2d.cpp
|
||||||
@@ -747,7 +765,7 @@ endif()
|
|||||||
# spice.exe
|
# spice.exe
|
||||||
###########
|
###########
|
||||||
|
|
||||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.i686.dll)
|
||||||
add_executable(spicetools_spice ${RESOURCE_FILES})
|
add_executable(spicetools_spice ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_spice PRIVATE spicetools_spice_objs)
|
target_link_libraries(spicetools_spice PRIVATE spicetools_spice_objs)
|
||||||
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice PROPERTIES PREFIX "")
|
||||||
@@ -760,7 +778,7 @@ endif()
|
|||||||
# spice_laa.exe
|
# spice_laa.exe
|
||||||
###########
|
###########
|
||||||
|
|
||||||
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc)
|
set(RESOURCE_FILES build/manifest.manifest build/manifest.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.i686.dll)
|
||||||
add_executable(spicetools_spice_laa ${RESOURCE_FILES})
|
add_executable(spicetools_spice_laa ${RESOURCE_FILES})
|
||||||
target_link_libraries(spicetools_spice_laa PRIVATE spicetools_spice_objs)
|
target_link_libraries(spicetools_spice_laa PRIVATE spicetools_spice_objs)
|
||||||
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice_laa PROPERTIES PREFIX "")
|
||||||
@@ -789,14 +807,14 @@ endif()
|
|||||||
# spice64.exe
|
# spice64.exe
|
||||||
#############
|
#############
|
||||||
|
|
||||||
set(RESOURCE_FILES build/manifest.manifest build/manifest64.rc build/icon.rc cfg/Win32D.rc)
|
set(RESOURCE_FILES build/manifest.manifest build/manifest64.rc build/icon.rc cfg/Win32D.rc build/blob.rc build/dsdmo.x86_64.dll)
|
||||||
add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
|
add_executable(spicetools_spice64 ${SOURCE_FILES} ${RESOURCE_FILES})
|
||||||
|
|
||||||
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
# do NOT link against: mf, mfplat, mfreadwrite; otherwise unity games will break
|
||||||
target_link_libraries(spicetools_spice64
|
target_link_libraries(spicetools_spice64
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp mfuuid strmiids dxva2
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||||
target_link_libraries(spicetools_spice64 PUBLIC winscard)
|
|
||||||
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
|
set_target_properties(spicetools_spice64 PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
set_target_properties(spicetools_spice64 PROPERTIES OUTPUT_NAME "spice64")
|
||||||
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
target_compile_definitions(spicetools_spice64 PRIVATE SPICE64=1)
|
||||||
@@ -840,7 +858,6 @@ add_executable(spicetools_cfg WIN32 ${SOURCE_FILES} ${RESOURCE_FILES})
|
|||||||
target_link_libraries(spicetools_cfg
|
target_link_libraries(spicetools_cfg
|
||||||
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
PUBLIC d3d9 ws2_32 version comctl32 shlwapi iphlpapi hid secur32 setupapi psapi winmm winhttp strmiids
|
||||||
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
PRIVATE fmt::fmt-header-only discord-rpc imgui hash-library minhook imm32 dwmapi CpuFeatures::cpu_features)
|
||||||
target_link_libraries(spicetools_cfg PUBLIC winscard)
|
|
||||||
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
|
set_target_properties(spicetools_cfg PROPERTIES PREFIX "")
|
||||||
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
set_target_properties(spicetools_cfg PROPERTIES OUTPUT_NAME "spicecfg")
|
||||||
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
target_compile_definitions(spicetools_cfg PRIVATE SPICETOOLS_SPICECFG_STANDALONE=1)
|
||||||
|
|||||||
@@ -267,6 +267,20 @@ which also means that your hex edits are applicable directly.
|
|||||||
- `Side Panel Right Inner`
|
- `Side Panel Right Inner`
|
||||||
- `Side Panel Right`
|
- `Side Panel Right`
|
||||||
|
|
||||||
|
#### SDVX
|
||||||
|
- tapeled_get(name: str, ...)
|
||||||
|
- returns a list containing a dict of the current tape LED states. The dict keys are:
|
||||||
|
- `Title`
|
||||||
|
- `Upper Left Speaker`
|
||||||
|
- `Upper Right Speaker`
|
||||||
|
- `Left Wing`
|
||||||
|
- `Right Wing`
|
||||||
|
- `Control Panel`
|
||||||
|
- `Lower Left Speaker`
|
||||||
|
- `Lower Right Speaker`
|
||||||
|
- `Woofer`
|
||||||
|
- `V Unit`
|
||||||
|
|
||||||
#### LCD
|
#### LCD
|
||||||
- info()
|
- info()
|
||||||
- returns information about the serial LCD controller some games use
|
- returns information about the serial LCD controller some games use
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace api {
|
||||||
|
|
||||||
|
extern std::atomic_uint32_t CLIENT_COUNT;
|
||||||
|
|
||||||
|
inline bool has_clients() {
|
||||||
|
return CLIENT_COUNT.load(std::memory_order_relaxed) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
#include "external/rapidjson/document.h"
|
#include "external/rapidjson/document.h"
|
||||||
#include "util/crypt.h"
|
#include "util/crypt.h"
|
||||||
@@ -28,6 +29,7 @@
|
|||||||
#include "modules/lcd.h"
|
#include "modules/lcd.h"
|
||||||
#include "modules/lights.h"
|
#include "modules/lights.h"
|
||||||
#include "modules/memory.h"
|
#include "modules/memory.h"
|
||||||
|
#include "modules/sdvx.h"
|
||||||
#include "modules/touch.h"
|
#include "modules/touch.h"
|
||||||
#include "modules/resize.h"
|
#include "modules/resize.h"
|
||||||
#include "request.h"
|
#include "request.h"
|
||||||
@@ -36,6 +38,8 @@
|
|||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
using namespace api;
|
using namespace api;
|
||||||
|
|
||||||
|
std::atomic_uint32_t api::CLIENT_COUNT = 0;
|
||||||
|
|
||||||
Controller::Controller(unsigned short port, std::string password, bool pretty)
|
Controller::Controller(unsigned short port, std::string password, bool pretty)
|
||||||
: port(port), password(std::move(password)), pretty(pretty)
|
: port(port), password(std::move(password)), pretty(pretty)
|
||||||
{
|
{
|
||||||
@@ -411,8 +415,11 @@ void Controller::init_state(api::ClientState *state) {
|
|||||||
state->modules.push_back(new modules::LCD());
|
state->modules.push_back(new modules::LCD());
|
||||||
state->modules.push_back(new modules::Lights());
|
state->modules.push_back(new modules::Lights());
|
||||||
state->modules.push_back(new modules::Memory());
|
state->modules.push_back(new modules::Memory());
|
||||||
|
state->modules.push_back(new modules::SDVX());
|
||||||
state->modules.push_back(new modules::Touch());
|
state->modules.push_back(new modules::Touch());
|
||||||
state->modules.push_back(new modules::Resize());
|
state->modules.push_back(new modules::Resize());
|
||||||
|
|
||||||
|
CLIENT_COUNT.fetch_add(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::free_state(api::ClientState *state) {
|
void Controller::free_state(api::ClientState *state) {
|
||||||
@@ -424,6 +431,8 @@ void Controller::free_state(api::ClientState *state) {
|
|||||||
|
|
||||||
// free cipher
|
// free cipher
|
||||||
delete state->cipher;
|
delete state->cipher;
|
||||||
|
|
||||||
|
CLIENT_COUNT.fetch_sub(1, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::free_socket() {
|
void Controller::free_socket() {
|
||||||
|
|||||||
@@ -106,14 +106,16 @@ namespace api::modules {
|
|||||||
void IIDX::copy_tapeled_data(Response &res, Value &response_object, const tapeledutils::tape_led &mapping) {
|
void IIDX::copy_tapeled_data(Response &res, Value &response_object, const tapeledutils::tape_led &mapping) {
|
||||||
// Create an array for the light state
|
// Create an array for the light state
|
||||||
Value light_state(kArrayType);
|
Value light_state(kArrayType);
|
||||||
light_state.Reserve(mapping.data.capacity() * 3, res.doc()->GetAllocator());
|
light_state.Reserve(
|
||||||
|
static_cast<SizeType>(mapping.data.size() * 3),
|
||||||
|
res.doc()->GetAllocator());
|
||||||
for (const auto [r, g, b] : mapping.data) {
|
for (const auto [r, g, b] : mapping.data) {
|
||||||
light_state.PushBack(r, res.doc()->GetAllocator());
|
light_state.PushBack(r, res.doc()->GetAllocator());
|
||||||
light_state.PushBack(g, res.doc()->GetAllocator());
|
light_state.PushBack(g, res.doc()->GetAllocator());
|
||||||
light_state.PushBack(b, res.doc()->GetAllocator());
|
light_state.PushBack(b, res.doc()->GetAllocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can't use StringRef here, turns some strings partially into null bytes for some reason
|
// can't use StringRef here, turns some strings partially into null bytes for some reason
|
||||||
Value light_name(mapping.lightName.c_str(), res.doc()->GetAllocator());
|
Value light_name(mapping.lightName.c_str(), res.doc()->GetAllocator());
|
||||||
response_object.AddMember(light_name, light_state, res.doc()->GetAllocator());
|
response_object.AddMember(light_name, light_state, res.doc()->GetAllocator());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#include "sdvx.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
using namespace std::placeholders;
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
namespace api::modules {
|
||||||
|
|
||||||
|
SDVX::SDVX() : Module("sdvx") {
|
||||||
|
functions["tapeled_get"] = std::bind(&SDVX::tapeled_get, this, _1, _2);
|
||||||
|
|
||||||
|
for (auto &light : games::sdvx::TAPELED_MAPPING) {
|
||||||
|
lights_by_names.emplace(light.lightName, light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tapeled_get()
|
||||||
|
* tapeled_get(name: str, ...)
|
||||||
|
*/
|
||||||
|
void SDVX::tapeled_get(Request &req, Response &res) {
|
||||||
|
Value response_object(kObjectType);
|
||||||
|
|
||||||
|
// all tape leds
|
||||||
|
if (req.params.Size() == 0) {
|
||||||
|
// iterate through each device and dump its lights data into the response
|
||||||
|
for (const auto &mapping : games::sdvx::TAPELED_MAPPING) {
|
||||||
|
copy_tapeled_data(res, response_object, mapping);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// specified light names
|
||||||
|
for (Value ¶m : req.params.GetArray()) {
|
||||||
|
// check params
|
||||||
|
if (!param.IsString()) {
|
||||||
|
error_type(res, "name", "string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto name = param.GetString();
|
||||||
|
if (const auto &it = lights_by_names.find(name); it != lights_by_names.end()) {
|
||||||
|
copy_tapeled_data(res, response_object, it->second.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.add_data(response_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDVX::copy_tapeled_data(Response &res, Value &response_object,
|
||||||
|
const tapeledutils::tape_led &mapping)
|
||||||
|
{
|
||||||
|
Value light_state(kArrayType);
|
||||||
|
light_state.Reserve(
|
||||||
|
static_cast<SizeType>(mapping.data.size() * 3),
|
||||||
|
res.doc()->GetAllocator());
|
||||||
|
for (const auto [r, g, b] : mapping.data) {
|
||||||
|
light_state.PushBack(r, res.doc()->GetAllocator());
|
||||||
|
light_state.PushBack(g, res.doc()->GetAllocator());
|
||||||
|
light_state.PushBack(b, res.doc()->GetAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't use StringRef here, turns some strings partially into null bytes for some reason
|
||||||
|
Value light_name(mapping.lightName.c_str(), res.doc()->GetAllocator());
|
||||||
|
response_object.AddMember(light_name, light_state, res.doc()->GetAllocator());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "api/module.h"
|
||||||
|
#include "api/request.h"
|
||||||
|
#include "external/robin_hood.h"
|
||||||
|
#include "games/sdvx/sdvx.h"
|
||||||
|
|
||||||
|
namespace api::modules {
|
||||||
|
|
||||||
|
class SDVX : public Module {
|
||||||
|
public:
|
||||||
|
SDVX();
|
||||||
|
|
||||||
|
private:
|
||||||
|
robin_hood::unordered_map<std::string, std::reference_wrapper<tapeledutils::tape_led>> lights_by_names;
|
||||||
|
|
||||||
|
void tapeled_get(Request &req, Response &res);
|
||||||
|
void copy_tapeled_data(Response &res, rapidjson::Value &response_object,
|
||||||
|
const tapeledutils::tape_led &mapping);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -55,9 +55,12 @@ namespace api::modules {
|
|||||||
native_canvas_w = 0;
|
native_canvas_w = 0;
|
||||||
native_canvas_h = 0;
|
native_canvas_h = 0;
|
||||||
if (is_sdvx) {
|
if (is_sdvx) {
|
||||||
// exceed gear subscreen, portrait after the rotation applied in apply_touch_errata
|
// windowed and landscape API coordinates already match the primary screen orientation;
|
||||||
native_canvas_w = 1080;
|
// fullscreen portrait coordinates are rotated by apply_touch_errata
|
||||||
native_canvas_h = 1920;
|
const bool landscape_coordinates =
|
||||||
|
GRAPHICS_WINDOWED || GRAPHICS_FS_ORIENTATION_SWAP;
|
||||||
|
native_canvas_w = landscape_coordinates ? 1920 : 1080;
|
||||||
|
native_canvas_h = landscape_coordinates ? 1080 : 1920;
|
||||||
} else if (avs::game::is_model("LDJ")) {
|
} else if (avs::game::is_model("LDJ")) {
|
||||||
// TDJ subscreen; FHD models are upscaled to 1080p by apply_touch_errata
|
// TDJ subscreen; FHD models are upscaled to 1080p by apply_touch_errata
|
||||||
native_canvas_w = is_tdj_fhd ? 1920 : 1280;
|
native_canvas_w = is_tdj_fhd ? 1920 : 1280;
|
||||||
@@ -218,8 +221,8 @@ namespace api::modules {
|
|||||||
// the target of the touch events so just assume it's the sub screen
|
// the target of the touch events so just assume it's the sub screen
|
||||||
x = x_raw * 1920 / 1280;
|
x = x_raw * 1920 / 1280;
|
||||||
y = y_raw * 1080 / 720;
|
y = y_raw * 1080 / 720;
|
||||||
} else if (is_sdvx) {
|
} else if (is_sdvx && !GRAPHICS_WINDOWED && !GRAPHICS_FS_ORIENTATION_SWAP) {
|
||||||
// for exceed gear, they are both 1080p screens, but need to apply transformation
|
// rotate API coordinates into SDVX's portrait touch space
|
||||||
x = 1080 - y_raw;
|
x = 1080 - y_raw;
|
||||||
y = x_raw;
|
y = x_raw;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from .coin import *
|
|||||||
from .control import *
|
from .control import *
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .iidx import *
|
from .iidx import *
|
||||||
|
from .sdvx import *
|
||||||
from .info import *
|
from .info import *
|
||||||
from .keypads import *
|
from .keypads import *
|
||||||
from .lights import *
|
from .lights import *
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from .connection import Connection
|
||||||
|
from .request import Request
|
||||||
|
|
||||||
|
|
||||||
|
def sdvx_tapeled_get(con: Connection, *light_names):
|
||||||
|
req = Request("sdvx", "tapeled_get")
|
||||||
|
|
||||||
|
for light_name in light_names:
|
||||||
|
req.add_param(light_name)
|
||||||
|
|
||||||
|
res = con.request(req)
|
||||||
|
return res.get_data()
|
||||||
@@ -41,6 +41,7 @@ namespace avs {
|
|||||||
AVS_FS_CLOSE_T avs_fs_close {};
|
AVS_FS_CLOSE_T avs_fs_close {};
|
||||||
AVS_FS_DUMP_MOUNTPOINT_T avs_fs_dump_mountpoint {};
|
AVS_FS_DUMP_MOUNTPOINT_T avs_fs_dump_mountpoint {};
|
||||||
AVS_FS_MOUNT_T avs_fs_mount {};
|
AVS_FS_MOUNT_T avs_fs_mount {};
|
||||||
|
AVS_FS_UMOUNT_T avs_fs_umount {};
|
||||||
AVS_FS_COPY_T avs_fs_copy {};
|
AVS_FS_COPY_T avs_fs_copy {};
|
||||||
AVS_FS_FSTAT_T avs_fs_fstat {};
|
AVS_FS_FSTAT_T avs_fs_fstat {};
|
||||||
AVS_FS_LSTAT_T avs_fs_lstat {};
|
AVS_FS_LSTAT_T avs_fs_lstat {};
|
||||||
@@ -927,6 +928,7 @@ namespace avs {
|
|||||||
.avs_fs_close = "XCgsqzn0000055",
|
.avs_fs_close = "XCgsqzn0000055",
|
||||||
.avs_fs_dump_mountpoint = "XCgsqzn0000068",
|
.avs_fs_dump_mountpoint = "XCgsqzn0000068",
|
||||||
.avs_fs_mount = "XCgsqzn000004b",
|
.avs_fs_mount = "XCgsqzn000004b",
|
||||||
|
.avs_fs_umount = "XCgsqzn000004d",
|
||||||
.avs_fs_fstat = "XCgsqzn0000062",
|
.avs_fs_fstat = "XCgsqzn0000062",
|
||||||
.avs_fs_lstat = "XCgsqzn0000063",
|
.avs_fs_lstat = "XCgsqzn0000063",
|
||||||
.avs_fs_lseek = "XCgsqzn000004f",
|
.avs_fs_lseek = "XCgsqzn000004f",
|
||||||
@@ -1018,6 +1020,7 @@ namespace avs {
|
|||||||
.avs_fs_close = "XCgsqzn0000055",
|
.avs_fs_close = "XCgsqzn0000055",
|
||||||
.avs_fs_dump_mountpoint = "XCgsqzn0000068",
|
.avs_fs_dump_mountpoint = "XCgsqzn0000068",
|
||||||
.avs_fs_mount = "XCgsqzn000004b",
|
.avs_fs_mount = "XCgsqzn000004b",
|
||||||
|
.avs_fs_umount = "XCgsqzn000004d",
|
||||||
.avs_fs_fstat = "XCgsqzn0000062",
|
.avs_fs_fstat = "XCgsqzn0000062",
|
||||||
.avs_fs_lstat = "XCgsqzn0000063",
|
.avs_fs_lstat = "XCgsqzn0000063",
|
||||||
.avs_fs_lseek = "XCgsqzn000004f",
|
.avs_fs_lseek = "XCgsqzn000004f",
|
||||||
@@ -1601,6 +1604,8 @@ namespace avs {
|
|||||||
DLL_INSTANCE, IMPORTS[ver].avs_fs_dump_mountpoint);
|
DLL_INSTANCE, IMPORTS[ver].avs_fs_dump_mountpoint);
|
||||||
avs_fs_mount = libutils::try_proc<AVS_FS_MOUNT_T>(
|
avs_fs_mount = libutils::try_proc<AVS_FS_MOUNT_T>(
|
||||||
DLL_INSTANCE, IMPORTS[ver].avs_fs_mount);
|
DLL_INSTANCE, IMPORTS[ver].avs_fs_mount);
|
||||||
|
avs_fs_umount = libutils::try_proc<AVS_FS_UMOUNT_T>(
|
||||||
|
DLL_INSTANCE, IMPORTS[ver].avs_fs_umount);
|
||||||
avs_fs_lstat = libutils::try_proc<AVS_FS_LSTAT_T>(
|
avs_fs_lstat = libutils::try_proc<AVS_FS_LSTAT_T>(
|
||||||
DLL_INSTANCE, IMPORTS[ver].avs_fs_lstat);
|
DLL_INSTANCE, IMPORTS[ver].avs_fs_lstat);
|
||||||
|
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ namespace avs {
|
|||||||
const char *avs_fs_close = "?";
|
const char *avs_fs_close = "?";
|
||||||
const char *avs_fs_dump_mountpoint = "?";
|
const char *avs_fs_dump_mountpoint = "?";
|
||||||
const char *avs_fs_mount = "?";
|
const char *avs_fs_mount = "?";
|
||||||
|
const char *avs_fs_umount = "?";
|
||||||
const char *avs_fs_fstat = "?";
|
const char *avs_fs_fstat = "?";
|
||||||
const char *avs_fs_lstat = "?";
|
const char *avs_fs_lstat = "?";
|
||||||
const char *avs_fs_lseek = "?";
|
const char *avs_fs_lseek = "?";
|
||||||
@@ -513,9 +514,12 @@ namespace avs {
|
|||||||
typedef int (*AVS_FS_DUMP_MOUNTPOINT_T)(void);
|
typedef int (*AVS_FS_DUMP_MOUNTPOINT_T)(void);
|
||||||
extern AVS_FS_DUMP_MOUNTPOINT_T avs_fs_dump_mountpoint;
|
extern AVS_FS_DUMP_MOUNTPOINT_T avs_fs_dump_mountpoint;
|
||||||
|
|
||||||
typedef int (*AVS_FS_MOUNT_T)(const char *mountpoint, const char *fsroot, const char *fstype, void *data);
|
typedef avs_file_t (*AVS_FS_MOUNT_T)(const char *mountpoint, const char *fsroot, const char *fstype, void *data);
|
||||||
extern AVS_FS_MOUNT_T avs_fs_mount;
|
extern AVS_FS_MOUNT_T avs_fs_mount;
|
||||||
|
|
||||||
|
typedef void (*AVS_FS_UMOUNT_T)(avs_file_t mount);
|
||||||
|
extern AVS_FS_UMOUNT_T avs_fs_umount;
|
||||||
|
|
||||||
typedef int (*AVS_FS_COPY_T)(const char *sname, const char *dname);
|
typedef int (*AVS_FS_COPY_T)(const char *sname, const char *dname);
|
||||||
extern AVS_FS_COPY_T avs_fs_copy;
|
extern AVS_FS_COPY_T avs_fs_copy;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef RCDATA
|
||||||
|
#define RCDATA 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SPICE64
|
||||||
|
DMO_BLOB RCDATA "dsdmo.x86_64.dll"
|
||||||
|
#else
|
||||||
|
DMO_BLOB RCDATA "dsdmo.i686.dll"
|
||||||
|
#endif
|
||||||
@@ -40,6 +40,7 @@ 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_BRANCH="${GIT_BRANCH//\//-}"
|
||||||
GIT_HEAD=$(git rev-parse HEAD || echo "none")
|
GIT_HEAD=$(git rev-parse HEAD || echo "none")
|
||||||
TOOLCHAIN_32="${TOOLCHAIN_32:-"/usr/share/mingw/toolchain-i686-w64-mingw32.cmake"}"
|
TOOLCHAIN_32="${TOOLCHAIN_32:-"/usr/share/mingw/toolchain-i686-w64-mingw32.cmake"}"
|
||||||
TOOLCHAIN_64="${TOOLCHAIN_64:-"/usr/share/mingw/toolchain-x86_64-w64-mingw32.cmake"}"
|
TOOLCHAIN_64="${TOOLCHAIN_64:-"/usr/share/mingw/toolchain-x86_64-w64-mingw32.cmake"}"
|
||||||
|
|||||||
Executable
+88
@@ -0,0 +1,88 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
: ${_G_buildir:="bin/build"}
|
||||||
|
: ${_G_bindir:="bin"}
|
||||||
|
: ${_G_debug:=false}
|
||||||
|
: ${_G_clean:=false}
|
||||||
|
|
||||||
|
# Hidden build all temporary environment for sourcing
|
||||||
|
<<__BUILDALLINIT__
|
||||||
|
# Auto-config for build_all.sh
|
||||||
|
GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2> /dev/null || echo "none")
|
||||||
|
GIT_HEAD=$(git rev-parse --short HEAD || echo "none")
|
||||||
|
BUILD_TYPE=$({ $_G_debug && echo Debug; } || echo Release)
|
||||||
|
OUTDIR="$_G_bindir/${BUILD_TYPE}"
|
||||||
|
OUTDIR_EXTRAS="$OUTDIR/extras"
|
||||||
|
DIST_FOLDER="$_G_bindir/Distribution"
|
||||||
|
DIST_NAME="${GIT_BRANCH}-${GIT_HEAD}.zip"
|
||||||
|
DIST_COMMENT="$(date +%Y)/$(date +%m)/$(date +%d):$(git rev-parse HEAD)"
|
||||||
|
DIST_ENABLE=0
|
||||||
|
UPX_ENABLE="$DIST_ENABLE"
|
||||||
|
IGNORE_CACHE=0
|
||||||
|
INCLUDE_SRC=0
|
||||||
|
UPX_FLAGS="-q --best --lzma --compress-exports=0"
|
||||||
|
CLEAN_BUILD=$({ $_G_clean && echo 1; } || echo 0)
|
||||||
|
DEBUG=$({ $_G_debug && echo 1; } || echo 0)
|
||||||
|
TOOLCHAIN_32="external/cmake-various/toolchain/toolchain-mingw_nix-win-x86.cmake"
|
||||||
|
TARGETS_32="spicetools_stubs_kbt spicetools_stubs_kld spicetools_cfg spicetools_spice spicetools_spice_laa spicetools_stubs_cpusbxpkm"
|
||||||
|
BUILDDIR_32="$_G_buildir/x86/${BUILD_TYPE}"
|
||||||
|
TOOLCHAIN_64="external/cmake-various/toolchain/toolchain-mingw_nix-win-x64.cmake"
|
||||||
|
TARGETS_64="spicetools_stubs_kbt64 spicetools_stubs_kld64 spicetools_spice64 spicetools_stubs_nvEncodeAPI64 spicetools_stubs_nvcuvid spicetools_stubs_nvcuda"
|
||||||
|
BUILDDIR_64="$_G_buildir/x64/${BUILD_TYPE}"
|
||||||
|
__BUILDALLINIT__
|
||||||
|
|
||||||
|
run_build_all() {
|
||||||
|
# Init build_all.sh
|
||||||
|
source <(sed -n '/__BUILDALLINIT__/{:a;n;/__BUILDALLINIT__/q;p;$!ba}' "$0")
|
||||||
|
source <(head -n +20 ./build_all.sh)
|
||||||
|
|
||||||
|
# Run build_all.sh
|
||||||
|
source <(tail -n +80 ./build_all.sh | head -n -3 | sed -e 's~mkdir -p ${OUTDIR}/src~~' -e '/linux/d')
|
||||||
|
}
|
||||||
|
|
||||||
|
run_deploy_all() {
|
||||||
|
# Init build_all.sh
|
||||||
|
source <(sed -n '/__BUILDALLINIT__/{:a;n;/__BUILDALLINIT__/q;p;$!ba}' "$0")
|
||||||
|
source <(head -n +20 ./build_all.sh)
|
||||||
|
|
||||||
|
# Run deploy in build_all.sh
|
||||||
|
set +e
|
||||||
|
source <(tail -n +182 ./build_all.sh | head -n -3 | sed -e 's~mkdir -p ${OUTDIR}/src~~' -e '/linux/d')
|
||||||
|
}
|
||||||
|
|
||||||
|
run_distribute_all() {
|
||||||
|
# Init build_all.sh
|
||||||
|
source <(sed -n '/__BUILDALLINIT__/{:a;n;/__BUILDALLINIT__/q;p;$!ba}' "$0")
|
||||||
|
source <(head -n +20 ./build_all.sh)
|
||||||
|
|
||||||
|
# Run deploy in build_all.sh
|
||||||
|
source <(tail -n +182 ./build_all.sh | head -n -3 | sed -e 's~mkdir -p ${OUTDIR}/src~~' -e '/linux/d')
|
||||||
|
|
||||||
|
# Use old distribute logic
|
||||||
|
echo "Building dist..."
|
||||||
|
mkdir -p ${DIST_FOLDER}
|
||||||
|
rm -rf ${DIST_FOLDER}/${DIST_NAME}
|
||||||
|
pushd ${OUTDIR} > /dev/null
|
||||||
|
zip -qrXT9 $OLDPWD/${DIST_FOLDER}/${DIST_NAME} . -z <<< "$DIST_COMMENT"
|
||||||
|
popd > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
run_clion_init() {
|
||||||
|
# Init cmake.sh only
|
||||||
|
source <(sed -n '/__BUILDALLINIT__/{:a;n;/__BUILDALLINIT__/q;p;$!ba}' "$0")
|
||||||
|
|
||||||
|
# Clion specific first-time setup
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sanity checks
|
||||||
|
[ -d "external/cmake-various/toolchain" ] || { echo "Toolchain not found" ; exit 1; }
|
||||||
|
[ "$(md5sum ./build_all.sh | cut -c -32)" = "5c5d7152a1bff96962223458fdf690a2" ] || { echo "Version mismatch for build_all.sh " ; exit 1; }
|
||||||
|
|
||||||
|
# Run requested task
|
||||||
|
if [[ $(type -t "run_${1}_${2}") == function ]]; then
|
||||||
|
echo "Starting task: 'run_${1}_${2}'"
|
||||||
|
"run_${1}_${2}"
|
||||||
|
else
|
||||||
|
echo "Invalid task: 'run_${1}_${2}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
+1
@@ -7,6 +7,7 @@ RUN pacman --noconfirm -Syu git \
|
|||||||
ninja \
|
ninja \
|
||||||
cmake \
|
cmake \
|
||||||
unzip \
|
unzip \
|
||||||
|
wget \
|
||||||
mingw-w64-crt \
|
mingw-w64-crt \
|
||||||
mingw-w64-winpthreads \
|
mingw-w64-winpthreads \
|
||||||
mingw-w64-gcc \
|
mingw-w64-gcc \
|
||||||
|
|||||||
Vendored
+62
@@ -31,8 +31,65 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
#include "hooks/sleephook.h"
|
#include "hooks/sleephook.h"
|
||||||
|
|
||||||
|
//_INFO: Lazy load winscard, not tested on actual hardware
|
||||||
|
struct Winscard
|
||||||
|
{
|
||||||
|
|
||||||
|
decltype(&::SCardEstablishContext) SCardEstablishContext;
|
||||||
|
decltype(&::SCardListReadersA) SCardListReadersA;
|
||||||
|
decltype(&::SCardFreeMemory) SCardFreeMemory;
|
||||||
|
decltype(&::SCardGetStatusChangeA) SCardGetStatusChangeA;
|
||||||
|
decltype(&::SCardConnectA) SCardConnectA;
|
||||||
|
decltype(&::SCardTransmit) SCardTransmit;
|
||||||
|
decltype(&::SCardStatusA) SCardStatusA;
|
||||||
|
decltype(&::SCardDisconnect) SCardDisconnect;
|
||||||
|
decltype(::g_rgSCardT0Pci)* g_rgSCardT0Pci;
|
||||||
|
decltype(::g_rgSCardT1Pci)* g_rgSCardT1Pci;
|
||||||
|
inline static Winscard *instance = nullptr;
|
||||||
|
|
||||||
|
static HMODULE attach()
|
||||||
|
{
|
||||||
|
if (instance) return instance->lib_;
|
||||||
|
instance = new Winscard();
|
||||||
|
return instance->lib_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HMODULE lib_;
|
||||||
|
|
||||||
|
Winscard()
|
||||||
|
{
|
||||||
|
#define GETPROC(name) (name) = reinterpret_cast<decltype(name)>(GetProcAddress(lib_, #name))
|
||||||
|
if ((lib_ = libutils::try_library("winscard.dll")))
|
||||||
|
{
|
||||||
|
GETPROC(SCardEstablishContext);
|
||||||
|
GETPROC(SCardListReadersA);
|
||||||
|
GETPROC(SCardFreeMemory);
|
||||||
|
GETPROC(SCardGetStatusChangeA);
|
||||||
|
GETPROC(SCardConnectA);
|
||||||
|
GETPROC(SCardTransmit);
|
||||||
|
GETPROC(SCardStatusA);
|
||||||
|
GETPROC(SCardDisconnect);
|
||||||
|
GETPROC(g_rgSCardT0Pci);
|
||||||
|
GETPROC(g_rgSCardT1Pci);
|
||||||
|
}
|
||||||
|
#undef GETPROC
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#define SCardEstablishContext Winscard::instance->SCardEstablishContext
|
||||||
|
#define SCardListReadersA Winscard::instance->SCardListReadersA
|
||||||
|
#define SCardFreeMemory Winscard::instance->SCardFreeMemory
|
||||||
|
#define SCardGetStatusChangeA Winscard::instance->SCardGetStatusChangeA
|
||||||
|
#define SCardConnectA Winscard::instance->SCardConnectA
|
||||||
|
#define SCardTransmit Winscard::instance->SCardTransmit
|
||||||
|
#define SCardStatusA Winscard::instance->SCardStatusA
|
||||||
|
#define SCardDisconnect Winscard::instance->SCardDisconnect
|
||||||
|
#define g_rgSCardT0Pci (*Winscard::instance->g_rgSCardT0Pci)
|
||||||
|
#define g_rgSCardT1Pci (*Winscard::instance->g_rgSCardT1Pci)
|
||||||
|
|
||||||
#define MAX_APDU_SIZE 255
|
#define MAX_APDU_SIZE 255
|
||||||
#define SCARD_POLL_INTERVAL_MS 100
|
#define SCARD_POLL_INTERVAL_MS 100
|
||||||
|
|
||||||
@@ -419,6 +476,11 @@ int scard_threadmain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void scard_threadstart() {
|
void scard_threadstart() {
|
||||||
|
if(!Winscard::attach())
|
||||||
|
{
|
||||||
|
log_warning("scard", "Support disabled due to missing winscard.dll");
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::thread t(scard_threadmain);
|
std::thread t(scard_threadmain);
|
||||||
t.detach();
|
t.detach();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ games::Game::Game(std::string name) {
|
|||||||
this->name = name;
|
this->name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *games::Game::title() {
|
||||||
|
return this->name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
void games::Game::attach() {
|
void games::Game::attach() {
|
||||||
log_info("game", "attach: {}", name);
|
log_info("game", "attach: {}", name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace games {
|
|||||||
|
|
||||||
// where the main magic will happen
|
// where the main magic will happen
|
||||||
virtual void attach();
|
virtual void attach();
|
||||||
|
virtual const char *title();
|
||||||
|
|
||||||
// optional
|
// optional
|
||||||
virtual void pre_attach();
|
virtual void pre_attach();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#if SPICE64
|
#if SPICE64
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "api/client.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
@@ -443,10 +444,12 @@ namespace games::iidx {
|
|||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < data_size; ++i) {
|
if (api::has_clients()) {
|
||||||
map.data[i].r = data[i * 3];
|
for (size_t i = 0; i < data_size; ++i) {
|
||||||
map.data[i].g = data[i * 3 + 1];
|
map.data[i].r = data[i * 3];
|
||||||
map.data[i].b = data[i * 3 + 2];
|
map.data[i].g = data[i * 3 + 1];
|
||||||
|
map.data[i].b = data[i * 3 + 2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -490,8 +490,8 @@ namespace games::iidx {
|
|||||||
log_fatal("iidx", "BAD MODEL NAME ERROR - TDJ specified, must be LDJ instead");
|
log_fatal("iidx", "BAD MODEL NAME ERROR - TDJ specified, must be LDJ instead");
|
||||||
}
|
}
|
||||||
|
|
||||||
// check -dxmainadapter + TDJ mode
|
// check -monitor + TDJ mode
|
||||||
if (!GRAPHICS_WINDOWED && D3D9_ADAPTER.has_value() && TDJ_MODE) {
|
if (false && !GRAPHICS_WINDOWED && D3D9_ADAPTER.has_value() && TDJ_MODE) {
|
||||||
IIDX_TDJ_MONITOR_WARNING = true;
|
IIDX_TDJ_MONITOR_WARNING = true;
|
||||||
log_warning(
|
log_warning(
|
||||||
"iidx",
|
"iidx",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#if SPICE64
|
#if SPICE64
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "api/client.h"
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
@@ -349,43 +350,29 @@ namespace games::sdvx {
|
|||||||
* 9 - v unit - 258 bytes - 86 colors
|
* 9 - v unit - 258 bytes - 86 colors
|
||||||
*
|
*
|
||||||
* data is stored in RGB order, 3 bytes per color
|
* data is stored in RGB order, 3 bytes per color
|
||||||
*
|
|
||||||
* TODO: expose this data via API
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// data mapping
|
|
||||||
static struct TapeLedMapping {
|
|
||||||
size_t data_size;
|
|
||||||
int index_r, index_g, index_b;
|
|
||||||
|
|
||||||
TapeLedMapping(size_t data_size, int index_r, int index_g, int index_b)
|
|
||||||
: data_size(data_size), index_r(index_r), index_g(index_g), index_b(index_b) {}
|
|
||||||
|
|
||||||
} mapping[] = {
|
|
||||||
{ 74, Lights::TITLE_AVG_R, Lights::TITLE_AVG_G, Lights::TITLE_AVG_B },
|
|
||||||
{ 12, Lights::UPPER_LEFT_SPEAKER_AVG_R, Lights::UPPER_LEFT_SPEAKER_AVG_G, Lights::UPPER_LEFT_SPEAKER_AVG_B },
|
|
||||||
{ 12, Lights::UPPER_RIGHT_SPEAKER_AVG_R, Lights::UPPER_RIGHT_SPEAKER_AVG_G, Lights::UPPER_RIGHT_SPEAKER_AVG_B },
|
|
||||||
{ 56, Lights::LEFT_WING_AVG_R, Lights::LEFT_WING_AVG_G, Lights::LEFT_WING_AVG_B },
|
|
||||||
{ 56, Lights::RIGHT_WING_AVG_R, Lights::RIGHT_WING_AVG_G, Lights::RIGHT_WING_AVG_B },
|
|
||||||
{ 94, Lights::CONTROL_PANEL_AVG_R, Lights::CONTROL_PANEL_AVG_G, Lights::CONTROL_PANEL_AVG_B },
|
|
||||||
{ 12, Lights::LOWER_LEFT_SPEAKER_AVG_R, Lights::LOWER_LEFT_SPEAKER_AVG_G, Lights::LOWER_LEFT_SPEAKER_AVG_B },
|
|
||||||
{ 12, Lights::LOWER_RIGHT_SPEAKER_AVG_R, Lights::LOWER_RIGHT_SPEAKER_AVG_G, Lights::LOWER_RIGHT_SPEAKER_AVG_B },
|
|
||||||
{ 14, Lights::WOOFER_AVG_R, Lights::WOOFER_AVG_G, Lights::WOOFER_AVG_B },
|
|
||||||
{ 86, Lights::V_UNIT_AVG_R, Lights::V_UNIT_AVG_G, Lights::V_UNIT_AVG_B },
|
|
||||||
};
|
|
||||||
|
|
||||||
// check index bounds
|
// check index bounds
|
||||||
if (tapeledutils::is_enabled() && index < std::size(mapping)) {
|
if (tapeledutils::is_enabled() && index < std::size(TAPELED_MAPPING)) {
|
||||||
auto &map = mapping[index];
|
auto &map = TAPELED_MAPPING[index];
|
||||||
|
const auto data_size = map.data.size();
|
||||||
|
|
||||||
// pick a color to use
|
// pick a color to use
|
||||||
const auto rgb = tapeledutils::pick_color_from_led_tape(data, map.data_size);
|
const auto rgb = tapeledutils::pick_color_from_led_tape(data, data_size);
|
||||||
|
|
||||||
// program the lights into API
|
// program the lights into API
|
||||||
auto &lights = get_lights();
|
auto &lights = get_lights();
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_r], rgb.r);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_g], rgb.g);
|
||||||
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
GameAPI::Lights::writeLight(RI_MGR, lights[map.index_b], rgb.b);
|
||||||
|
|
||||||
|
if (api::has_clients()) {
|
||||||
|
for (size_t i = 0; i < data_size; ++i) {
|
||||||
|
map.data[i].r = data[i * 3];
|
||||||
|
map.data[i].g = data[i * 3 + 1];
|
||||||
|
map.data[i].b = data[i * 3 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (This != custom_node) {
|
if (This != custom_node) {
|
||||||
|
|||||||
@@ -61,6 +61,19 @@ namespace games::sdvx {
|
|||||||
static HKEY real_asio_reg_handle = nullptr;
|
static HKEY real_asio_reg_handle = nullptr;
|
||||||
static HKEY real_asio_device_reg_handle = nullptr;
|
static HKEY real_asio_device_reg_handle = nullptr;
|
||||||
|
|
||||||
|
tapeledutils::tape_led TAPELED_MAPPING[SDVX_TAPELED_TOTAL] = {
|
||||||
|
{ 74, Lights::TITLE_AVG_R, Lights::TITLE_AVG_G, Lights::TITLE_AVG_B, "Title" },
|
||||||
|
{ 12, Lights::UPPER_LEFT_SPEAKER_AVG_R, Lights::UPPER_LEFT_SPEAKER_AVG_G, Lights::UPPER_LEFT_SPEAKER_AVG_B, "Upper Left Speaker" },
|
||||||
|
{ 12, Lights::UPPER_RIGHT_SPEAKER_AVG_R, Lights::UPPER_RIGHT_SPEAKER_AVG_G, Lights::UPPER_RIGHT_SPEAKER_AVG_B, "Upper Right Speaker" },
|
||||||
|
{ 56, Lights::LEFT_WING_AVG_R, Lights::LEFT_WING_AVG_G, Lights::LEFT_WING_AVG_B, "Left Wing" },
|
||||||
|
{ 56, Lights::RIGHT_WING_AVG_R, Lights::RIGHT_WING_AVG_G, Lights::RIGHT_WING_AVG_B, "Right Wing" },
|
||||||
|
{ 94, Lights::CONTROL_PANEL_AVG_R, Lights::CONTROL_PANEL_AVG_G, Lights::CONTROL_PANEL_AVG_B, "Control Panel" },
|
||||||
|
{ 12, Lights::LOWER_LEFT_SPEAKER_AVG_R, Lights::LOWER_LEFT_SPEAKER_AVG_G, Lights::LOWER_LEFT_SPEAKER_AVG_B, "Lower Left Speaker" },
|
||||||
|
{ 12, Lights::LOWER_RIGHT_SPEAKER_AVG_R, Lights::LOWER_RIGHT_SPEAKER_AVG_G, Lights::LOWER_RIGHT_SPEAKER_AVG_B, "Lower Right Speaker" },
|
||||||
|
{ 14, Lights::WOOFER_AVG_R, Lights::WOOFER_AVG_G, Lights::WOOFER_AVG_B, "Woofer" },
|
||||||
|
{ 86, Lights::V_UNIT_AVG_R, Lights::V_UNIT_AVG_G, Lights::V_UNIT_AVG_B, "V Unit" },
|
||||||
|
};
|
||||||
|
|
||||||
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
static LONG WINAPI RegOpenKeyA_hook(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult) {
|
||||||
if (lpSubKey != nullptr &&
|
if (lpSubKey != nullptr &&
|
||||||
phkResult != nullptr &&
|
phkResult != nullptr &&
|
||||||
@@ -353,8 +366,8 @@ namespace games::sdvx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SPICE64 // SDVX5+ specific code
|
#ifdef SPICE64 // SDVX5+ specific code
|
||||||
// check -dxmainadapter + UFC mode
|
// check -monitor + UFC mode
|
||||||
if (!GRAPHICS_WINDOWED && D3D9_ADAPTER.has_value() && is_valkyrie_model()) {
|
if (false && !GRAPHICS_WINDOWED && D3D9_ADAPTER.has_value() && is_valkyrie_model()) {
|
||||||
SHOW_VM_MONITOR_WARNING = true;
|
SHOW_VM_MONITOR_WARNING = true;
|
||||||
log_warning(
|
log_warning(
|
||||||
"sdvx",
|
"sdvx",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "games/game.h"
|
#include "games/game.h"
|
||||||
|
#include "util/tapeled.h"
|
||||||
|
|
||||||
namespace games::sdvx {
|
namespace games::sdvx {
|
||||||
|
|
||||||
@@ -25,6 +26,9 @@ namespace games::sdvx {
|
|||||||
// states
|
// states
|
||||||
extern bool SHOW_VM_MONITOR_WARNING;
|
extern bool SHOW_VM_MONITOR_WARNING;
|
||||||
|
|
||||||
|
constexpr int SDVX_TAPELED_TOTAL = 10;
|
||||||
|
extern tapeledutils::tape_led TAPELED_MAPPING[SDVX_TAPELED_TOTAL];
|
||||||
|
|
||||||
static inline bool is_valkyrie_model() {
|
static inline bool is_valkyrie_model() {
|
||||||
return (
|
return (
|
||||||
avs::game::is_model("KFC") &&
|
avs::game::is_model("KFC") &&
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ namespace hooks::audio {
|
|||||||
enum class Backend {
|
enum class Backend {
|
||||||
Asio,
|
Asio,
|
||||||
WaveOut,
|
WaveOut,
|
||||||
|
Pipewire,
|
||||||
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// surround-to-stereo downmix algorithm
|
// surround-to-stereo downmix algorithm
|
||||||
@@ -64,6 +66,10 @@ namespace hooks::audio {
|
|||||||
return Backend::Asio;
|
return Backend::Asio;
|
||||||
} else if (_stricmp(value, "waveout") == 0) {
|
} else if (_stricmp(value, "waveout") == 0) {
|
||||||
return Backend::WaveOut;
|
return Backend::WaveOut;
|
||||||
|
} else if (_stricmp(value, "pipewire") == 0) {
|
||||||
|
return Backend::Pipewire;
|
||||||
|
} else if (_stricmp(value, "none") == 0) {
|
||||||
|
return Backend::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#include "hooks/audio/backends/wasapi/util.h"
|
#include "hooks/audio/backends/wasapi/util.h"
|
||||||
#include "hooks/audio/implementations/asio.h"
|
#include "hooks/audio/implementations/asio.h"
|
||||||
#include "hooks/audio/implementations/wave_out.h"
|
#include "hooks/audio/implementations/wave_out.h"
|
||||||
|
#include "hooks/audio/implementations/pipewire.h"
|
||||||
|
#include "hooks/audio/implementations/none.h"
|
||||||
//#include "util/co_task_mem_ptr.h"
|
//#include "util/co_task_mem_ptr.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
@@ -78,6 +80,12 @@ IAudioClient *wrap_audio_client(IAudioClient *audio_client) {
|
|||||||
case hooks::audio::Backend::WaveOut:
|
case hooks::audio::Backend::WaveOut:
|
||||||
backend = new WaveOutBackend();
|
backend = new WaveOutBackend();
|
||||||
break;
|
break;
|
||||||
|
case hooks::audio::Backend::Pipewire:
|
||||||
|
backend = new PipewireBackend();
|
||||||
|
break;
|
||||||
|
case hooks::audio::Backend::None:
|
||||||
|
backend = new NoneBackend();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ HRESULT STDMETHODCALLTYPE DummyIAudioClient::Initialize(
|
|||||||
log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
|
log_info("audio::wasapi", "IAudioClient::Initialize hook hit");
|
||||||
print_format(ShareMode, StreamFlags, hnsBufferDuration, hnsPeriodicity, pFormat);
|
print_format(ShareMode, StreamFlags, hnsBufferDuration, hnsPeriodicity, pFormat);
|
||||||
|
|
||||||
|
log_info("audio::wasapi", "IAudioClient::Initialize forwarding format");
|
||||||
|
copy_wave_format(&hooks::audio::FORMAT, pFormat);
|
||||||
|
|
||||||
HRESULT ret = this->backend->on_initialize(
|
HRESULT ret = this->backend->on_initialize(
|
||||||
&ShareMode,
|
&ShareMode,
|
||||||
&StreamFlags,
|
&StreamFlags,
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ static SampleType convert_asio_sample_type(AsioSampleType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsioBackend::AsioBackend() {
|
AsioBackend::AsioBackend() : format_(hooks::audio::FORMAT) {
|
||||||
this->asio_thread = std::thread([this]() {
|
this->asio_thread = std::thread([this]() {
|
||||||
std::unique_lock<std::mutex> lock_handle(this->asio_thread_state_lock);
|
std::unique_lock<std::mutex> lock_handle(this->asio_thread_state_lock);
|
||||||
|
|
||||||
@@ -777,7 +777,6 @@ HRESULT AsioBackend::on_initialize(
|
|||||||
{
|
{
|
||||||
AsioError result;
|
AsioError result;
|
||||||
|
|
||||||
copy_wave_format(&this->format_, pFormat);
|
|
||||||
memcpy(&this->last_checked_format, &this->format_, sizeof(this->format_));
|
memcpy(&this->last_checked_format, &this->format_, sizeof(this->format_));
|
||||||
|
|
||||||
if (!this->asio_thread_initialized) {
|
if (!this->asio_thread_initialized) {
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ private:
|
|||||||
SampleType asio_sample_type = SampleType::UNSUPPORTED;
|
SampleType asio_sample_type = SampleType::UNSUPPORTED;
|
||||||
|
|
||||||
std::atomic_bool started = false;
|
std::atomic_bool started = false;
|
||||||
WAVEFORMATEXTENSIBLE format_ {};
|
const WAVEFORMATEXTENSIBLE &format_;
|
||||||
WAVEFORMATEXTENSIBLE last_checked_format {};
|
WAVEFORMATEXTENSIBLE last_checked_format {};
|
||||||
|
|
||||||
//std::vector<BYTE> last_sound_buffer;
|
//std::vector<BYTE> last_sound_buffer;
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#include "none.h"
|
||||||
|
#include "hooks/audio/audio.h"
|
||||||
|
#include "hooks/audio/backends/wasapi/audio_client.h"
|
||||||
|
|
||||||
|
|
||||||
|
const WAVEFORMATEXTENSIBLE &NoneBackend::format() const noexcept {
|
||||||
|
return format_;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT NoneBackend::on_initialize(
|
||||||
|
AUDCLNT_SHAREMODE *ShareMode,
|
||||||
|
DWORD *StreamFlags,
|
||||||
|
REFERENCE_TIME *hnsBufferDuration,
|
||||||
|
REFERENCE_TIME *hnsPeriodicity,
|
||||||
|
const WAVEFORMATEX *pFormat,
|
||||||
|
LPCGUID AudioSessionGuid) noexcept
|
||||||
|
{
|
||||||
|
*ShareMode = AUDCLNT_SHAREMODE_SHARED;
|
||||||
|
*StreamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
|
||||||
|
AUDCLNT_STREAMFLAGS_RATEADJUST |
|
||||||
|
AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
|
||||||
|
AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||||
|
*hnsBufferDuration = 100000;
|
||||||
|
*hnsPeriodicity = 100000;
|
||||||
|
log_info("audio::none", "on_initialize");
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_get_buffer_size(uint32_t *buffer_frames) noexcept {
|
||||||
|
*buffer_frames = 0;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_get_stream_latency(REFERENCE_TIME *latency) noexcept {
|
||||||
|
*latency = 100000;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept {
|
||||||
|
|
||||||
|
padding_frames = 0;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_is_format_supported(
|
||||||
|
AUDCLNT_SHAREMODE *ShareMode,
|
||||||
|
const WAVEFORMATEX *pFormat,
|
||||||
|
WAVEFORMATEX **ppClosestMatch) noexcept
|
||||||
|
{
|
||||||
|
// only accept 44.1 kHz, stereo, 16-bits per channel
|
||||||
|
if (*ShareMode == AUDCLNT_SHAREMODE_EXCLUSIVE &&
|
||||||
|
pFormat->nChannels == 2 &&
|
||||||
|
pFormat->nSamplesPerSec == 44100 &&
|
||||||
|
pFormat->wBitsPerSample == 16)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept {
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_get_device_period(
|
||||||
|
REFERENCE_TIME *default_device_period,
|
||||||
|
REFERENCE_TIME *minimum_device_period)
|
||||||
|
{
|
||||||
|
*default_device_period = 10000;
|
||||||
|
*minimum_device_period = 10000;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_start() noexcept {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_stop() noexcept {
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_set_event_handle(HANDLE *event_handle) {
|
||||||
|
|
||||||
|
*event_handle = CreateEvent(nullptr, true, false, nullptr);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT NoneBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) {
|
||||||
|
static BYTE buf[10000];
|
||||||
|
*ppData = buf;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT NoneBackend::on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) {
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
NoneBackend::NoneBackend() : format_(hooks::audio::FORMAT)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "backend.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct NoneBackend final : AudioBackend {
|
||||||
|
public:
|
||||||
|
explicit NoneBackend();
|
||||||
|
~NoneBackend() final = default;
|
||||||
|
|
||||||
|
[[nodiscard]] const WAVEFORMATEXTENSIBLE &format() const noexcept override;
|
||||||
|
|
||||||
|
HRESULT on_initialize(
|
||||||
|
AUDCLNT_SHAREMODE *ShareMode,
|
||||||
|
DWORD *StreamFlags,
|
||||||
|
REFERENCE_TIME *hnsBufferDuration,
|
||||||
|
REFERENCE_TIME *hnsPeriodicity,
|
||||||
|
const WAVEFORMATEX *pFormat,
|
||||||
|
LPCGUID AudioSessionGuid) noexcept override;
|
||||||
|
|
||||||
|
HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override;
|
||||||
|
HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override;
|
||||||
|
HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept override;
|
||||||
|
|
||||||
|
HRESULT on_is_format_supported(
|
||||||
|
AUDCLNT_SHAREMODE *ShareMode,
|
||||||
|
const WAVEFORMATEX *pFormat,
|
||||||
|
WAVEFORMATEX **ppClosestMatch) noexcept override;
|
||||||
|
|
||||||
|
HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override;
|
||||||
|
|
||||||
|
HRESULT on_get_device_period(
|
||||||
|
REFERENCE_TIME *default_device_period,
|
||||||
|
REFERENCE_TIME *minimum_device_period) override;
|
||||||
|
|
||||||
|
HRESULT on_start() noexcept override;
|
||||||
|
HRESULT on_stop() noexcept override;
|
||||||
|
HRESULT on_set_event_handle(HANDLE *event_handle) override;
|
||||||
|
|
||||||
|
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) override;
|
||||||
|
HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const WAVEFORMATEXTENSIBLE &format_;
|
||||||
|
BYTE *active_sound_buffer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
#include <winternl.h>
|
||||||
|
#include "pipewire.h"
|
||||||
|
#include "hooks/audio/audio.h"
|
||||||
|
#include "hooks/audio/backends/wasapi/audio_client.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "launcher/launcher.h"
|
||||||
|
#include "hooks/audio/util.h"
|
||||||
|
#include "hooks/audio/backends/wasapi/util.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
... ShareMode : AUDCLNT_SHAREMODE_EXCLUSIVE <- backend to reimplement, THIS is the audio engine, GAME is client https://learn.microsoft.com/en-us/windows/win32/coreaudio/audclnt-streamflags-xxx-constants
|
||||||
|
... StreamFlags : AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST <- first is the whole reason for relay_handle_ requirement, second flag not tested
|
||||||
|
... hnsBufferDuration : 10000 <- wasapi people inventing new time units, 1ms (since 1unit==100ns, 10000*0.0001ms)
|
||||||
|
... hnsPeriodicity : 10000 <- same as above (1ms)
|
||||||
|
... nChannels : 2 <- channel_count
|
||||||
|
... nSamplesPerSec : 44100 <- bitrate
|
||||||
|
... nAvgBytesPerSec : 176400 <- raw buffer size per second (bitrate * stride)(bytes)
|
||||||
|
... nBlockAlign : 4 <- stride (bytes)
|
||||||
|
... wBitsPerSample : 16 <- sample size (bits)
|
||||||
|
... wValidBitsPerSample : 16 <- same as above
|
||||||
|
... dwChannelMask : SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT <- position config
|
||||||
|
_INFO: Code pipeline
|
||||||
|
INIT: on_is_format_supported()?->on_initialize()->on_set_event_handle()-:(LOOPx1):->on_start()
|
||||||
|
LOOP: if relay_handle_: on_get_buffer_size()->on_get_buffer()->..->on_release_buffer()
|
||||||
|
DEINIT: on_stop()
|
||||||
|
|
||||||
|
_REV: POSSIBLE ALTERNATIVES:
|
||||||
|
Check if the stream is driving. The stream needs to have the
|
||||||
|
* PW_STREAM_FLAG_DRIVER set. When the stream is driving,
|
||||||
|
* pw_stream_trigger_process() needs to be called when data is
|
||||||
|
* available (output) or needed (input). Since 0.3.34
|
||||||
|
bool pw_stream_is_driving(struct pw_stream *stream);
|
||||||
|
* */
|
||||||
|
|
||||||
|
/* Imports/Exports (refer to bmsound-wine.dll.spec) */
|
||||||
|
typedef void (*BmswConfigInit_t)(const char *);
|
||||||
|
typedef void (*BmswExperimentalForceProfile_t)(const char *);
|
||||||
|
typedef int(*BmswClientFormatIsSupported_t)(DWORD, DWORD, DWORD, void *);
|
||||||
|
typedef int(*BmswClientFormatPeriodFPC_t)(void *);
|
||||||
|
typedef REFERENCE_TIME(*BmswClientFormatPeriodWRT_t)(void *);
|
||||||
|
typedef void *(*BmswClientCreate_t)(const char *, void *, void *);
|
||||||
|
typedef int(*BmswClientStart_t)(void *);
|
||||||
|
typedef int(*BmswClientStop_t)(void *);
|
||||||
|
typedef int(*BmswClientDestroy_t)(void *);
|
||||||
|
typedef unsigned char *(*BmswClientGetBuffer_t)(void *, uint32_t);
|
||||||
|
typedef int(*BmswClientReleaseBuffer_t)(void *, uint32_t);
|
||||||
|
typedef int(*BmswClientAwaitBuffer_t)(void *);
|
||||||
|
typedef void (*BmswClientUpdateCallback_t)(void *, void *, void *);
|
||||||
|
static BmswConfigInit_t BmswConfigInit;
|
||||||
|
[[maybe_unused]] static BmswExperimentalForceProfile_t BmswExperimentalForceProfile;
|
||||||
|
static BmswClientFormatIsSupported_t BmswClientFormatIsSupported;
|
||||||
|
static BmswClientFormatPeriodFPC_t BmswClientFormatPeriodFPC;
|
||||||
|
static BmswClientFormatPeriodWRT_t BmswClientFormatPeriodWRT;
|
||||||
|
static BmswClientCreate_t BmswClientCreate;
|
||||||
|
static BmswClientStart_t BmswClientStart;
|
||||||
|
static BmswClientStop_t BmswClientStop;
|
||||||
|
static BmswClientDestroy_t BmswClientDestroy;
|
||||||
|
static BmswClientGetBuffer_t BmswClientGetBuffer;
|
||||||
|
static BmswClientReleaseBuffer_t BmswClientReleaseBuffer;
|
||||||
|
static BmswClientAwaitBuffer_t BmswClientAwaitBuffer;
|
||||||
|
[[maybe_unused]] static BmswClientUpdateCallback_t BmswClientUpdateCallback;
|
||||||
|
static HMODULE bmsw_ = nullptr;
|
||||||
|
|
||||||
|
/* Audio init (unless specified otherwise, run once at start) */
|
||||||
|
// Reports to game whether each requested audio format is available for device (first success return will be used)
|
||||||
|
HRESULT PipewireBackend::on_is_format_supported(AUDCLNT_SHAREMODE *ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) noexcept
|
||||||
|
{
|
||||||
|
// Format reporting and filtering
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
log_misc("audio::pipewire", "Checking backend support for {} channels, {} Hz, {}-bit",
|
||||||
|
pFormat->nChannels,
|
||||||
|
pFormat->nSamplesPerSec,
|
||||||
|
pFormat->wBitsPerSample);
|
||||||
|
|
||||||
|
// IIDX? will always request format that was last checked through this function
|
||||||
|
if (*ShareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
|
||||||
|
// Request format support from real backend (only accepts 44.1 kHz, stereo, 16-bits per channel for now)
|
||||||
|
return BmswClientFormatIsSupported(pFormat->nSamplesPerSec, pFormat->nChannels, pFormat->wBitsPerSample, nullptr) == 0 ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
|
}
|
||||||
|
// Populate hnsPeriodicity, _INFO: runs before on_initialize, requires configured client stream data
|
||||||
|
HRESULT PipewireBackend::on_get_device_period(REFERENCE_TIME *default_device_period, REFERENCE_TIME *minimum_device_period)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
*default_device_period = wrt_;
|
||||||
|
*minimum_device_period = wrt_;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
// This expects to be run once on_is_format_supported() succeeds, initializes backend based on passed arguments (and updates them if needed)
|
||||||
|
HRESULT PipewireBackend::on_initialize(AUDCLNT_SHAREMODE *ShareMode, DWORD *StreamFlags, REFERENCE_TIME *hnsBufferDuration, REFERENCE_TIME *hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) noexcept
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
|
||||||
|
// Initialize pipewire client (without starting the thread)
|
||||||
|
client_ = BmswClientCreate(GAME_INSTANCE->title(), nullptr, nullptr);
|
||||||
|
notif_ = std::thread(PipewireBackend::notif_poll, this);
|
||||||
|
|
||||||
|
if (!client_)
|
||||||
|
log_fatal("audio::pipewire", "Client could not be initialized");
|
||||||
|
log_info("audio::pipewire", "Client initialized: '{}'", fmt::ptr(client_));
|
||||||
|
|
||||||
|
// Adjust WASAPI configuration visible to game (passed arguments are populated and should match that of last on_is_format_supported call)
|
||||||
|
*hnsBufferDuration = wrt_;
|
||||||
|
*hnsPeriodicity = wrt_;
|
||||||
|
|
||||||
|
//_TODO: Init info
|
||||||
|
log_info("audio::pipewire", "Device Info:");
|
||||||
|
log_info("audio::pipewire", "... hnsBufferDuration : {}", *hnsBufferDuration);
|
||||||
|
log_info("audio::pipewire", "... hnsPeriodicity : {}", *hnsPeriodicity);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
// This takes ownership over shared event handle exclusive to AUDCLNT_STREAMFLAGS_EVENTCALLBACK _INFO: first loop iteration runs directly after this, before on_start() call
|
||||||
|
HRESULT PipewireBackend::on_set_event_handle(HANDLE *event_handle)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
|
||||||
|
// Take over WASAPI's owned handle pre-initialized by client and replace with always off dummy, cleaning up previously owned handle
|
||||||
|
if (relay_handle_) CloseHandle(relay_handle_);
|
||||||
|
relay_handle_ = *event_handle;
|
||||||
|
*event_handle = CreateEvent(nullptr, true, false, nullptr);
|
||||||
|
//BmswClientUpdateCallback(client_, (void *) 0, relay_handle_);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
|
||||||
|
ULONG ntbuf_size = sizeof(OBJECT_NAME_INFORMATION) + 1024;
|
||||||
|
char ntbuf[ntbuf_size];
|
||||||
|
OBJECT_NAME_INFORMATION *ntinfo = (OBJECT_NAME_INFORMATION *) ntbuf;
|
||||||
|
NTSTATUS status = NtQueryObject(*event_handle, ObjectNameInformation, ntinfo, ntbuf_size, &ntbuf_size);
|
||||||
|
if (NT_SUCCESS(status))
|
||||||
|
{
|
||||||
|
// possible to rename anonymous handle to access by name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HRESULT PipewireBackend::on_start() noexcept
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
BmswClientStart(client_);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
PipewireBackend::PipewireBackend() : relay_handle_(CreateEvent(nullptr, true, false, nullptr)), format_(hooks::audio::FORMAT), client_(nullptr), notif_state_(-1)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
|
||||||
|
// Initialize bmsound-wine.dll once
|
||||||
|
if (!bmsw_ && (bmsw_ = libutils::try_library(MODULE_PATH / "bmsound-wine.dll")))
|
||||||
|
{
|
||||||
|
BmswConfigInit = (BmswConfigInit_t) GetProcAddress(bmsw_, "BmswConfigInit");
|
||||||
|
BmswExperimentalForceProfile = (BmswExperimentalForceProfile_t) GetProcAddress(bmsw_, "BmswExperimentalForceProfile");
|
||||||
|
BmswClientFormatIsSupported = (BmswClientFormatIsSupported_t) GetProcAddress(bmsw_, "BmswClientFormatIsSupported");
|
||||||
|
BmswClientFormatPeriodWRT = (BmswClientFormatPeriodWRT_t) GetProcAddress(bmsw_, "BmswClientFormatPeriodWRT");
|
||||||
|
BmswClientFormatPeriodFPC = (BmswClientFormatPeriodFPC_t) GetProcAddress(bmsw_, "BmswClientFormatPeriodFPC");
|
||||||
|
BmswClientCreate = (BmswClientCreate_t) GetProcAddress(bmsw_, "BmswClientCreate");
|
||||||
|
BmswClientStart = (BmswClientStart_t) GetProcAddress(bmsw_, "BmswClientStart");
|
||||||
|
BmswClientStop = (BmswClientStop_t) GetProcAddress(bmsw_, "BmswClientStop");
|
||||||
|
BmswClientDestroy = (BmswClientDestroy_t) GetProcAddress(bmsw_, "BmswClientDestroy");
|
||||||
|
BmswClientGetBuffer = (BmswClientGetBuffer_t) GetProcAddress(bmsw_, "BmswClientGetBuffer");
|
||||||
|
BmswClientReleaseBuffer = (BmswClientReleaseBuffer_t) GetProcAddress(bmsw_, "BmswClientReleaseBuffer");
|
||||||
|
BmswClientAwaitBuffer = (BmswClientAwaitBuffer_t) GetProcAddress(bmsw_, "BmswClientAwaitBuffer");
|
||||||
|
BmswClientUpdateCallback = (BmswClientUpdateCallback_t) GetProcAddress(bmsw_, "BmswClientUpdateCallback");
|
||||||
|
|
||||||
|
// Load config
|
||||||
|
BmswConfigInit("prop/linux.json");
|
||||||
|
//BmswExperimentalForceProfile("notif_spice");
|
||||||
|
}
|
||||||
|
if (bmsw_)
|
||||||
|
{
|
||||||
|
// Sync config
|
||||||
|
wrt_ = BmswClientFormatPeriodWRT(nullptr); //_INFO: wrt affects reported latency (1:100ns)
|
||||||
|
fpc_ = BmswClientFormatPeriodFPC(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_fatal("audio::pipewire", "Library not found: '{}'", (MODULE_PATH / "bmsound-wine.dll").string());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Audio callback loop (reacts to state of relay_handle_, most likely separate thread */
|
||||||
|
// _REV: Synchronizing client and backend with nanotime may be necessary (bmsound-pw endpoint dependant)
|
||||||
|
inline static void callback_notify(void *self)
|
||||||
|
{
|
||||||
|
//log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
auto *self_ = (PipewireBackend *) self;
|
||||||
|
//std::this_thread::sleep_for(std::chrono::nanoseconds(10 * 1000 * 1000 - 227));
|
||||||
|
if (!SetEvent(self_->relay_handle_)) // has to be called for game-side audio loop to continue
|
||||||
|
{
|
||||||
|
DWORD last_error = GetLastError();
|
||||||
|
|
||||||
|
log_warning("audio::pipewire", "SetEvent failed({}): {}",
|
||||||
|
last_error,
|
||||||
|
std::system_category().message(last_error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PipewireBackend::notif_poll(PipewireBackend *self)
|
||||||
|
{
|
||||||
|
self->notif_state_ = BmswClientAwaitBuffer(self->client_);
|
||||||
|
while (self->notif_state_ == 1)
|
||||||
|
{
|
||||||
|
BmswClientAwaitBuffer(self->client_);
|
||||||
|
callback_notify(self);
|
||||||
|
}
|
||||||
|
self->notif_state_ = -1;
|
||||||
|
}
|
||||||
|
// Amount in frames of data we may handle at once (which should always end up being what gets send by client, unless overrun happens)
|
||||||
|
HRESULT PipewireBackend::on_get_buffer_size(uint32_t *buffer_frames) noexcept
|
||||||
|
{
|
||||||
|
static int iterc = -1;
|
||||||
|
if (iterc == -1)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}, frames: {} (INITIAL HIT)", __FUNCTION__, fpc_);
|
||||||
|
iterc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buffer_frames = fpc_;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
// Wants a raw stream buffer to be assigned into *ppData, this stream will have x amount of sound frames stored into it by a client and assumes exclusive access until next on_release_buffer
|
||||||
|
HRESULT PipewireBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData)
|
||||||
|
{
|
||||||
|
static int iterc = -1;
|
||||||
|
if (iterc == -1)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}, frames: {} (INITIAL HIT)", __FUNCTION__, num_frames_requested);
|
||||||
|
}
|
||||||
|
iterc++;
|
||||||
|
if (iterc > 999999)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "on_get_buffer, frames: {} (HIT {})", num_frames_requested, iterc);
|
||||||
|
iterc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppData = BmswClientGetBuffer(client_, num_frames_requested);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
// This releases access to buffer from last on_get_buffer and implies x amount of frames being valid data to be streamed
|
||||||
|
HRESULT PipewireBackend::on_release_buffer(uint32_t num_frames_written, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
static int iterc = -1;
|
||||||
|
if (iterc == -1)
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}, frames: {} (INITIAL HIT)", __FUNCTION__, num_frames_written);
|
||||||
|
iterc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BmswClientReleaseBuffer(client_, num_frames_written);
|
||||||
|
if (notif_state_ == -1) callback_notify(this);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Audio deinit (unless specified otherwise, run once at termination) */
|
||||||
|
HRESULT PipewireBackend::on_stop() noexcept
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
BmswClientStop(client_);
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
PipewireBackend::~PipewireBackend()
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "~PipewireBackend");
|
||||||
|
if (notif_state_ == 1)
|
||||||
|
{
|
||||||
|
notif_state_ = 0;
|
||||||
|
notif_.join();
|
||||||
|
if (notif_state_ != -1)
|
||||||
|
{
|
||||||
|
log_warning("audio::pipewire", "Errors during thread cleanup: '{}'", (const int) notif_state_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (client_) BmswClientDestroy(client_);
|
||||||
|
if (relay_handle_) CloseHandle(relay_handle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unsorted (unknown callers, should be considered as unimplemented/untested) *///_BUG: does this need implementation?
|
||||||
|
const WAVEFORMATEXTENSIBLE &PipewireBackend::format() const noexcept
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
return format_;
|
||||||
|
}
|
||||||
|
HRESULT PipewireBackend::on_get_stream_latency(REFERENCE_TIME *latency) noexcept
|
||||||
|
{
|
||||||
|
// log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
*latency = BmswClientFormatPeriodWRT(client_);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT PipewireBackend::on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept
|
||||||
|
{
|
||||||
|
// log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
padding_frames = 0;
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
HRESULT PipewireBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept
|
||||||
|
{
|
||||||
|
log_info("audio::pipewire", "{}", __FUNCTION__);
|
||||||
|
return E_NOTIMPL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "backend.h"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
struct PipewireBackend final : AudioBackend
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HANDLE relay_handle_;
|
||||||
|
|
||||||
|
explicit PipewireBackend();
|
||||||
|
~PipewireBackend() final;
|
||||||
|
[[nodiscard]] const WAVEFORMATEXTENSIBLE &format() const noexcept override;
|
||||||
|
HRESULT on_initialize(AUDCLNT_SHAREMODE *ShareMode, DWORD *StreamFlags, REFERENCE_TIME *hnsBufferDuration, REFERENCE_TIME *hnsPeriodicity, const WAVEFORMATEX *pFormat, LPCGUID AudioSessionGuid) noexcept override;
|
||||||
|
HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override;
|
||||||
|
HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override;
|
||||||
|
HRESULT on_get_current_padding(std::optional<uint32_t> &padding_frames) noexcept override;
|
||||||
|
HRESULT on_is_format_supported(AUDCLNT_SHAREMODE *ShareMode, const WAVEFORMATEX *pFormat, WAVEFORMATEX **ppClosestMatch) noexcept override;
|
||||||
|
HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override;
|
||||||
|
HRESULT on_get_device_period(REFERENCE_TIME *default_device_period, REFERENCE_TIME *minimum_device_period) override;
|
||||||
|
HRESULT on_start() noexcept override;
|
||||||
|
HRESULT on_stop() noexcept override;
|
||||||
|
HRESULT on_set_event_handle(HANDLE *event_handle) override;
|
||||||
|
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) override;
|
||||||
|
HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) override;
|
||||||
|
static void notif_poll(PipewireBackend *self);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fpc_;
|
||||||
|
REFERENCE_TIME wrt_;
|
||||||
|
const WAVEFORMATEXTENSIBLE &format_;
|
||||||
|
void *client_;
|
||||||
|
std::thread notif_;
|
||||||
|
volatile int notif_state_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
@@ -3,27 +3,35 @@
|
|||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
#include "hooks/audio/backends/wasapi/audio_client.h"
|
#include "hooks/audio/backends/wasapi/audio_client.h"
|
||||||
#include "hooks/audio/backends/wasapi/defs.h"
|
#include "hooks/audio/backends/wasapi/defs.h"
|
||||||
|
#include "hooks/audio/util.h"
|
||||||
|
#include "hooks/audio/buffer.h"
|
||||||
#include "util/precise_timer.h"
|
#include "util/precise_timer.h"
|
||||||
|
|
||||||
static REFERENCE_TIME WASAPI_TARGET_REFTIME = TARGET_REFTIME;
|
static REFERENCE_TIME WASAPI_TARGET_REFTIME = TARGET_REFTIME;
|
||||||
|
|
||||||
HRESULT WaveOutBackend::init(uint32_t buffer_size) {
|
HRESULT WaveOutBackend::init(uint32_t buffer_size) {
|
||||||
auto &format = hooks::audio::FORMAT.Format;
|
MMRESULT ret;
|
||||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
|
|
||||||
log_info("audio::wave_out", "initializing waveOut backend with {} channels, {} Hz, {}-bit",
|
if (format_.Format.nSamplesPerSec == 0)
|
||||||
format.nChannels,
|
{
|
||||||
format.nSamplesPerSec,
|
log_warning("audio::wave_out", "format_ condition race");
|
||||||
format.wBitsPerSample);
|
return static_cast<HRESULT>(MMSYSERR_ERROR);
|
||||||
log_info("audio::wave_out", "... nBlockAlign : {} bytes", format.nBlockAlign);
|
}
|
||||||
log_info("audio::wave_out", "... nAvgBytesPerSec : {} bytes", format.nAvgBytesPerSec);
|
hooks::audio::FORMAT.Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
log_info("audio::wave_out", "initializing waveOut backend with {} channels, {} Hz, {}-bit, {} format",
|
||||||
|
format_.Format.nChannels,
|
||||||
|
format_.Format.nSamplesPerSec,
|
||||||
|
format_.Format.wBitsPerSample,
|
||||||
|
format_.Format.wFormatTag);
|
||||||
|
log_info("audio::wave_out", "... nBlockAlign : {} bytes", format_.Format.nBlockAlign);
|
||||||
|
log_info("audio::wave_out", "... nAvgBytesPerSec : {} bytes", format_.Format.nAvgBytesPerSec);
|
||||||
log_info("audio::wave_out", "... buffer reftime : {} ms", WASAPI_TARGET_REFTIME / 10000.f);
|
log_info("audio::wave_out", "... buffer reftime : {} ms", WASAPI_TARGET_REFTIME / 10000.f);
|
||||||
log_info("audio::wave_out", "... buffer count : {} buffers", _countof(this->hdrs));
|
log_info("audio::wave_out", "... buffer count : {} buffers", _countof(this->hdrs));
|
||||||
|
|
||||||
MMRESULT ret = waveOutOpen(
|
ret = waveOutOpen(
|
||||||
&this->handle,
|
&this->handle,
|
||||||
WAVE_MAPPER,
|
WAVE_MAPPER,
|
||||||
reinterpret_cast<const WAVEFORMATEX *>(&hooks::audio::FORMAT.Format),
|
reinterpret_cast<const WAVEFORMATEX *>(&format_.Format),
|
||||||
reinterpret_cast<DWORD_PTR>(this->dispatcher_event),
|
reinterpret_cast<DWORD_PTR>(this->dispatcher_event),
|
||||||
reinterpret_cast<DWORD_PTR>(nullptr),
|
reinterpret_cast<DWORD_PTR>(nullptr),
|
||||||
CALLBACK_EVENT);
|
CALLBACK_EVENT);
|
||||||
@@ -36,6 +44,7 @@ HRESULT WaveOutBackend::init(uint32_t buffer_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initialize buffers
|
// initialize buffers
|
||||||
|
log_info("audio::wave_out", "... device handle : {}", fmt::ptr(this->handle));
|
||||||
for (auto &hdr : this->hdrs) {
|
for (auto &hdr : this->hdrs) {
|
||||||
memset(&hdr, 0, sizeof(hdr));
|
memset(&hdr, 0, sizeof(hdr));
|
||||||
hdr.lpData = new char[buffer_size] {};
|
hdr.lpData = new char[buffer_size] {};
|
||||||
@@ -71,7 +80,7 @@ HRESULT WaveOutBackend::init(uint32_t buffer_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const WAVEFORMATEXTENSIBLE &WaveOutBackend::format() const noexcept {
|
const WAVEFORMATEXTENSIBLE &WaveOutBackend::format() const noexcept {
|
||||||
return hooks::audio::FORMAT;
|
return format_;
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT WaveOutBackend::on_initialize(
|
HRESULT WaveOutBackend::on_initialize(
|
||||||
@@ -90,6 +99,8 @@ HRESULT WaveOutBackend::on_initialize(
|
|||||||
*hnsBufferDuration = WASAPI_TARGET_REFTIME;
|
*hnsBufferDuration = WASAPI_TARGET_REFTIME;
|
||||||
*hnsPeriodicity = WASAPI_TARGET_REFTIME;
|
*hnsPeriodicity = WASAPI_TARGET_REFTIME;
|
||||||
|
|
||||||
|
log_info("audio::wave_out", "on_initialize");
|
||||||
|
|
||||||
// this backend only supports stereo audio
|
// this backend only supports stereo audio
|
||||||
if (pFormat->nChannels > 2) {
|
if (pFormat->nChannels > 2) {
|
||||||
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
@@ -116,7 +127,7 @@ HRESULT WaveOutBackend::on_get_current_padding(std::optional<uint32_t> &padding_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frames = static_cast<uint32_t>(queued_bytes / hooks::audio::FORMAT.Format.nBlockAlign);
|
auto frames = static_cast<uint32_t>(queued_bytes / format_.Format.nBlockAlign);
|
||||||
//log_info("audio::wave_out", "queued_bytes = {}, frames = {}", queued_bytes, frames);
|
//log_info("audio::wave_out", "queued_bytes = {}, frames = {}", queued_bytes, frames);
|
||||||
|
|
||||||
padding_frames = frames;
|
padding_frames = frames;
|
||||||
@@ -137,6 +148,7 @@ HRESULT WaveOutBackend::on_is_format_supported(
|
|||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//return waveOutOpen(nullptr, WAVE_MAPPER, reinterpret_cast<const WAVEFORMATEX *>(&format_.Format), NULL, NULL, WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR ? S_OK : AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||||
}
|
}
|
||||||
HRESULT WaveOutBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept {
|
HRESULT WaveOutBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept {
|
||||||
@@ -167,17 +179,20 @@ HRESULT WaveOutBackend::on_set_event_handle(HANDLE *event_handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HRESULT WaveOutBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) {
|
HRESULT WaveOutBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) {
|
||||||
auto buffer_size = hooks::audio::FORMAT.Format.nBlockAlign * num_frames_requested;
|
size_t buffer_size = format_.Format.nBlockAlign * num_frames_requested;
|
||||||
|
|
||||||
if (!this->initialized) {
|
if (!this->initialized) {
|
||||||
this->init(buffer_size);
|
this->init(buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t converted_size = required_buffer_size(num_frames_requested, format_.Format.nChannels, SampleType::SINT_16);
|
||||||
|
const size_t max_size = std::max(buffer_size, converted_size);
|
||||||
|
|
||||||
// wait for a free slot
|
// wait for a free slot
|
||||||
WaitForSingleObject(this->dispatcher_event, INFINITE);
|
WaitForSingleObject(this->dispatcher_event, INFINITE);
|
||||||
|
|
||||||
// allocate temporary sound buffer
|
// allocate temporary sound buffer
|
||||||
this->active_sound_buffer = reinterpret_cast<BYTE *>(CoTaskMemAlloc(buffer_size));
|
this->active_sound_buffer = reinterpret_cast<BYTE *>(CoTaskMemAlloc(max_size));
|
||||||
|
|
||||||
// hand the buffer to the callee
|
// hand the buffer to the callee
|
||||||
*ppData = this->active_sound_buffer;
|
*ppData = this->active_sound_buffer;
|
||||||
@@ -224,3 +239,7 @@ HRESULT WaveOutBackend::on_release_buffer(uint32_t num_frames_written, DWORD dwF
|
|||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
WaveOutBackend::WaveOutBackend() : format_(hooks::audio::FORMAT)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
struct WaveOutBackend final : AudioBackend {
|
struct WaveOutBackend final : AudioBackend {
|
||||||
public:
|
public:
|
||||||
|
explicit WaveOutBackend();
|
||||||
~WaveOutBackend() final = default;
|
~WaveOutBackend() final = default;
|
||||||
|
|
||||||
HRESULT init(uint32_t buffer_size);
|
HRESULT init(uint32_t buffer_size);
|
||||||
@@ -49,6 +50,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
WrappedIAudioClient *client;
|
WrappedIAudioClient *client;
|
||||||
|
|
||||||
|
const WAVEFORMATEXTENSIBLE &format_;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
HANDLE relay_event = nullptr;
|
HANDLE relay_event = nullptr;
|
||||||
HANDLE dispatcher_event = nullptr;
|
HANDLE dispatcher_event = nullptr;
|
||||||
|
|||||||
@@ -179,11 +179,6 @@ static int avs_fs_lstat(const char *name, struct avs::core::avs_stat *st) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hooks::avs::config::DISABLE_CACHE && (st != nullptr) &&
|
|
||||||
avs::game::is_model("LDJ") && is_ldj_cacheable_file(name)) {
|
|
||||||
return cached_avs_fs_lstat(name, st);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto value = avs::core::avs_fs_lstat(name, st);
|
const auto value = avs::core::avs_fs_lstat(name, st);
|
||||||
if (!is_spam_file(name)) {
|
if (!is_spam_file(name)) {
|
||||||
WRAP_DEBUG_FMT("name: {}", name);
|
WRAP_DEBUG_FMT("name: {}", name);
|
||||||
@@ -251,7 +246,7 @@ static avs::core::avs_file_t avs_fs_opendir(const char *path) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data) {
|
static avs::core::avs_file_t avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data) {
|
||||||
// avs redirection breaks ongaku paradise
|
// avs redirection breaks ongaku paradise
|
||||||
if (mountpoint == nullptr ||
|
if (mountpoint == nullptr ||
|
||||||
fsroot == nullptr ||
|
fsroot == nullptr ||
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
#include "develhook.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
#include "util/sigscan.h"
|
||||||
|
#include "avs/core.h"
|
||||||
|
#include "avs/game.h"
|
||||||
|
#include "hooks/wmischook.h"
|
||||||
|
#include "external/stackwalker/stackwalker.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace hooks::devel
|
||||||
|
{
|
||||||
|
static class Thumbnail : public Routine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
log_warning("hooks::devel::thumbnail", "Forcing thumbnail patch..");
|
||||||
|
hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, "FORCE", "thumbnail");
|
||||||
|
}
|
||||||
|
} thumbnail_("wmisc_thum");
|
||||||
|
|
||||||
|
static class Msacm : public Routine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
log_warning("hooks::devel::msacm", "Forcing msacm patch..");
|
||||||
|
hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, "FORCE", "msacm");
|
||||||
|
}
|
||||||
|
} msacm_("wmisc_acm");
|
||||||
|
|
||||||
|
static class DmoEffector : public Routine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
log_warning("hooks::devel::msacm", "Forcing msacm patch..");
|
||||||
|
hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, "FORCE", "dmoeffector");
|
||||||
|
}
|
||||||
|
} dmoeffector_("wmisc_dmoeffector");
|
||||||
|
|
||||||
|
static class Wmisc : public Routine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void attach() override
|
||||||
|
{
|
||||||
|
log_warning("hooks::devel::wmisc", "Disabling auto-patching..");
|
||||||
|
hooks::wmisc::skip_patching_by_model(true);
|
||||||
|
}
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
// Reenable logging
|
||||||
|
hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, "FORCE", "bmsound");
|
||||||
|
}
|
||||||
|
} wmisc_("disable_auto_wmisc");
|
||||||
|
|
||||||
|
static class Avs_fs : public Routine
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static constexpr char needle_[] = ""; // set to "" to print all
|
||||||
|
inline static avs::core::AVS_FS_LSTAT_T avs_fs_lstat_;
|
||||||
|
inline static avs::core::AVS_FS_MOUNT_T avs_fs_mount_;
|
||||||
|
inline static avs::core::AVS_FS_OPEN_T avs_fs_open_;
|
||||||
|
|
||||||
|
static int on_avs_fs_lstat(const char *path, struct avs::core::avs_stat *stat)
|
||||||
|
{
|
||||||
|
if (strstr(path, needle_))
|
||||||
|
{
|
||||||
|
log_info("hooks::devel", "{}({})", __FUNCTION__, path);
|
||||||
|
}
|
||||||
|
return avs_fs_lstat_(path, stat);
|
||||||
|
}
|
||||||
|
static avs::core::avs_file_t on_avs_fs_mount(const char *mountpoint, const char *fsroot, const char *fstype, void *data)
|
||||||
|
{
|
||||||
|
if (strstr(fsroot, needle_))
|
||||||
|
{
|
||||||
|
log_info("hooks::devel", "{}({}=>{}) @{} :nullptr data?{} ", __FUNCTION__, fsroot, mountpoint, fstype, data == nullptr);
|
||||||
|
}
|
||||||
|
return avs_fs_mount_(mountpoint, fsroot, fstype, data);
|
||||||
|
}
|
||||||
|
static avs::core::avs_file_t on_avs_fs_open(const char *name, uint16_t mode, int flags)
|
||||||
|
{
|
||||||
|
if (strstr(name, needle_))
|
||||||
|
{
|
||||||
|
log_info("hooks::devel", "{}({}::{}) @{}", __FUNCTION__, name, mode, flags);
|
||||||
|
}
|
||||||
|
return avs_fs_open_(name, mode, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_lstat), reinterpret_cast<void *>(on_avs_fs_lstat), reinterpret_cast<void **>(&avs_fs_lstat_));
|
||||||
|
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_mount), reinterpret_cast<void *>(on_avs_fs_mount), reinterpret_cast<void **>(&avs_fs_mount_));
|
||||||
|
detour::trampoline(reinterpret_cast<void *>(avs::core::avs_fs_open), reinterpret_cast<void *>(on_avs_fs_open), reinterpret_cast<void **>(&avs_fs_open_));
|
||||||
|
}
|
||||||
|
} avs_fs_("avs_fs_detour");
|
||||||
|
|
||||||
|
static class CMoviePlayer : public Routine
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef void (*GetWmvChunk_t)(uint8_t *param_1);
|
||||||
|
inline static GetWmvChunk_t GetWmvChunk_;
|
||||||
|
|
||||||
|
|
||||||
|
static void on_get_wmv_chunk_(uint8_t *param_1)
|
||||||
|
{
|
||||||
|
static FILE *fp = nullptr;
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
fp = fopen("data/movie/testbg2_fhd.wmv", "rb");
|
||||||
|
if (!fp)
|
||||||
|
log_warning("hooks::devel::CMoviePlayer", "Missing wmv file");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read from file (skip AVS)
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
int chunksz = *(uint32_t *) (param_1 + 0x10);
|
||||||
|
log_misc("hooks::devel::CMoviePlayer", "Reading {} bytes", chunksz);
|
||||||
|
int readsz = fread((void *) *(intptr_t *) (param_1 + 0x08), chunksz, 1, fp);
|
||||||
|
*(int *) (param_1 + 0x14) = readsz;
|
||||||
|
if(readsz < chunksz)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
fp = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
log_warning("hooks::devel", "Test code for SDVX5::CMoviePlayer only");
|
||||||
|
|
||||||
|
intptr_t TX_ThumExists = find_pattern_from(avs::game::DLL_INSTANCE, "40534883ec20448b4110488bd9488b51088b09ff150000000089431485c0791d448bc0488d1500000000488d0d000000004883c4205b48ff25000000004883c4205bc3", "XXXXXXXXXXXXXXXXXXXXX????XXXXXXXXXXXXX????XXX????XXXXXXXX????XXXXXX", 0, 0, 0);
|
||||||
|
if (!detour::trampoline_try(reinterpret_cast<void *>(TX_ThumExists), reinterpret_cast<void *>(on_get_wmv_chunk_), reinterpret_cast<void **>(&GetWmvChunk_)))
|
||||||
|
{
|
||||||
|
log_fatal("hooks::devel", "Hook failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} cmovieplayer_("wmisc_cmovieplayer");
|
||||||
|
|
||||||
|
std::vector<std::string> from_env(const char *str)
|
||||||
|
{
|
||||||
|
std::vector<std::string> r;
|
||||||
|
std::stringstream ss(getenv(str) ? getenv(str) : "");
|
||||||
|
std::string flag;
|
||||||
|
|
||||||
|
while (std::getline(ss, flag, ';'))
|
||||||
|
{
|
||||||
|
r.push_back(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
static std::vector<Routine *> &routines()
|
||||||
|
{
|
||||||
|
static std::vector<Routine *> routines_;
|
||||||
|
if (routines_.empty())
|
||||||
|
{
|
||||||
|
//Default routines
|
||||||
|
routines_.push_back(&avs_fs_);
|
||||||
|
routines_.push_back(&thumbnail_);
|
||||||
|
routines_.push_back(&msacm_);
|
||||||
|
routines_.push_back(&wmisc_);
|
||||||
|
routines_.push_back(&cmovieplayer_);
|
||||||
|
routines_.push_back(&dmoeffector_);
|
||||||
|
}
|
||||||
|
return routines_;
|
||||||
|
}
|
||||||
|
Routine *active_routine(const char *name)
|
||||||
|
{
|
||||||
|
unsigned int hash = to_hash(name);
|
||||||
|
for (auto &routine: routines())
|
||||||
|
{
|
||||||
|
if (routine->hash() == hash)
|
||||||
|
return routine;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void bind_routine(Routine *routine)
|
||||||
|
{
|
||||||
|
routines().push_back(routine);
|
||||||
|
}
|
||||||
|
void log_environment()
|
||||||
|
{
|
||||||
|
log_warning("hooks::devel", "WINEDLLOVERRIDES: '{}'", getenv("WINEDLLOVERRIDES") ? getenv("WINEDLLOVERRIDES") : "null");
|
||||||
|
}
|
||||||
|
void entry_main()
|
||||||
|
{
|
||||||
|
log_environment();
|
||||||
|
const auto rnames = from_env("SPICE_DEVEL");
|
||||||
|
if (!rnames.empty()) log_info("hooks::devel", "Run subroutines..");
|
||||||
|
for (const auto &routinename: from_env("SPICE_DEVEL"))
|
||||||
|
{
|
||||||
|
Routine *routine = active_routine(routinename.c_str());
|
||||||
|
if (routine) routine->entry_main();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void attach()
|
||||||
|
{
|
||||||
|
const auto rnames = from_env("SPICE_DEVEL");
|
||||||
|
if (!rnames.empty()) log_info("hooks::devel", "Attach subroutines..");
|
||||||
|
for (const auto &rname: rnames)
|
||||||
|
{
|
||||||
|
Routine *routine = active_routine(rname.c_str());
|
||||||
|
if (routine) routine->attach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include "util/utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace hooks::devel
|
||||||
|
{
|
||||||
|
//_INFO: use attach()/entry_main() to run task before game::attach()/game::entry_main()
|
||||||
|
class Routine
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
unsigned int hash_;
|
||||||
|
public:
|
||||||
|
[[nodiscard]] inline unsigned int constexpr hash() const { return hash_; }
|
||||||
|
virtual void attach() {}
|
||||||
|
virtual void entry_main() {}
|
||||||
|
explicit Routine(const char *name) : hash_(to_hash(name)) {}
|
||||||
|
virtual ~Routine() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
Routine *active_routine(const char *name);
|
||||||
|
void bind_routine(Routine *routine);
|
||||||
|
void attach();
|
||||||
|
void entry_main();
|
||||||
|
}
|
||||||
@@ -5,12 +5,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <external/robin_hood.h>
|
|
||||||
|
|
||||||
#include <d3d9.h>
|
#include <d3d9.h>
|
||||||
#ifdef __GNUC__
|
|
||||||
#include <d3dx9tex.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "avs/game.h"
|
#include "avs/game.h"
|
||||||
#include "cfg/screen_resize.h"
|
#include "cfg/screen_resize.h"
|
||||||
@@ -19,28 +15,23 @@
|
|||||||
#include "games/popn/popn.h"
|
#include "games/popn/popn.h"
|
||||||
#include "games/sdvx/sdvx.h"
|
#include "games/sdvx/sdvx.h"
|
||||||
#include "games/mfc/mfc.h"
|
#include "games/mfc/mfc.h"
|
||||||
#include "games/io.h"
|
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "launcher/options.h"
|
#include "launcher/options.h"
|
||||||
#include "launcher/signal.h"
|
#include "launcher/signal.h"
|
||||||
#include "launcher/shutdown.h"
|
#include "launcher/shutdown.h"
|
||||||
#include "misc/clipboard.h"
|
|
||||||
#include "misc/eamuse.h"
|
|
||||||
#include "misc/wintouchemu.h"
|
#include "misc/wintouchemu.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "overlay/notifications.h"
|
|
||||||
#include "util/detour.h"
|
#include "util/detour.h"
|
||||||
#include "util/deferlog.h"
|
#include "util/deferlog.h"
|
||||||
#include "util/fileutils.h"
|
|
||||||
#include "util/flags_helper.h"
|
#include "util/flags_helper.h"
|
||||||
#include "util/libutils.h"
|
#include "util/libutils.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
#include "util/memutils.h"
|
#include "util/memutils.h"
|
||||||
#include "util/threadpool.h"
|
|
||||||
|
|
||||||
#include "d3d9_device.h"
|
#include "d3d9_device.h"
|
||||||
|
#include "d3d9_screenshot.h"
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
@@ -64,19 +55,6 @@
|
|||||||
return __ret; \
|
return __ret; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
typedef decltype(D3DXSaveSurfaceToFileA) *D3DXSaveSurfaceToFileA_t;
|
|
||||||
#else
|
|
||||||
#define D3DXIFF_PNG ((DWORD) 3)
|
|
||||||
|
|
||||||
typedef HRESULT (WINAPI *D3DXSaveSurfaceToFileA_t)(
|
|
||||||
LPCSTR pDestFile,
|
|
||||||
DWORD DestFormat,
|
|
||||||
LPDIRECT3DSURFACE9 pSrcSurface,
|
|
||||||
CONST PALETTEENTRY *pSrcPalette,
|
|
||||||
CONST RECT *pSrcRect);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 9 on 12
|
* 9 on 12
|
||||||
*/
|
*/
|
||||||
@@ -100,8 +78,6 @@ typedef IDirect3D9* (WINAPI *Direct3DCreate9On12_t)(
|
|||||||
static void *D3D9_DIRECT3D_CREATE9_ADR = nullptr;
|
static void *D3D9_DIRECT3D_CREATE9_ADR = nullptr;
|
||||||
static char D3D9_DIRECT3D_CREATE9_CONTENTS[16];
|
static char D3D9_DIRECT3D_CREATE9_CONTENTS[16];
|
||||||
|
|
||||||
static bool ATTEMPTED_D3DX9_LOAD_LIBRARY = false;
|
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
std::optional<UINT> D3D9_ADAPTER = std::nullopt;
|
std::optional<UINT> D3D9_ADAPTER = std::nullopt;
|
||||||
DWORD D3D9_BEHAVIOR_DISABLE = 0;
|
DWORD D3D9_BEHAVIOR_DISABLE = 0;
|
||||||
@@ -1499,178 +1475,6 @@ static void graphics_d3d9_ldj_on_present(IDirect3DDevice9 *wrapped_device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_capture(
|
|
||||||
int screen,
|
|
||||||
D3DFORMAT format,
|
|
||||||
UINT width,
|
|
||||||
UINT height,
|
|
||||||
IDirect3DSurface9 *surface) {
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
// lock surface to be able to access the data
|
|
||||||
D3DLOCKED_RECT finished_copy {};
|
|
||||||
hr = surface->LockRect(&finished_copy, nullptr, 0);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9", "failed to lock screenshot surface, hr={}", FMT_HRESULT(hr));
|
|
||||||
graphics_capture_skip(screen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy pixel data
|
|
||||||
size_t pitch = finished_copy.Pitch;
|
|
||||||
auto data = reinterpret_cast<uint8_t *>(finished_copy.pBits);
|
|
||||||
auto pixels = new uint8_t[width * height * 3];
|
|
||||||
for (size_t row = 0; row < height; row++) {
|
|
||||||
size_t offset_pixels = 0;
|
|
||||||
size_t offset_row = row * width * 3;
|
|
||||||
switch (format) {
|
|
||||||
case D3DFMT_R8G8B8: {
|
|
||||||
for (size_t offset = 0; offset < pitch; offset += 3) {
|
|
||||||
auto cell = data + row * pitch + offset;
|
|
||||||
auto pixel = &pixels[offset_row + offset_pixels];
|
|
||||||
pixel[0] = cell[0];
|
|
||||||
pixel[1] = cell[1];
|
|
||||||
pixel[2] = cell[2];
|
|
||||||
offset_pixels += 3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case D3DFMT_X8R8G8B8:
|
|
||||||
case D3DFMT_A8R8G8B8: {
|
|
||||||
for (size_t offset = 0; offset < pitch; offset += 4) {
|
|
||||||
auto cell = data + row * pitch + offset;
|
|
||||||
auto pixel = &pixels[offset_row + offset_pixels];
|
|
||||||
pixel[0] = cell[2];
|
|
||||||
pixel[1] = cell[1];
|
|
||||||
pixel[2] = cell[0];
|
|
||||||
offset_pixels += 3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case D3DFMT_X8B8G8R8:
|
|
||||||
case D3DFMT_A8B8G8R8: {
|
|
||||||
for (size_t offset = 0; offset < pitch; offset += 4) {
|
|
||||||
auto cell = data + row * pitch + offset;
|
|
||||||
auto pixel = &pixels[offset_row + offset_pixels];
|
|
||||||
pixel[0] = cell[0];
|
|
||||||
pixel[1] = cell[1];
|
|
||||||
pixel[2] = cell[2];
|
|
||||||
offset_pixels += 3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
for (size_t offset = 0; offset < width; offset++) {
|
|
||||||
auto pixel = &pixels[offset_row + offset_pixels];
|
|
||||||
pixel[0] = 0;
|
|
||||||
pixel[1] = 0;
|
|
||||||
pixel[2] = 0;
|
|
||||||
offset_pixels += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// unlock surface
|
|
||||||
hr = surface->UnlockRect();
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9", "failed to unlock screenshot surface, hr={}", FMT_HRESULT(hr));
|
|
||||||
graphics_capture_skip(screen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enqueue
|
|
||||||
graphics_capture_enqueue(screen, pixels, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void save_screenshot(const std::string &file_path, UINT height, IDirect3DSurface9 *surface) {
|
|
||||||
HRESULT hr;
|
|
||||||
|
|
||||||
D3DLOCKED_RECT finished_copy {};
|
|
||||||
hr = surface->LockRect(&finished_copy, nullptr, 0);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9", "failed to lock screenshot surface, hr={}", FMT_HRESULT(hr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set alpha channel to 255
|
|
||||||
{
|
|
||||||
auto pitch = finished_copy.Pitch;
|
|
||||||
auto data = reinterpret_cast<uint8_t *>(finished_copy.pBits);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < height; i++) {
|
|
||||||
for (int j = 3; j < pitch; j += 4) {
|
|
||||||
data[i * pitch + j] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = surface->UnlockRect();
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9", "failed to unlock screenshot surface, hr={}", FMT_HRESULT(hr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lazy load function
|
|
||||||
static D3DXSaveSurfaceToFileA_t D3DXSaveSurfaceToFileA_ptr = nullptr;
|
|
||||||
if (D3DXSaveSurfaceToFileA_ptr == nullptr) {
|
|
||||||
D3DXSaveSurfaceToFileA_ptr = libutils::try_proc<D3DXSaveSurfaceToFileA_t>("D3DXSaveSurfaceToFileA");
|
|
||||||
|
|
||||||
// check if function was not found, likely because d3dx9 is not loaded
|
|
||||||
if (!ATTEMPTED_D3DX9_LOAD_LIBRARY && D3DXSaveSurfaceToFileA_ptr == nullptr) {
|
|
||||||
ATTEMPTED_D3DX9_LOAD_LIBRARY = true;
|
|
||||||
|
|
||||||
for (size_t i = 43; i >= 24; i--) {
|
|
||||||
auto lib_name = fmt::format("d3dx9_{}.dll", i);
|
|
||||||
auto d3dx9 = libutils::try_library(lib_name);
|
|
||||||
|
|
||||||
// Check if library was not found
|
|
||||||
if (d3dx9 == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DXSaveSurfaceToFileA_ptr = libutils::try_proc<D3DXSaveSurfaceToFileA_t>(
|
|
||||||
d3dx9, "D3DXSaveSurfaceToFileA");
|
|
||||||
|
|
||||||
// Check if function was not found
|
|
||||||
if (D3DXSaveSurfaceToFileA_ptr == nullptr) {
|
|
||||||
FreeLibrary(d3dx9);
|
|
||||||
d3dx9 = nullptr;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_info("graphics::d3d9", "found surface save function in '{}'", lib_name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (D3DXSaveSurfaceToFileA_ptr != nullptr) {
|
|
||||||
|
|
||||||
// save to file
|
|
||||||
log_info("graphics::d3d9", "saving screenshot to {}", file_path);
|
|
||||||
auto hr = D3DXSaveSurfaceToFileA_ptr(file_path.c_str(), D3DXIFF_PNG, surface, nullptr, nullptr);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9", "Failed to save screenshot");
|
|
||||||
overlay::notifications::add(
|
|
||||||
overlay::notifications::Severity::Error,
|
|
||||||
"Screenshot failed to save");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save to clipboard
|
|
||||||
clipboard::copy_image(file_path);
|
|
||||||
|
|
||||||
overlay::notifications::add(
|
|
||||||
overlay::notifications::Severity::Success,
|
|
||||||
fmt::format("Screenshot saved: {}", fileutils::basename(file_path)));
|
|
||||||
} else {
|
|
||||||
log_warning("graphics::d3d9", "Direct3D save helper function not available");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void graphics_d3d9_on_present(
|
void graphics_d3d9_on_present(
|
||||||
HWND hFocusWindow,
|
HWND hFocusWindow,
|
||||||
IDirect3DDevice9 *device,
|
IDirect3DDevice9 *device,
|
||||||
@@ -1718,135 +1522,8 @@ void graphics_d3d9_on_present(
|
|||||||
wintouchemu::update();
|
wintouchemu::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check screenshot key
|
graphics_d3d9_poll_screenshot_hotkey();
|
||||||
static bool trigger_last = false;
|
graphics_d3d9_process_screenshot_and_capture(device, SUB_SWAP_CHAIN);
|
||||||
auto buttons = games::get_buttons_overlay(eamuse_get_game());
|
|
||||||
if (buttons && (!overlay::OVERLAY || overlay::OVERLAY->hotkeys_triggered()) &&
|
|
||||||
GameAPI::Buttons::getState(RI_MGR, buttons->at(games::OverlayButtons::Screenshot)))
|
|
||||||
{
|
|
||||||
if (!trigger_last) {
|
|
||||||
graphics_screenshot_trigger();
|
|
||||||
}
|
|
||||||
trigger_last = true;
|
|
||||||
} else {
|
|
||||||
trigger_last = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process pending screenshot
|
|
||||||
bool screenshot = false;
|
|
||||||
bool capture = false;
|
|
||||||
int capture_screen = 0;
|
|
||||||
if ((screenshot = graphics_screenshot_consume())
|
|
||||||
|| ((capture = graphics_capture_consume(&capture_screen)))) {
|
|
||||||
HRESULT hr = S_OK;
|
|
||||||
|
|
||||||
// TODO: verify capture_screen is a valid swapchain
|
|
||||||
|
|
||||||
// get back buffer
|
|
||||||
IDirect3DSurface9 *buffer = nullptr;
|
|
||||||
if (SUB_SWAP_CHAIN != nullptr && capture_screen & 1) {
|
|
||||||
hr = SUB_SWAP_CHAIN->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &buffer);
|
|
||||||
} else {
|
|
||||||
hr = device->GetBackBuffer(capture_screen, 0, D3DBACKBUFFER_TYPE_MONO, &buffer);
|
|
||||||
}
|
|
||||||
if (FAILED(hr) || buffer == nullptr) {
|
|
||||||
log_warning("graphics::d3d9",
|
|
||||||
"failed to get back buffer, hr={}",
|
|
||||||
FMT_HRESULT(hr));
|
|
||||||
if (capture) {
|
|
||||||
graphics_capture_skip(capture_screen);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DSURFACE_DESC desc {};
|
|
||||||
hr = buffer->GetDesc(&desc);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9",
|
|
||||||
"failed to acquire back buffer descriptor, hr={}",
|
|
||||||
FMT_HRESULT(hr));
|
|
||||||
buffer->Release();
|
|
||||||
if (capture) {
|
|
||||||
graphics_capture_skip(capture_screen);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: cache render targets
|
|
||||||
IDirect3DSurface9 *temp_surface = nullptr;
|
|
||||||
hr = device->CreateRenderTarget(
|
|
||||||
desc.Width, desc.Height, desc.Format, desc.MultiSampleType,
|
|
||||||
desc.MultiSampleQuality, TRUE, &temp_surface, nullptr);
|
|
||||||
if (FAILED(hr) || temp_surface == nullptr) {
|
|
||||||
log_warning("graphics::d3d9",
|
|
||||||
"failed to acquire temporary surface, hr={}",
|
|
||||||
FMT_HRESULT(hr));
|
|
||||||
buffer->Release();
|
|
||||||
if (capture) {
|
|
||||||
graphics_capture_skip(capture_screen);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = device->StretchRect(buffer, nullptr, temp_surface, nullptr, D3DTEXF_NONE);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
log_warning("graphics::d3d9",
|
|
||||||
"failed to copy back buffer contents, hr={}",
|
|
||||||
FMT_HRESULT(hr));
|
|
||||||
temp_surface->Release();
|
|
||||||
buffer->Release();
|
|
||||||
if (capture) {
|
|
||||||
graphics_capture_skip(capture_screen);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// release original back buffer reference
|
|
||||||
buffer->Release();
|
|
||||||
|
|
||||||
// function for storing the surface
|
|
||||||
auto surface_process = [=]() {
|
|
||||||
|
|
||||||
// capture
|
|
||||||
if (capture) {
|
|
||||||
save_capture(capture_screen, desc.Format, desc.Width, desc.Height, temp_surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
// screenshot
|
|
||||||
if (screenshot) {
|
|
||||||
|
|
||||||
// check where we can save it
|
|
||||||
auto file_path = graphics_screenshot_genpath();
|
|
||||||
if (!file_path.empty()) {
|
|
||||||
|
|
||||||
// write to file
|
|
||||||
save_screenshot(file_path, desc.Height, temp_surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// release surface
|
|
||||||
temp_surface->Release();
|
|
||||||
};
|
|
||||||
|
|
||||||
// list of games that crash when running the screenshot processor on another thread
|
|
||||||
static const robin_hood::unordered_set<std::string> THREAD_BAN {
|
|
||||||
"JMA",
|
|
||||||
#ifndef SPICE64
|
|
||||||
"KFC",
|
|
||||||
#endif
|
|
||||||
"KMA",
|
|
||||||
"KLP",
|
|
||||||
"LMA",
|
|
||||||
};
|
|
||||||
|
|
||||||
// run the save operation on another thread for supported games
|
|
||||||
if (THREAD_BAN.contains(avs::game::MODEL)) {
|
|
||||||
surface_process();
|
|
||||||
} else {
|
|
||||||
static auto pool = ThreadPool(2);
|
|
||||||
pool.add(surface_process);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_backbuffer_dimensions(D3DPRESENT_PARAMETERS *params) {
|
void update_backbuffer_dimensions(D3DPRESENT_PARAMETERS *params) {
|
||||||
|
|||||||
@@ -0,0 +1,409 @@
|
|||||||
|
#include "d3d9_screenshot.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <external/robin_hood.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#include <d3dx9tex.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "avs/game.h"
|
||||||
|
#include "games/io.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
#include "launcher/launcher.h"
|
||||||
|
#include "misc/clipboard.h"
|
||||||
|
#include "misc/eamuse.h"
|
||||||
|
#include "overlay/notifications.h"
|
||||||
|
#include "overlay/overlay.h"
|
||||||
|
#include "util/fileutils.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/threadpool.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
typedef decltype(D3DXSaveSurfaceToFileA) *D3DXSaveSurfaceToFileA_t;
|
||||||
|
#else
|
||||||
|
#define D3DXIFF_PNG ((DWORD) 3)
|
||||||
|
|
||||||
|
typedef HRESULT (WINAPI *D3DXSaveSurfaceToFileA_t)(
|
||||||
|
LPCSTR pDestFile,
|
||||||
|
DWORD DestFormat,
|
||||||
|
LPDIRECT3DSURFACE9 pSrcSurface,
|
||||||
|
CONST PALETTEENTRY *pSrcPalette,
|
||||||
|
CONST RECT *pSrcRect);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool ATTEMPTED_D3DX9_LOAD_LIBRARY = false;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
enum class ImageRequestKind {
|
||||||
|
Screenshot,
|
||||||
|
Capture,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ImageRequest {
|
||||||
|
ImageRequestKind kind;
|
||||||
|
int screen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SurfaceReleaser {
|
||||||
|
void operator()(IDirect3DSurface9 *surface) const {
|
||||||
|
surface->Release();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using SurfacePtr = std::unique_ptr<IDirect3DSurface9, SurfaceReleaser>;
|
||||||
|
|
||||||
|
struct BackbufferCopy {
|
||||||
|
D3DSURFACE_DESC desc {};
|
||||||
|
SurfacePtr surface;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static void save_capture(
|
||||||
|
int screen,
|
||||||
|
D3DFORMAT format,
|
||||||
|
UINT width,
|
||||||
|
UINT height,
|
||||||
|
IDirect3DSurface9 *surface) {
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
// lock surface to be able to access the data
|
||||||
|
D3DLOCKED_RECT finished_copy {};
|
||||||
|
hr = surface->LockRect(&finished_copy, nullptr, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
log_warning("graphics::d3d9", "failed to lock screenshot surface, hr={}", FMT_HRESULT(hr));
|
||||||
|
graphics_capture_skip(screen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize supported D3D formats to packed RGB for API capture
|
||||||
|
size_t pitch = finished_copy.Pitch;
|
||||||
|
auto data = reinterpret_cast<uint8_t *>(finished_copy.pBits);
|
||||||
|
auto pixels = std::unique_ptr<uint8_t[]>(new uint8_t[width * height * 3]);
|
||||||
|
for (size_t row = 0; row < height; row++) {
|
||||||
|
size_t offset_row = row * width * 3;
|
||||||
|
switch (format) {
|
||||||
|
case D3DFMT_R8G8B8: {
|
||||||
|
for (size_t column = 0; column < width; column++) {
|
||||||
|
auto cell = data + row * pitch + column * 3;
|
||||||
|
auto pixel = &pixels[offset_row + column * 3];
|
||||||
|
pixel[0] = cell[0];
|
||||||
|
pixel[1] = cell[1];
|
||||||
|
pixel[2] = cell[2];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case D3DFMT_X8R8G8B8:
|
||||||
|
case D3DFMT_A8R8G8B8: {
|
||||||
|
for (size_t column = 0; column < width; column++) {
|
||||||
|
auto cell = data + row * pitch + column * 4;
|
||||||
|
auto pixel = &pixels[offset_row + column * 3];
|
||||||
|
pixel[0] = cell[2];
|
||||||
|
pixel[1] = cell[1];
|
||||||
|
pixel[2] = cell[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case D3DFMT_X8B8G8R8:
|
||||||
|
case D3DFMT_A8B8G8R8: {
|
||||||
|
for (size_t column = 0; column < width; column++) {
|
||||||
|
auto cell = data + row * pitch + column * 4;
|
||||||
|
auto pixel = &pixels[offset_row + column * 3];
|
||||||
|
pixel[0] = cell[0];
|
||||||
|
pixel[1] = cell[1];
|
||||||
|
pixel[2] = cell[2];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
for (size_t column = 0; column < width; column++) {
|
||||||
|
auto pixel = &pixels[offset_row + column * 3];
|
||||||
|
pixel[0] = 0;
|
||||||
|
pixel[1] = 0;
|
||||||
|
pixel[2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlock surface
|
||||||
|
hr = surface->UnlockRect();
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
log_warning("graphics::d3d9", "failed to unlock screenshot surface, hr={}", FMT_HRESULT(hr));
|
||||||
|
graphics_capture_skip(screen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// enqueue
|
||||||
|
graphics_capture_enqueue(screen, pixels.release(), width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void save_screenshot(
|
||||||
|
const std::string &file_path,
|
||||||
|
D3DFORMAT format,
|
||||||
|
UINT width,
|
||||||
|
UINT height,
|
||||||
|
IDirect3DSurface9 *surface) {
|
||||||
|
// 32-bit XRGB and ARGB surfaces use byte 3 as alpha; force opaque PNG output
|
||||||
|
if (format == D3DFMT_X8R8G8B8 || format == D3DFMT_A8R8G8B8 ||
|
||||||
|
format == D3DFMT_X8B8G8R8 || format == D3DFMT_A8B8G8R8) {
|
||||||
|
|
||||||
|
D3DLOCKED_RECT finished_copy {};
|
||||||
|
HRESULT hr = surface->LockRect(&finished_copy, nullptr, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
log_warning("graphics::d3d9", "failed to lock screenshot surface, hr={}", FMT_HRESULT(hr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t pitch = finished_copy.Pitch;
|
||||||
|
auto data = reinterpret_cast<uint8_t *>(finished_copy.pBits);
|
||||||
|
for (size_t row = 0; row < height; row++) {
|
||||||
|
for (size_t column = 0; column < width; column++) {
|
||||||
|
data[row * pitch + column * 4 + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = surface->UnlockRect();
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
log_warning("graphics::d3d9", "failed to unlock screenshot surface, hr={}", FMT_HRESULT(hr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lazy load function
|
||||||
|
static D3DXSaveSurfaceToFileA_t D3DXSaveSurfaceToFileA_ptr = nullptr;
|
||||||
|
if (D3DXSaveSurfaceToFileA_ptr == nullptr) {
|
||||||
|
D3DXSaveSurfaceToFileA_ptr = libutils::try_proc<D3DXSaveSurfaceToFileA_t>("D3DXSaveSurfaceToFileA");
|
||||||
|
|
||||||
|
// check if function was not found, likely because d3dx9 is not loaded
|
||||||
|
if (!ATTEMPTED_D3DX9_LOAD_LIBRARY && D3DXSaveSurfaceToFileA_ptr == nullptr) {
|
||||||
|
ATTEMPTED_D3DX9_LOAD_LIBRARY = true;
|
||||||
|
|
||||||
|
// prefer the newest installed helper while supporting older D3DX9 runtimes
|
||||||
|
for (size_t i = 43; i >= 24; i--) {
|
||||||
|
auto lib_name = fmt::format("d3dx9_{}.dll", i);
|
||||||
|
auto d3dx9 = libutils::try_library(lib_name);
|
||||||
|
|
||||||
|
// Check if library was not found
|
||||||
|
if (d3dx9 == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3DXSaveSurfaceToFileA_ptr = libutils::try_proc<D3DXSaveSurfaceToFileA_t>(
|
||||||
|
d3dx9, "D3DXSaveSurfaceToFileA");
|
||||||
|
|
||||||
|
// Check if function was not found
|
||||||
|
if (D3DXSaveSurfaceToFileA_ptr == nullptr) {
|
||||||
|
FreeLibrary(d3dx9);
|
||||||
|
d3dx9 = nullptr;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("graphics::d3d9", "found surface save function in '{}'", lib_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (D3DXSaveSurfaceToFileA_ptr != nullptr) {
|
||||||
|
|
||||||
|
// save to file
|
||||||
|
log_info("graphics::d3d9", "saving screenshot to {}", file_path);
|
||||||
|
const HRESULT save_result = D3DXSaveSurfaceToFileA_ptr(
|
||||||
|
file_path.c_str(), D3DXIFF_PNG, surface, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (FAILED(save_result)) {
|
||||||
|
log_warning("graphics::d3d9", "Failed to save screenshot");
|
||||||
|
overlay::notifications::add(
|
||||||
|
overlay::notifications::Severity::Error,
|
||||||
|
"Screenshot failed to save");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save to clipboard
|
||||||
|
clipboard::copy_image(file_path);
|
||||||
|
|
||||||
|
overlay::notifications::add(
|
||||||
|
overlay::notifications::Severity::Success,
|
||||||
|
fmt::format("Screenshot saved: {}", fileutils::basename(file_path)));
|
||||||
|
} else {
|
||||||
|
log_warning("graphics::d3d9", "Direct3D save helper function not available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_d3d9_poll_screenshot_hotkey() {
|
||||||
|
static bool trigger_last = false;
|
||||||
|
auto buttons = games::get_buttons_overlay(eamuse_get_game());
|
||||||
|
if (buttons && (!overlay::OVERLAY || overlay::OVERLAY->hotkeys_triggered()) &&
|
||||||
|
GameAPI::Buttons::getState(RI_MGR, buttons->at(games::OverlayButtons::Screenshot)))
|
||||||
|
{
|
||||||
|
if (!trigger_last) {
|
||||||
|
graphics_screenshot_trigger();
|
||||||
|
}
|
||||||
|
trigger_last = true;
|
||||||
|
} else {
|
||||||
|
trigger_last = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<BackbufferCopy> acquire_backbuffer_copy(
|
||||||
|
IDirect3DDevice9 *device, IDirect3DSwapChain9 *sub_swap_chain, int screen) {
|
||||||
|
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
// TODO: verify screen is a valid swapchain
|
||||||
|
|
||||||
|
IDirect3DSurface9 *buffer = nullptr;
|
||||||
|
if (sub_swap_chain != nullptr && screen & 1) {
|
||||||
|
hr = sub_swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &buffer);
|
||||||
|
} else {
|
||||||
|
hr = device->GetBackBuffer(screen, 0, D3DBACKBUFFER_TYPE_MONO, &buffer);
|
||||||
|
}
|
||||||
|
if (FAILED(hr) || buffer == nullptr) {
|
||||||
|
log_warning("graphics::d3d9",
|
||||||
|
"failed to get back buffer, hr={}",
|
||||||
|
FMT_HRESULT(hr));
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3DSURFACE_DESC desc {};
|
||||||
|
hr = buffer->GetDesc(&desc);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
log_warning("graphics::d3d9",
|
||||||
|
"failed to acquire back buffer descriptor, hr={}",
|
||||||
|
FMT_HRESULT(hr));
|
||||||
|
buffer->Release();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cache render targets
|
||||||
|
IDirect3DSurface9 *temp_surface = nullptr;
|
||||||
|
hr = device->CreateRenderTarget(
|
||||||
|
desc.Width, desc.Height, desc.Format, desc.MultiSampleType,
|
||||||
|
desc.MultiSampleQuality, TRUE, &temp_surface, nullptr);
|
||||||
|
if (FAILED(hr) || temp_surface == nullptr) {
|
||||||
|
log_warning("graphics::d3d9",
|
||||||
|
"failed to acquire temporary surface, hr={}",
|
||||||
|
FMT_HRESULT(hr));
|
||||||
|
buffer->Release();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = device->StretchRect(buffer, nullptr, temp_surface, nullptr, D3DTEXF_NONE);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
log_warning("graphics::d3d9",
|
||||||
|
"failed to copy back buffer contents, hr={}",
|
||||||
|
FMT_HRESULT(hr));
|
||||||
|
temp_surface->Release();
|
||||||
|
buffer->Release();
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// release original back buffer reference
|
||||||
|
buffer->Release();
|
||||||
|
|
||||||
|
return BackbufferCopy {
|
||||||
|
.desc = desc,
|
||||||
|
.surface = SurfacePtr(temp_surface),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dispatch_surface_save(
|
||||||
|
const ImageRequest &request,
|
||||||
|
BackbufferCopy copy) {
|
||||||
|
auto surface_process = [request, copy = std::move(copy)]() {
|
||||||
|
switch (request.kind) {
|
||||||
|
case ImageRequestKind::Capture:
|
||||||
|
save_capture(
|
||||||
|
request.screen,
|
||||||
|
copy.desc.Format,
|
||||||
|
copy.desc.Width,
|
||||||
|
copy.desc.Height,
|
||||||
|
copy.surface.get());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ImageRequestKind::Screenshot: {
|
||||||
|
auto file_path = graphics_screenshot_genpath();
|
||||||
|
if (!file_path.empty()) {
|
||||||
|
save_screenshot(
|
||||||
|
file_path,
|
||||||
|
copy.desc.Format,
|
||||||
|
copy.desc.Width,
|
||||||
|
copy.desc.Height,
|
||||||
|
copy.surface.get());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// list of games that crash when running the screenshot processor on another thread
|
||||||
|
static const robin_hood::unordered_set<std::string> THREAD_BAN {
|
||||||
|
"JMA",
|
||||||
|
#ifndef SPICE64
|
||||||
|
// KFC only crashes under threaded processing in 32-bit builds
|
||||||
|
"KFC",
|
||||||
|
#endif
|
||||||
|
"KMA",
|
||||||
|
"KLP",
|
||||||
|
"LMA",
|
||||||
|
};
|
||||||
|
|
||||||
|
// run the save operation on another thread for supported games
|
||||||
|
if (THREAD_BAN.contains(avs::game::MODEL)) {
|
||||||
|
surface_process();
|
||||||
|
} else {
|
||||||
|
static auto pool = ThreadPool(2);
|
||||||
|
pool.add(std::move(surface_process));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::optional<ImageRequest> consume_image_request() {
|
||||||
|
if (graphics_screenshot_consume()) {
|
||||||
|
return ImageRequest {
|
||||||
|
.kind = ImageRequestKind::Screenshot,
|
||||||
|
.screen = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int capture_screen = 0;
|
||||||
|
if (graphics_capture_consume(&capture_screen)) {
|
||||||
|
return ImageRequest {
|
||||||
|
.kind = ImageRequestKind::Capture,
|
||||||
|
.screen = capture_screen,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_d3d9_process_screenshot_and_capture(
|
||||||
|
IDirect3DDevice9 *device,
|
||||||
|
IDirect3DSwapChain9 *sub_swap_chain) {
|
||||||
|
const auto request = consume_image_request();
|
||||||
|
if (!request.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto copy = acquire_backbuffer_copy(
|
||||||
|
device,
|
||||||
|
sub_swap_chain,
|
||||||
|
request->screen);
|
||||||
|
if (!copy.has_value()) {
|
||||||
|
if (request->kind == ImageRequestKind::Capture) {
|
||||||
|
graphics_capture_skip(request->screen);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_surface_save(*request, std::move(*copy));
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <d3d9.h>
|
||||||
|
|
||||||
|
void graphics_d3d9_poll_screenshot_hotkey();
|
||||||
|
|
||||||
|
void graphics_d3d9_process_screenshot_and_capture(
|
||||||
|
IDirect3DDevice9 *device,
|
||||||
|
IDirect3DSwapChain9 *sub_swap_chain);
|
||||||
@@ -0,0 +1,976 @@
|
|||||||
|
#include "sndbhook.h"
|
||||||
|
#include "hooks/develhook.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/memutils.h"
|
||||||
|
#include "util/sigscan.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
#include "avs/core.h"
|
||||||
|
#include <codecvt>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
// This implementation outsources libavcodec from host ffmpeg (so that linking ffmpeg stack with spicetools isn't required)
|
||||||
|
namespace hooks::soundbank::avcodec
|
||||||
|
{
|
||||||
|
enum pcm_resampler : int8_t
|
||||||
|
{
|
||||||
|
bmswac_resampler_none = -1,
|
||||||
|
bmswac_resampler_u8,
|
||||||
|
bmswac_resampler_s16,
|
||||||
|
bmswac_resampler_s16_ad,
|
||||||
|
bmswac_resampler_f32
|
||||||
|
};
|
||||||
|
typedef enum pcm_resampler pcm_resampler_t;
|
||||||
|
typedef void (*BmswConfigInit_t)(const char *path);
|
||||||
|
typedef int (*BmswSymlink_t)(const char *srcwpath, const char *dstwpath, int canonic);
|
||||||
|
typedef uint64_t (*BmswTranscoderEnumValidSoundbanksAddr_t)();
|
||||||
|
typedef pcm_resampler (*BmswTranscoderResampler_t)();
|
||||||
|
typedef int (*BmswTranscoderAsfToWav_t)(const uint8_t *srcasf, uint32_t srcsz, uint8_t **dstwav, uint32_t *dstsz, pcm_resampler_t resampler);
|
||||||
|
static BmswConfigInit_t BmswConfigInit;
|
||||||
|
static BmswSymlink_t BmswSymlink;
|
||||||
|
static BmswTranscoderEnumValidSoundbanksAddr_t BmswTranscoderEnumValidSoundbanksAddr;
|
||||||
|
static BmswTranscoderResampler_t BmswTranscoderResampler;
|
||||||
|
static BmswTranscoderAsfToWav_t BmswTranscoderAsfToWav;
|
||||||
|
static HMODULE bmsw_ = nullptr;
|
||||||
|
bool init()
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank::avcodec", "{}", __FUNCTION__);
|
||||||
|
|
||||||
|
// Initialize bmsound-wine.dll once
|
||||||
|
if (bmsw_)
|
||||||
|
return true;
|
||||||
|
if ((bmsw_ = libutils::try_library(MODULE_PATH / "bmsound-wine.dll")))
|
||||||
|
{
|
||||||
|
BmswConfigInit = (BmswConfigInit_t) GetProcAddress(bmsw_, "BmswConfigInit");
|
||||||
|
BmswSymlink = (BmswSymlink_t) GetProcAddress(bmsw_, "BmswSymlink");
|
||||||
|
BmswTranscoderEnumValidSoundbanksAddr = (BmswTranscoderEnumValidSoundbanksAddr_t) GetProcAddress(bmsw_, "BmswTranscoderEnumValidSoundbanksAddr");
|
||||||
|
BmswTranscoderResampler = (BmswTranscoderResampler_t) GetProcAddress(bmsw_, "BmswTranscoderResampler");
|
||||||
|
BmswTranscoderAsfToWav = (BmswTranscoderAsfToWav_t) GetProcAddress(bmsw_, "BmswTranscoderAsfToWav");
|
||||||
|
|
||||||
|
//_REM: 0.2.x support (old behaviour), remove on 0.3.0
|
||||||
|
if (!BmswTranscoderEnumValidSoundbanksAddr || !BmswTranscoderResampler)
|
||||||
|
{
|
||||||
|
BmswTranscoderEnumValidSoundbanksAddr = (BmswTranscoderEnumValidSoundbanksAddr_t) GetProcAddress(bmsw_, "BmswEnumValidSoundbanksAddr");
|
||||||
|
BmswTranscoderResampler = []() -> pcm_resampler
|
||||||
|
{
|
||||||
|
return bmswac_resampler_s16_ad;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load config
|
||||||
|
BmswConfigInit("prop/linux.json");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warning("hooks::soundbank", "Library not found: '{}'", (MODULE_PATH / "bmsound-wine.dll").string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void deinit()
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank::avcodec", "{}", __FUNCTION__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replicates wine MF wma=>wav playback bug 1:1, follows https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/multimedia/mediafoundation/AudioClip/main.cpp
|
||||||
|
#include <mfapi.h>
|
||||||
|
#include <mfidl.h>
|
||||||
|
#include <mfreadwrite.h>
|
||||||
|
#include <mfobjects.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
namespace hooks::soundbank::mf_broken
|
||||||
|
{
|
||||||
|
typedef HRESULT (*MFCreateMFByteStreamOnStream_t)(IStream *, IMFByteStream **);
|
||||||
|
typedef HRESULT (*MFCreateSourceReaderFromByteStream_t)(IMFByteStream *, IMFAttributes *, IMFSourceReader **);
|
||||||
|
typedef HRESULT (*MFStartup_t)(ULONG, DWORD);
|
||||||
|
typedef HRESULT (*MFShutdown_t)();
|
||||||
|
typedef IStream *(*SHCreateMemStream_t)(const BYTE *, UINT);
|
||||||
|
MFCreateMFByteStreamOnStream_t MFCreateMFByteStreamOnStream;
|
||||||
|
MFCreateSourceReaderFromByteStream_t MFCreateSourceReaderFromByteStream;
|
||||||
|
MFStartup_t MFStartup;
|
||||||
|
MFShutdown_t MFShutdown;
|
||||||
|
SHCreateMemStream_t SHCreateMemStream;
|
||||||
|
struct wav_hdr
|
||||||
|
{
|
||||||
|
char sig_riff[4] = {'R', 'I', 'F', 'F'};
|
||||||
|
uint32_t filesz = -1;
|
||||||
|
char sig_wave[4] = {'W', 'A', 'V', 'E'};
|
||||||
|
char sig_fmt[4] = {'f', 'm', 't', ' '};
|
||||||
|
uint32_t chunksize = 16;
|
||||||
|
uint16_t format = 1;
|
||||||
|
uint16_t channels = 2;
|
||||||
|
uint32_t samplerate = 44100;
|
||||||
|
uint32_t byterate = 44100 * 2 * 2;
|
||||||
|
uint16_t stride = 2 * 2;
|
||||||
|
uint16_t bitdepth = 16;
|
||||||
|
char sig_data[4] = {'d', 'a', 't', 'a'};
|
||||||
|
uint32_t datasz = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT asf_unpack_pcm_s16le(BYTE *dst, IMFSourceReader *srcreader, uint32_t szmax, uint32_t *sz)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
size_t srcpos = 0;
|
||||||
|
size_t srcchunk = 0;
|
||||||
|
BYTE *audiobuf = nullptr;
|
||||||
|
IMFSample *samples = nullptr;
|
||||||
|
IMFMediaBuffer *mediabuf = nullptr;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
DWORD flags = 0;
|
||||||
|
|
||||||
|
// Get next samples chunk, in memcpy capable format
|
||||||
|
hr = srcreader->ReadSample((DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, &flags, nullptr, &samples);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "ReadSample() failure, skipping..");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "Unsupported WAVE format, skipping..");
|
||||||
|
samples->Release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (samples == nullptr)
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "Missing samples");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
hr = samples->ConvertToContiguousBuffer(&mediabuf);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "ConvertToContiguousBuffer() failure, skipping..");
|
||||||
|
samples->Release();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store to destination (szmax as overflow check)
|
||||||
|
mediabuf->Lock(&audiobuf, nullptr, reinterpret_cast<DWORD *>(&srcchunk));
|
||||||
|
if (szmax - srcpos < srcchunk)
|
||||||
|
{
|
||||||
|
srcchunk = (signed int) szmax - srcpos;
|
||||||
|
}
|
||||||
|
memcpy(dst + srcpos, audiobuf, srcchunk);
|
||||||
|
srcpos += srcchunk;
|
||||||
|
hr = mediabuf->Unlock();
|
||||||
|
|
||||||
|
// Necessary per samples chunk
|
||||||
|
audiobuf = nullptr;
|
||||||
|
samples->Release();
|
||||||
|
mediabuf->Release();
|
||||||
|
if (srcpos >= szmax)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*sz = srcpos;
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
HRESULT asf_to_wav(const BYTE *srcasf, uint32_t srcsz, BYTE **dstwav, uint32_t *dstsz)
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
// Reuse raw asf container into a byte stream https://stackoverflow.com/questions/46493191/create-imfbytestream-from-byte-array
|
||||||
|
IStream *shstream = SHCreateMemStream(srcasf, srcsz);
|
||||||
|
IMFByteStream *bstream;
|
||||||
|
MFCreateMFByteStreamOnStream(shstream, &bstream);
|
||||||
|
|
||||||
|
// Create preconfigured from source buffer reader
|
||||||
|
IMFSourceReader *srcreader;
|
||||||
|
hr = MFCreateSourceReaderFromByteStream(bstream, nullptr, &srcreader);
|
||||||
|
|
||||||
|
// Setup wav metadata/header (s16le@44.1kHz 2ch)
|
||||||
|
UINT32 a, b, c;
|
||||||
|
IMFMediaType *mediatype;
|
||||||
|
PROPVARIANT duration;
|
||||||
|
srcreader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_AUDIO_STREAM, &mediatype);
|
||||||
|
srcreader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &duration);
|
||||||
|
#ifdef _WIN64
|
||||||
|
mediatype->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &a);
|
||||||
|
mediatype->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &b);
|
||||||
|
mediatype->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &c);
|
||||||
|
#else
|
||||||
|
a = 2;
|
||||||
|
b = 44100;
|
||||||
|
c = 16;
|
||||||
|
#endif
|
||||||
|
wav_hdr dsthdr = {
|
||||||
|
.channels=static_cast<uint16_t>(a),
|
||||||
|
.samplerate=b,
|
||||||
|
.bitdepth=static_cast<uint16_t>(c)
|
||||||
|
};
|
||||||
|
|
||||||
|
// ASF reader => PCM data
|
||||||
|
if (!*dstwav) *dstwav = (BYTE *) malloc(size_t(((double) duration.uhVal.QuadPart / 10000000.0 * dsthdr.samplerate + 4096) * dsthdr.bitdepth * dsthdr.channels) + sizeof(struct wav_hdr));
|
||||||
|
asf_unpack_pcm_s16le(*dstwav + sizeof(struct wav_hdr), srcreader, 0xFFFFFFFF, dstsz); //_INFO: overflow handled elsewhere
|
||||||
|
|
||||||
|
// Finalize and store header
|
||||||
|
dsthdr.datasz = *dstsz;
|
||||||
|
dsthdr.filesz = *dstsz + sizeof(struct wav_hdr) - 8;
|
||||||
|
memcpy(*dstwav, &dsthdr, sizeof(struct wav_hdr));
|
||||||
|
*dstsz += sizeof(wav_hdr);
|
||||||
|
|
||||||
|
// Cleanup without releasing srcasf
|
||||||
|
PropVariantClear(&duration);
|
||||||
|
mediatype->Release();
|
||||||
|
srcreader->Release();
|
||||||
|
bstream->Close();
|
||||||
|
shstream->Release();
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
bool init()
|
||||||
|
{
|
||||||
|
HMODULE mf_ = libutils::try_library("mf.dll");
|
||||||
|
HMODULE mfreadwrite_ = libutils::try_library("mfreadwrite.dll");
|
||||||
|
HMODULE mfplat_ = libutils::try_library("mfplat.dll");
|
||||||
|
HMODULE shlwapi_ = libutils::try_library("shlwapi.dll");
|
||||||
|
if (!mf_ || !mfreadwrite_ || !mfplat_ || !shlwapi_) return false;
|
||||||
|
|
||||||
|
// Required by linker
|
||||||
|
MFCreateMFByteStreamOnStream = (MFCreateMFByteStreamOnStream_t) GetProcAddress(mfplat_, "MFCreateMFByteStreamOnStream");
|
||||||
|
MFStartup = (MFStartup_t) GetProcAddress(mfplat_, "MFStartup");
|
||||||
|
MFShutdown = (MFShutdown_t) GetProcAddress(mfplat_, "MFShutdown");
|
||||||
|
MFCreateSourceReaderFromByteStream = (MFCreateSourceReaderFromByteStream_t) GetProcAddress(mfreadwrite_, "MFCreateSourceReaderFromByteStream");
|
||||||
|
SHCreateMemStream = (SHCreateMemStream_t) GetProcAddress(shlwapi_, "SHCreateMemStream");
|
||||||
|
|
||||||
|
if (!MFCreateMFByteStreamOnStream || !MFCreateSourceReaderFromByteStream || !MFStartup || !MFShutdown || FAILED(MFStartup(MF_VERSION, MFSTARTUP_FULL)))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void deinit()
|
||||||
|
{
|
||||||
|
MFShutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace hooks::soundbank
|
||||||
|
{
|
||||||
|
constexpr char SNDPATHFMT[] = "%05d/%05d";
|
||||||
|
constexpr size_t SNDPATHFMTMAX = sizeof(SNDPATHFMT) - 1;
|
||||||
|
constexpr size_t MNTPATHMAX = sizeof("/sdAABBB/AABBB/AABBBC_pre.2dx");
|
||||||
|
constexpr size_t AVSPATHMAX = sizeof("/data/sound/AABBB/AABBBC_pre.2dx");
|
||||||
|
constexpr uint8_t CACHEMAX = 8;
|
||||||
|
constexpr int operator "" _i(long double x) { return static_cast<int>(x); }
|
||||||
|
typedef struct snd_bank snd_bank;
|
||||||
|
typedef struct snd_s3p snd_s3p;
|
||||||
|
typedef struct snd_2dx snd_2dx;
|
||||||
|
typedef void *(*EnumValidSoundbanks_t)(void *, int32_t, int32_t);
|
||||||
|
|
||||||
|
struct snd_2dx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct bank
|
||||||
|
{
|
||||||
|
struct voice_hdr
|
||||||
|
{
|
||||||
|
char sig[4];
|
||||||
|
uint32_t fbegin;
|
||||||
|
uint32_t sz;
|
||||||
|
int16_t unk0;
|
||||||
|
int16_t type;
|
||||||
|
int16_t unk1;
|
||||||
|
int16_t volume;
|
||||||
|
int32_t unk2;
|
||||||
|
[[nodiscard]] constexpr BYTE *wave() noexcept
|
||||||
|
{
|
||||||
|
return ((BYTE *) this) + this->fbegin;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct voice_ptr
|
||||||
|
{
|
||||||
|
uint32_t fbegin;
|
||||||
|
[[nodiscard]] constexpr void sz(voice_hdr *val) noexcept
|
||||||
|
{
|
||||||
|
(this + 1)->fbegin = this->fbegin + val->fbegin + val->sz; // see constructor
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr size_t sz() const noexcept
|
||||||
|
{
|
||||||
|
return (this + 1)->fbegin > 0 ? (this + 1)->fbegin - this->fbegin : 0; // see constructor
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char name[16];
|
||||||
|
uint32_t sz;
|
||||||
|
uint32_t voice_cnt;
|
||||||
|
char unk[48];
|
||||||
|
} header;
|
||||||
|
voice_ptr table;
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr size_t sz() const noexcept
|
||||||
|
{
|
||||||
|
return (&table + header.voice_cnt - 1)->fbegin + (&table + header.voice_cnt - 1)->sz();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] static constexpr size_t assertsz_asf(size_t sz, int8_t resampler = 1) noexcept
|
||||||
|
{
|
||||||
|
resampler = (resampler > 1 || resampler == -1) ? 2 : 1; // resampler ratio multiplier (see pcm_resampler enum, original data is float)
|
||||||
|
return static_cast<size_t>(static_cast<double>(sz) * 14.8) * resampler + WAVHDRMAX; // 0.wma is consistent 180 therefore VBR Q90, sometimes 160 though, but samples are all over the place
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr const decltype(bank::header) *header() const noexcept
|
||||||
|
{
|
||||||
|
return &this->bank_->header;
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr bank::voice_ptr *voice_ptr(size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return &bank_->table + i;
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr bank::voice_hdr *voice(size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return (bank::voice_hdr *) ((char *) this->bank_ + this->voice_ptr(i)->fbegin);
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr size_t voice_emplace(size_t assertsz) noexcept //_INFO: assertsz guaranteed until serialize(true), overridden by voice_ptr::sz(v), compute value with assertsz_*()
|
||||||
|
{
|
||||||
|
// memory space assertion
|
||||||
|
if (this->voice_ptr(this->bank_->header.voice_cnt)->fbegin + assertsz >= banksz_)
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank", "snd_2dx::voice_emplace({}=>{})", banksz_, banksz_ + assertsz + ALLOCSIZE);
|
||||||
|
banksz_ += assertsz + ALLOCSIZE;
|
||||||
|
bank_ = (bank *) realloc(bank_, banksz_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// voice_ptr updating works through voice_ptr::sz()
|
||||||
|
//_REV: table and header.sz resizing event if voice_cnt == 4077, as voice_ptr::sz() needs to read 1 ahead
|
||||||
|
|
||||||
|
// voice_hdr setup
|
||||||
|
bank::voice_hdr *voice_hdr = this->voice(this->bank_->header.voice_cnt);
|
||||||
|
std::copy("2DX9", &"2DX9"[4], voice_hdr->sig);
|
||||||
|
voice_hdr->fbegin = sizeof(bank::voice_hdr);
|
||||||
|
voice_hdr->sz = 0;
|
||||||
|
voice_hdr->unk0 = (bank_->header.name[1] - '0') % 2 == 1 ? 0x3231 : 0x3230; // 0x3230/0x3231 for even/odd style
|
||||||
|
voice_hdr->type = this->bank_->header.voice_cnt == 0 ? 0 : -1; // special case for Voice[0]
|
||||||
|
voice_hdr->unk1 = 0x40;
|
||||||
|
voice_hdr->volume = 1;
|
||||||
|
voice_hdr->unk2 = 0x0;
|
||||||
|
return this->bank_->header.voice_cnt++;
|
||||||
|
}
|
||||||
|
static snd_2dx *unpack(char *refbank) = delete;
|
||||||
|
static snd_2dx *pack(int id);
|
||||||
|
|
||||||
|
bank *serialize(bool trim);
|
||||||
|
~snd_2dx();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t WAVHDRMAX = 78;
|
||||||
|
static constexpr size_t ALLOCSIZE = 4 * 1024 * 1024;
|
||||||
|
struct bank *bank_;
|
||||||
|
size_t banksz_;
|
||||||
|
explicit snd_2dx(uint8_t *bindbank);
|
||||||
|
|
||||||
|
};
|
||||||
|
snd_2dx::snd_2dx(uint8_t *bindbank) : bank_(reinterpret_cast<struct bank *>(bindbank)), banksz_(0)
|
||||||
|
{
|
||||||
|
if (bank_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Necessary bank header initialization
|
||||||
|
banksz_ = ALLOCSIZE;
|
||||||
|
bank_ = (bank *) malloc(ALLOCSIZE);
|
||||||
|
memset(&bank_->header, 0, sizeof(bank_->header) + 4078 * sizeof(bank::voice_ptr)); // initializes bank::voice_ptr::sz and bank::header.unk
|
||||||
|
bank_->header.name[0] = '\0';
|
||||||
|
bank_->header.voice_cnt = 0;
|
||||||
|
bank_->header.sz = sizeof(bank_->header) + 4078 * sizeof(bank::voice_ptr); // 4078 keysounds limit (16KB header), refer to voice_emplace()
|
||||||
|
|
||||||
|
// Necessary voice pointer table initialization (refer to voice_ptr::sz())
|
||||||
|
(&bank_->table)[0].fbegin = bank_->header.sz;
|
||||||
|
}
|
||||||
|
snd_2dx *snd_2dx::pack(int id)
|
||||||
|
{
|
||||||
|
snd_2dx *r = new snd_2dx(nullptr);
|
||||||
|
snprintf(r->bank_->header.name, sizeof(r->bank_->header.name), "%05d.2dx", id);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
snd_2dx::bank *snd_2dx::serialize(bool trim)
|
||||||
|
{
|
||||||
|
if (trim)
|
||||||
|
{
|
||||||
|
//_REV: prune voice_ptr for unused voice slots + move data segment up adjusting voice_ptr->fbegin
|
||||||
|
}
|
||||||
|
return bank_;
|
||||||
|
}
|
||||||
|
snd_2dx::~snd_2dx()
|
||||||
|
{
|
||||||
|
free(bank_);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct snd_s3p
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct bank
|
||||||
|
{
|
||||||
|
struct voice_hdr
|
||||||
|
{
|
||||||
|
char sig[4]; // S3V0
|
||||||
|
uint32_t fbegin;
|
||||||
|
uint32_t sz;
|
||||||
|
uint8_t unk[20];
|
||||||
|
[[nodiscard]] constexpr BYTE *asf() const noexcept
|
||||||
|
{
|
||||||
|
return ((BYTE *) this) + this->fbegin;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct voice_ptr
|
||||||
|
{
|
||||||
|
uint32_t fbegin;
|
||||||
|
uint32_t sz;
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char sig[4]; // S3P0
|
||||||
|
uint32_t voice_cnt;
|
||||||
|
} header;
|
||||||
|
voice_ptr table;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const decltype(bank::header) *header() const noexcept
|
||||||
|
{
|
||||||
|
return &this->bank_->header;
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr bank::voice_ptr *voice_ptr(size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return &bank_->table + i;
|
||||||
|
}
|
||||||
|
[[nodiscard]] constexpr bank::voice_hdr *voice(size_t i) const noexcept
|
||||||
|
{
|
||||||
|
return (bank::voice_hdr *) ((char *) this->bank_ + this->voice_ptr(i)->fbegin);
|
||||||
|
}
|
||||||
|
|
||||||
|
static snd_s3p *unpack(uint8_t *refbank);
|
||||||
|
static snd_s3p *pack(int id) = delete;
|
||||||
|
bank *serialize(bool trim) = delete;
|
||||||
|
~snd_s3p();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct bank *bank_;
|
||||||
|
size_t banksz_; //_TODO: keep track of allocated memory
|
||||||
|
explicit snd_s3p(uint8_t *bindbank);
|
||||||
|
};
|
||||||
|
snd_s3p::snd_s3p(uint8_t *bindbank) : bank_(reinterpret_cast<struct bank *>(bindbank)), banksz_(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
snd_s3p::~snd_s3p()
|
||||||
|
{
|
||||||
|
free(bank_);
|
||||||
|
}
|
||||||
|
snd_s3p *snd_s3p::unpack(uint8_t *refbank)
|
||||||
|
{
|
||||||
|
return refbank ? new snd_s3p(refbank) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct snd_bank
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static snd_bank *new_instance(int id);
|
||||||
|
static void flush_cache();
|
||||||
|
static void pop_cache();
|
||||||
|
static snd_bank *get_bank(int id, const char suffix = '0');
|
||||||
|
static uint8_t *read_bank_any(const char *avspath, const char *ext, size_t *sz);
|
||||||
|
static bool has_format(const char *avspath, const char *ext);
|
||||||
|
static avs::core::avs_file_t map_ifs(char *avspath);
|
||||||
|
static void dump(const char *path, const uint8_t *src, size_t sz);
|
||||||
|
|
||||||
|
int id;
|
||||||
|
char avspath[AVSPATHMAX];
|
||||||
|
void cache_bank_any(const uint8_t *sndbuf, size_t sz);
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool is_cached() const noexcept
|
||||||
|
{
|
||||||
|
return uid_ != UID_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const char *sndpath() const noexcept
|
||||||
|
{
|
||||||
|
const char *it = avspath + AVSPATHMAX;
|
||||||
|
size_t c = 0;
|
||||||
|
while (it >= avspath && c < 2)
|
||||||
|
{
|
||||||
|
it--;
|
||||||
|
if (*it == '/') c++;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
if (strlen(it) > SNDPATHFMTMAX)
|
||||||
|
return SNDPATHFMT;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
inline static avcodec::pcm_resampler_t resampler() noexcept
|
||||||
|
{
|
||||||
|
return resampler_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr avs::core::avs_file_t E_NOT_FOUND = 0x80070002;
|
||||||
|
static constexpr uint8_t UID_INVALID = 0x00;
|
||||||
|
static snd_bank *cache_;
|
||||||
|
static size_t cachesz_;
|
||||||
|
static avcodec::pcm_resampler_t resampler_;
|
||||||
|
friend void hooks::soundbank::init(HINSTANCE hmodule, const char *model, const char *ext);
|
||||||
|
|
||||||
|
uint8_t uid_;
|
||||||
|
uint32_t mnt_;
|
||||||
|
snd_bank *next_;
|
||||||
|
snd_bank();
|
||||||
|
~snd_bank();
|
||||||
|
};
|
||||||
|
void snd_bank::dump(const char *path, const uint8_t *src, size_t sz)
|
||||||
|
{
|
||||||
|
FILE *fh = fopen(path, "wb");
|
||||||
|
fwrite(src, sz, 1, fh);
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
snd_bank *snd_bank::new_instance(int id)
|
||||||
|
{
|
||||||
|
snd_bank *prev, *instance;
|
||||||
|
|
||||||
|
// Latest entry should always be head
|
||||||
|
instance = new snd_bank();
|
||||||
|
instance->id = id;
|
||||||
|
instance->next_ = cache_;
|
||||||
|
cache_ = instance;
|
||||||
|
cachesz_ += 1;
|
||||||
|
|
||||||
|
// Clean cache (last entry indexing target excluded, cache limit reached)
|
||||||
|
if (instance->next_ && instance->next_->uid_ == UID_INVALID)
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank", "Cache prune");
|
||||||
|
prev = instance->next_;
|
||||||
|
instance->next_ = prev->next_;
|
||||||
|
log_info("hooks::soundbank", "Removing {}::Bank[CACHE]::{}", prev->id, (uint32_t) prev->uid_);
|
||||||
|
delete prev;
|
||||||
|
cachesz_ -= 1;
|
||||||
|
}
|
||||||
|
if (cachesz_ > CACHEMAX)
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank", "Cache full");
|
||||||
|
for (uint8_t i = 0; i < CACHEMAX; i += 2)
|
||||||
|
{
|
||||||
|
prev = nullptr;
|
||||||
|
instance = cache_;
|
||||||
|
while (instance && instance->next_)
|
||||||
|
{
|
||||||
|
prev = instance;
|
||||||
|
instance = instance->next_;
|
||||||
|
}
|
||||||
|
prev->next_ = nullptr;
|
||||||
|
delete instance;
|
||||||
|
cachesz_ -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache_;
|
||||||
|
}
|
||||||
|
void snd_bank::cache_bank_any(const uint8_t *sndbuf, size_t sz)
|
||||||
|
{
|
||||||
|
// Update struct using next free cache uid
|
||||||
|
if (uid_ == UID_INVALID)
|
||||||
|
{
|
||||||
|
snd_bank *it = cache_;
|
||||||
|
while (it)
|
||||||
|
{
|
||||||
|
if (uid_ == UID_INVALID || (uid_ == it->uid_ && it != this))
|
||||||
|
{
|
||||||
|
uid_--;
|
||||||
|
it = cache_;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it = it->next_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snprintf(this->avspath, sizeof(this->avspath), "data/sound/system/%02x", (unsigned int) uid_);
|
||||||
|
|
||||||
|
// Store file
|
||||||
|
char path[AVSPATHMAX];
|
||||||
|
snprintf(path, sizeof(path), "%s.2dx", this->avspath);
|
||||||
|
log_info("hooks::soundbank", "Storing as intermediate soundbank at '{}'", (const char *) path);
|
||||||
|
dump(path, sndbuf, sz);
|
||||||
|
}
|
||||||
|
snd_bank::snd_bank() : id(0), avspath(""), uid_(UID_INVALID), mnt_(E_NOT_FOUND), next_(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
snd_bank::~snd_bank()
|
||||||
|
{
|
||||||
|
if (uid_ != UID_INVALID)
|
||||||
|
{
|
||||||
|
char path[AVSPATHMAX];
|
||||||
|
snprintf(path, sizeof(path), "data/sound/system/%02x.2dx", uid_);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[CACHE]::Purge '{}'", this->id, (const char *) path);
|
||||||
|
remove(path);
|
||||||
|
}
|
||||||
|
if (mnt_ != E_NOT_FOUND)
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[CACHE]::Purge mount(0x{:08x})", this->id, mnt_);
|
||||||
|
avs::core::avs_fs_umount(mnt_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snd_bank *snd_bank::get_bank(int id, const char suffix)
|
||||||
|
{
|
||||||
|
// Find in cache (latest=>oldest)
|
||||||
|
id = id + ((suffix - '0') * 1e6_i);
|
||||||
|
for (snd_bank *it = cache_; it; it = it->next_)
|
||||||
|
if (it->id == id) return it;
|
||||||
|
|
||||||
|
// Find in avs (has valid s3p/.2dx resource at data/sound/AABBB/AABBB.2dx)
|
||||||
|
snd_bank *bank = new_instance(id);
|
||||||
|
snprintf(bank->avspath, AVSPATHMAX, "data/sound/%05d", (id % 1e6_i));
|
||||||
|
if (has_format(bank->avspath, ".ifs"))
|
||||||
|
bank->mnt_ = map_ifs(bank->avspath);
|
||||||
|
snprintf(bank->avspath + strlen(bank->avspath), 7, "/%05d", (id % 1e6_i));
|
||||||
|
if (id / 1e6_i) snprintf(bank->avspath + strlen(bank->avspath), 2, "%c", '0' + (id / 1e6_i));
|
||||||
|
if (!(has_format(bank->avspath, ".s3p") || has_format(bank->avspath, ".2dx")))
|
||||||
|
{
|
||||||
|
pop_cache();
|
||||||
|
bank = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bank;
|
||||||
|
}
|
||||||
|
void snd_bank::flush_cache()
|
||||||
|
{
|
||||||
|
snd_bank *prev;
|
||||||
|
while (cache_)
|
||||||
|
{
|
||||||
|
prev = cache_;
|
||||||
|
cache_ = cache_->next_;
|
||||||
|
delete prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void snd_bank::pop_cache()
|
||||||
|
{
|
||||||
|
snd_bank *prev = cache_;
|
||||||
|
cache_ = cache_->next_;
|
||||||
|
delete prev;
|
||||||
|
}
|
||||||
|
uint8_t *snd_bank::read_bank_any(const char *avspath, const char *ext, size_t *sz)
|
||||||
|
{
|
||||||
|
constexpr uint16_t O_RDONLY = 1; // rw:12 consistent across versions with s3p support
|
||||||
|
uint8_t *r = nullptr;
|
||||||
|
char path[AVSPATHMAX];
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "%s%s", avspath, ext);
|
||||||
|
avs::core::avs_file_t fd = avs::core::avs_fs_open(path, O_RDONLY, 420);
|
||||||
|
if (fd != E_NOT_FOUND)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
avs::core::avs_stat st; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||||
|
avs::core::avs_fs_fstat(fd, &st);
|
||||||
|
*sz = st.filesize;
|
||||||
|
}
|
||||||
|
r = (uint8_t *) malloc(*sz);
|
||||||
|
if (r) avs::core::avs_fs_read(fd, r, *sz);
|
||||||
|
avs::core::avs_fs_close(fd);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
bool snd_bank::has_format(const char *avspath, const char *ext)
|
||||||
|
{
|
||||||
|
char path[AVSPATHMAX] = "";
|
||||||
|
snprintf(path, sizeof(path), "%s%s", avspath, ext);
|
||||||
|
avs::core::avs_stat st; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||||
|
bool r = static_cast<bool>(avs::core::avs_fs_lstat(path, &st)); // lstat should be faster than open
|
||||||
|
log_info("hooks::soundbank", "'{}' exists? => {}", path, r);
|
||||||
|
return static_cast<bool>(r);
|
||||||
|
}
|
||||||
|
avs::core::avs_file_t snd_bank::map_ifs(char *avspath)
|
||||||
|
{
|
||||||
|
// Map */${name}.ifs => /sc${name}
|
||||||
|
char ifspath[AVSPATHMAX];
|
||||||
|
char mntpath[MNTPATHMAX];
|
||||||
|
const char *it = avspath + strlen(avspath);
|
||||||
|
while (it >= avspath && *it != '/')
|
||||||
|
{
|
||||||
|
it--;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
snprintf(ifspath, sizeof(ifspath), "%s.ifs", avspath);
|
||||||
|
snprintf(mntpath, sizeof(mntpath), "sc%s", it);
|
||||||
|
avs::core::avs_file_t r = avs::core::avs_fs_mount(mntpath, ifspath, "imagefs", nullptr);
|
||||||
|
|
||||||
|
// Finalize avspath
|
||||||
|
if (r != E_NOT_FOUND)
|
||||||
|
{
|
||||||
|
snprintf(mntpath + strlen(mntpath), strlen(it) + 2, "/%s", it);
|
||||||
|
log_info("hooks::soundbank", "'{}' => '{}'", avspath, mntpath);
|
||||||
|
strcpy(avspath, mntpath);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct offset_t
|
||||||
|
{
|
||||||
|
intptr_t RD_05d_s3p; // %05d/%05d.s3p
|
||||||
|
intptr_t RD_05d_c_s3p; // %05d/%05d%c.s3p
|
||||||
|
intptr_t RD_05d_2dx; // %05d/%05d.2dx
|
||||||
|
intptr_t RD_05d_c_2dx; // %05d/%05d%c.2dx
|
||||||
|
intptr_t TX_EnumValidSoundbanks; // enumerates above databank paths, simple exist check (lstat()/OPEN -> CLOSE_NOWRITE only)
|
||||||
|
intptr_t DAT_song_titlel;
|
||||||
|
intptr_t DAT_song_artistl;
|
||||||
|
intptr_t DAT_song_id;
|
||||||
|
bool is_lstr_wchar;
|
||||||
|
memutils::VProtectGuard *guard;
|
||||||
|
} offset_;
|
||||||
|
snd_bank *snd_bank::cache_ = nullptr;
|
||||||
|
size_t snd_bank::cachesz_ = 0;
|
||||||
|
avcodec::pcm_resampler_t snd_bank::resampler_ = avcodec::bmswac_resampler_s16;
|
||||||
|
static EnumValidSoundbanks_t EnumValidSoundbanks;
|
||||||
|
void *on_enum_valid_soundbanks(void *song, int32_t difficulty, int32_t unk2)
|
||||||
|
{
|
||||||
|
// Keysounds populated into CtrlSound::Bank[2][X] = [0:s3p][1:2dx][2:_pre.2dx], always uses lowest i databank for resource confirmed valid by this function
|
||||||
|
// Struct memory layout 1:1 with data/info/(0/1)/music_*.bin
|
||||||
|
snd_bank *keysounds = nullptr;
|
||||||
|
const char *titlel = (const char *) song + offset_.DAT_song_titlel;
|
||||||
|
const char *artistl = (const char *) song + offset_.DAT_song_artistl;
|
||||||
|
const int32_t id = *(int32_t *) ((const char *) song + offset_.DAT_song_id);
|
||||||
|
const char suffix = *((const char *) song + offset_.DAT_song_id + 8 + difficulty);
|
||||||
|
|
||||||
|
if (offset_.is_lstr_wchar)
|
||||||
|
{
|
||||||
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
||||||
|
log_info("hooks::soundbank", "Processing s3p->2dx transcoding routine for [{}]({} - {})",
|
||||||
|
id,
|
||||||
|
converter.to_bytes(std::wstring(reinterpret_cast<const wchar_t *>(artistl), wcslen(reinterpret_cast<const wchar_t *>(artistl)))),
|
||||||
|
converter.to_bytes(std::wstring(reinterpret_cast<const wchar_t *>(titlel), wcslen(reinterpret_cast<const wchar_t *>(titlel))))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_info("hooks::soundbank", "Processing s3p->2dx transcoding routine for [{}]({} - {})", id, artistl, titlel);
|
||||||
|
if (!(keysounds = snd_bank::get_bank(id, suffix)))
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "soundbank::get_bank() was 0x0, this shouldn't happen..");
|
||||||
|
memcpy(reinterpret_cast<void *>(offset_.RD_05d_2dx), "%05d/%05d", SNDPATHFMTMAX);
|
||||||
|
return EnumValidSoundbanks(song, difficulty, unk2);
|
||||||
|
}
|
||||||
|
else if (!snd_bank::has_format(keysounds->avspath, ".2dx"))
|
||||||
|
{
|
||||||
|
// Get s3p and process into s3p soundbank for intermediate wma voice storage
|
||||||
|
size_t szs3p;
|
||||||
|
uint8_t *bufs3p = snd_bank::read_bank_any(keysounds->avspath, ".s3p", &szs3p);
|
||||||
|
snd_s3p *snds3p = snd_s3p::unpack(bufs3p);
|
||||||
|
|
||||||
|
// Process wma voices into wav voices stored directly into 2dx soundbank
|
||||||
|
size_t i, j;
|
||||||
|
snd_2dx *snd2dx = snd_2dx::pack(id);
|
||||||
|
for (i = 0; i < snds3p->header()->voice_cnt; i++)
|
||||||
|
{
|
||||||
|
// WMA=>WAV transcode
|
||||||
|
snd_s3p::bank::voice_hdr *voicesrc = snds3p->voice(i);
|
||||||
|
j = snd2dx->voice_emplace(snd_2dx::assertsz_asf(voicesrc->sz));
|
||||||
|
snd_2dx::bank::voice_hdr *voicedst = snd2dx->voice(j);
|
||||||
|
BYTE *voicedst_wave = voicedst->wave();
|
||||||
|
avcodec::BmswTranscoderAsfToWav(voicesrc->asf(), voicesrc->sz, &voicedst_wave, &voicedst->sz, snd_bank::resampler());
|
||||||
|
snd2dx->voice_ptr(j)->sz(voicedst); // updates voice_ptr table, do not skip
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output to cache (reuse output file, while in valid cache)
|
||||||
|
snd_2dx::bank *buf2dx = snd2dx->serialize(false);
|
||||||
|
keysounds->cache_bank_any(reinterpret_cast<const uint8_t *>(buf2dx), buf2dx->sz());
|
||||||
|
|
||||||
|
//_REV: symlink system/uid_.2dx -> /tmp/uid_.2dx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume execution (force %05.2dx branch)
|
||||||
|
const char *t = keysounds->sndpath();
|
||||||
|
memcpy(reinterpret_cast<void *>(offset_.RD_05d_2dx), t, SNDPATHFMTMAX);
|
||||||
|
log_info("hooks::soundbank", "RD_05d_2dx set to '{}'", reinterpret_cast<const char *>(offset_.RD_05d_2dx));
|
||||||
|
log_info("hooks::soundbank", "Processing completed");
|
||||||
|
*((char *) song + offset_.DAT_song_id + 8 + difficulty) = keysounds->is_cached() ? '0' : suffix;
|
||||||
|
void *r = EnumValidSoundbanks(song, difficulty, unk2);
|
||||||
|
*((char *) song + offset_.DAT_song_id + 8 + difficulty) = suffix;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
static class Tests : public hooks::devel::Routine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Routine::Routine;
|
||||||
|
void entry_main() override
|
||||||
|
{
|
||||||
|
size_t szs3p;
|
||||||
|
BYTE *wav = nullptr;
|
||||||
|
uint32_t wavsz = 0;
|
||||||
|
char avspath[AVSPATHMAX];
|
||||||
|
avs::core::avs_file_t avsmnt = 0;
|
||||||
|
char sig[5] = " ";
|
||||||
|
int id = 25073;
|
||||||
|
if (!mf_broken::init())
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "MF initialization failed, skipping..");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filesystem tests, s3p unpacking
|
||||||
|
snprintf(avspath, sizeof(avspath), "data/sound/%05d", id);
|
||||||
|
if (snd_bank::has_format(avspath, ".ifs")) avsmnt = snd_bank::map_ifs(avspath);
|
||||||
|
snprintf(avspath + strlen(avspath), 7, "/%05d", id);
|
||||||
|
snd_bank::has_format(avspath, ".s3p");
|
||||||
|
snd_bank::has_format(avspath, ".2dx");
|
||||||
|
snd_bank::has_format(avspath, "_pre.2dx");
|
||||||
|
uint8_t *bufs3p = snd_bank::read_bank_any(avspath, ".s3p", &szs3p);
|
||||||
|
snd_s3p *snds3p = snd_s3p::unpack(bufs3p);
|
||||||
|
if (avsmnt) avs::core::avs_fs_umount(avsmnt);
|
||||||
|
|
||||||
|
// S3P => WMA => WAV => 2DX pipeline
|
||||||
|
if (snds3p)
|
||||||
|
{
|
||||||
|
// S3P/S3V metadata
|
||||||
|
memcpy(sig, snds3p->header()->sig, 4);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[S3P]::Signature {}", id, sig);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[S3P]::Size {}", id, szs3p);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[S3P]::VoiceCount {}", id, snds3p->header()->voice_cnt);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[S3P]::Voice[0]::Size {}", id, snds3p->voice_ptr(0)->sz);
|
||||||
|
memcpy(sig, snds3p->voice(0)->sig, 4);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[S3P]::Voice[0]::Signature {}", id, sig);
|
||||||
|
snd_bank::dump("raw_wma.wma", snds3p->voice(0)->asf(), snds3p->voice(0)->sz);
|
||||||
|
|
||||||
|
// MF codec (tainted PCM data, bad)
|
||||||
|
mf_broken::asf_to_wav(snds3p->voice(0)->asf(), snds3p->voice(0)->sz, &wav, &wavsz);
|
||||||
|
snd_bank::dump("mf_wav.wav", wav, wavsz);
|
||||||
|
free(wav);
|
||||||
|
wav = nullptr;
|
||||||
|
wavsz = 0;
|
||||||
|
|
||||||
|
// AV codec (1:1 unmodified PCM data, other than resampling if enabled)
|
||||||
|
wav = (BYTE *) malloc(snd_2dx::assertsz_asf(snds3p->voice(0)->sz, avcodec::bmswac_resampler_f32));
|
||||||
|
avcodec::BmswTranscoderAsfToWav(snds3p->voice(0)->asf(), snds3p->voice(0)->sz, &wav, &wavsz, avcodec::bmswac_resampler_f32);
|
||||||
|
snd_bank::dump("ac_wav.wav", wav, wavsz);
|
||||||
|
free(wav);
|
||||||
|
wav = nullptr;
|
||||||
|
wavsz = 0;
|
||||||
|
|
||||||
|
// S3P=>2DX (max 4076 voices)
|
||||||
|
size_t i, j;
|
||||||
|
snd_2dx *snd2dx = snd_2dx::pack(id);
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[2DX]::Name {}", id, snd2dx->header()->name);
|
||||||
|
for (i = 0; i < snds3p->header()->voice_cnt; i++)
|
||||||
|
{
|
||||||
|
// WMA=>WAV transcode
|
||||||
|
snd_s3p::bank::voice_hdr *voicesrc = snds3p->voice(i);
|
||||||
|
j = snd2dx->voice_emplace(snd_2dx::assertsz_asf(voicesrc->sz));
|
||||||
|
snd_2dx::bank::voice_hdr *voicedst = snd2dx->voice(j);
|
||||||
|
BYTE *voicedst_wave = voicedst->wave();
|
||||||
|
//mf_broken::asf_to_wav(voicesrc->asf(), voicesrc->sz, &voicedst_wave, &voicedst->sz);
|
||||||
|
avcodec::BmswTranscoderAsfToWav(voicesrc->asf(), voicesrc->sz, &voicedst_wave, &voicedst->sz, snd_bank::resampler());
|
||||||
|
snd2dx->voice_ptr(j)->sz(voicedst); // updates voice_ptr table, do not skip
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid 2DX (trim is not necessary)
|
||||||
|
log_info("hooks::soundbank", "{}::Bank[2DX]::Dumping", id);
|
||||||
|
snd_2dx::bank *buf2dx = snd2dx->serialize(false);
|
||||||
|
snd_bank::dump("ac_soundbank.2dx", reinterpret_cast<const uint8_t *>(buf2dx), buf2dx->sz());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank", "Tests failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caching and intermediate 2dx storage detection
|
||||||
|
EnumValidSoundbanks_t t = EnumValidSoundbanks;
|
||||||
|
EnumValidSoundbanks = [](void *, int32_t, int32_t) -> void * { return nullptr; };
|
||||||
|
char *tmp = (char *) malloc(0x3b8 + strlen("00000000") + 1);
|
||||||
|
int arr[6] = {25073, 24016, 26057, 25073, 26087, 29095};
|
||||||
|
strcpy(tmp, "SJISTITLE");
|
||||||
|
strcpy(tmp + 0xc0, "SJISARTIST");
|
||||||
|
strcpy(tmp + 0x3b8, "00000000");
|
||||||
|
for (int it: arr)
|
||||||
|
{
|
||||||
|
*(int32_t *) (tmp + 0x3b0) = it;
|
||||||
|
on_enum_valid_soundbanks(tmp, 3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
EnumValidSoundbanks = t;
|
||||||
|
snd_bank::flush_cache();
|
||||||
|
mf_broken::deinit();
|
||||||
|
}
|
||||||
|
} tests_("sndb_test");
|
||||||
|
void init(HINSTANCE hmodule, const char *model, const char *ext)
|
||||||
|
{
|
||||||
|
if (to_hash(model) != to_hash("LDJ")) return;
|
||||||
|
if (false && IsDebuggerPresent())
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "Debugger detected, skipping..");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!avcodec::init())
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "AVCodec initialization failed, skipping..");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override .data (per datacode)
|
||||||
|
long extl = strtol(ext, nullptr, 10);
|
||||||
|
if (extl < 2019100800)
|
||||||
|
{
|
||||||
|
offset_.DAT_song_titlel = 0x00;
|
||||||
|
offset_.DAT_song_artistl = 0xc0;
|
||||||
|
offset_.DAT_song_id = 0x1c8;
|
||||||
|
offset_.is_lstr_wchar = false;
|
||||||
|
snd_bank::resampler_ = avcodec::bmswac_resampler_s16_ad;
|
||||||
|
}
|
||||||
|
else if (extl < 2024082700)
|
||||||
|
{
|
||||||
|
offset_.DAT_song_titlel = 0x00;
|
||||||
|
offset_.DAT_song_artistl = 0xc0;
|
||||||
|
offset_.DAT_song_id = 0x3b0;
|
||||||
|
offset_.is_lstr_wchar = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset_.DAT_song_titlel = 0x00;
|
||||||
|
offset_.DAT_song_artistl = 0x1c0;
|
||||||
|
offset_.DAT_song_id = 0x67c;
|
||||||
|
offset_.is_lstr_wchar = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override .text (pattern match)
|
||||||
|
offset_.TX_EnumValidSoundbanks = patch_pipeline(
|
||||||
|
hmodule,
|
||||||
|
[](HMODULE hmodule, intptr_t addr) { return find_asm_leacstr_from(hmodule, R8, "%05d/%05d.2dx"); },
|
||||||
|
[](HMODULE hmodule, intptr_t addr) { return find_pattern_from(hmodule, "CCCCCCCCCCCCCCCC", "XXXXXXXX", 8, 0, addr, true); }
|
||||||
|
);
|
||||||
|
snd_bank::resampler_ = avcodec::BmswTranscoderResampler() == avcodec::bmswac_resampler_none ? snd_bank::resampler_ : avcodec::BmswTranscoderResampler();
|
||||||
|
offset_.TX_EnumValidSoundbanks = avcodec::BmswTranscoderEnumValidSoundbanksAddr() == 0x0 ? offset_.TX_EnumValidSoundbanks : (intptr_t) hmodule + (int64_t) avcodec::BmswTranscoderEnumValidSoundbanksAddr();
|
||||||
|
if (!offset_.TX_EnumValidSoundbanks)
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "Unsupported game version({}), skipping..", ext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_info("hooks::soundbank", "Supported game version({})", ext);
|
||||||
|
|
||||||
|
// Override .rdata (pattern match)
|
||||||
|
offset_.RD_05d_s3p = replace_pattern(hmodule, "253035642f253035642e73337000", "003035642f253035642e73337000", 0, 0);
|
||||||
|
offset_.RD_05d_c_s3p = replace_pattern(hmodule, "253035642f2530356425632e73337000", "003035642f2530356425632e73337000", 0, 0);
|
||||||
|
offset_.RD_05d_2dx = replace_pattern(hmodule, "253035642F253035642E32647800", "73797374656D2F30302E32647800", 0, 0);
|
||||||
|
offset_.RD_05d_c_2dx = replace_pattern(hmodule, "253035642f2530356425632e32647800", "253035642f2530356425632e32647800", 0, 0);
|
||||||
|
if (!(offset_.TX_EnumValidSoundbanks && offset_.RD_05d_s3p && offset_.RD_05d_c_s3p && offset_.RD_05d_2dx && offset_.RD_05d_c_2dx))
|
||||||
|
{
|
||||||
|
log_warning("hooks::soundbank", "Could not find valid offsets, skipping..");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup on_enum_valid_ksbd and optional tests
|
||||||
|
log_info("hooks::soundbank", "Hooking EnumValidSoundbanks(0x{:x})", offset_.TX_EnumValidSoundbanks);
|
||||||
|
offset_.guard = new memutils::VProtectGuard((void *) offset_.RD_05d_2dx, SNDPATHFMTMAX);
|
||||||
|
detour::trampoline(reinterpret_cast<void *>(offset_.TX_EnumValidSoundbanks), reinterpret_cast<void *>(on_enum_valid_soundbanks), reinterpret_cast<void **>(&EnumValidSoundbanks));
|
||||||
|
hooks::devel::bind_routine(&tests_);
|
||||||
|
|
||||||
|
log_info("hooks::soundbank", "Soundbank preprocessor ready");
|
||||||
|
}
|
||||||
|
void deinit(HINSTANCE hmodule)
|
||||||
|
{
|
||||||
|
log_info("hooks::soundbank", "Releasing soundbank preprocessor");
|
||||||
|
|
||||||
|
snd_bank::flush_cache();
|
||||||
|
delete offset_.guard;
|
||||||
|
avcodec::deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace hooks::soundbank
|
||||||
|
{
|
||||||
|
void init(HINSTANCE hmodule, const char *model, const char *ext);
|
||||||
|
void deinit(HINSTANCE hmodule);
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
#include "wmischook.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/sigscan.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "util/utils.h"
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
|
||||||
|
namespace hooks::wmisc::msacm
|
||||||
|
{
|
||||||
|
typedef MMRESULT (__stdcall *acmFormatSuggest_t)(HANDLE had, LPWAVEFORMATEX pwfxSrc, LPWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest);
|
||||||
|
static acmFormatSuggest_t acmFormatSuggest;
|
||||||
|
|
||||||
|
static uint64_t hash_waveformatex(const WAVEFORMATEX *pwfx, DWORD fdwSuggest)
|
||||||
|
{
|
||||||
|
//_INFO: no clashes, likely faster than hashing sizeof(WAVEFORMATEX) buffer
|
||||||
|
uint64_t h = 0;
|
||||||
|
h ^= (uint64_t) pwfx->nSamplesPerSec << 0;
|
||||||
|
h ^= (uint64_t) pwfx->nAvgBytesPerSec << 1;
|
||||||
|
h ^= (uint64_t) pwfx->nBlockAlign << 2;
|
||||||
|
h ^= (uint64_t) pwfx->wBitsPerSample << 3;
|
||||||
|
h ^= (uint64_t) pwfx->cbSize << 4;
|
||||||
|
h ^= (uint64_t) fdwSuggest << 5;
|
||||||
|
h ^= (uint64_t) pwfx->wFormatTag << 6;
|
||||||
|
h ^= (uint64_t) pwfx->nChannels << 7;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
MMRESULT __stdcall on_acmFormatSuggest(HANDLE had, LPWAVEFORMATEX pwfxSrc, LPWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest)
|
||||||
|
{
|
||||||
|
static std::unordered_map<uint64_t, std::vector<char>> acmformats;
|
||||||
|
static std::mutex mutex;
|
||||||
|
|
||||||
|
// Find cached formats
|
||||||
|
size_t hash = hash_waveformatex(pwfxSrc, fdwSuggest);
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
auto it = acmformats.find(hash);
|
||||||
|
if (it != acmformats.end())
|
||||||
|
{
|
||||||
|
// Copy cached result
|
||||||
|
memcpy(pwfxDst, it->second.data(), std::min(cbwfxDst, (DWORD) (sizeof(WAVEFORMATEX) + ((WAVEFORMATEX *) it->second.data())->cbSize)));
|
||||||
|
return MMSYSERR_NOERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache unique formats
|
||||||
|
log_info("hooks::wmisc::msacm", "Forwarding acmFormatSuggest({}) request due to cache miss", reinterpret_cast<void *>(hash));
|
||||||
|
MMRESULT r = acmFormatSuggest(had, pwfxSrc, pwfxDst, cbwfxDst, fdwSuggest);
|
||||||
|
if (r == MMSYSERR_NOERROR)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
acmformats[hash].resize(sizeof(WAVEFORMATEX) + pwfxDst->cbSize);
|
||||||
|
memcpy(acmformats[hash].data(), pwfxDst, sizeof(WAVEFORMATEX) + pwfxDst->cbSize);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
void attach(HINSTANCE hmodule)
|
||||||
|
{
|
||||||
|
// Override acmFormatSuggest
|
||||||
|
HMODULE msacm = nullptr;
|
||||||
|
if ((msacm = libutils::try_library("msacm32.dll")))
|
||||||
|
{
|
||||||
|
acmFormatSuggest = (acmFormatSuggest_t) GetProcAddress(msacm, "acmFormatSuggest");
|
||||||
|
}
|
||||||
|
log_info("hooks::wmisc::msacm", "Hooking acmFormatSuggest({})", reinterpret_cast<void *>(acmFormatSuggest));
|
||||||
|
detour::trampoline_try(reinterpret_cast<void *>(acmFormatSuggest), reinterpret_cast<void *>(on_acmFormatSuggest), reinterpret_cast<void **>(&acmFormatSuggest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace hooks::wmisc::thumbnail
|
||||||
|
{
|
||||||
|
typedef bool (*ThumExists_t)(void *titleUTF_getter, int32_t id, char flag);
|
||||||
|
static ThumExists_t ThumExists;
|
||||||
|
|
||||||
|
bool on_thum_exists_(void *titleUTF_getter, int32_t id, char flag)
|
||||||
|
{
|
||||||
|
static std::unordered_map<int32_t, bool> thumids;
|
||||||
|
auto it = thumids.find(id);
|
||||||
|
if (it != thumids.end())
|
||||||
|
{
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// log_misc("hooks::wmisc::thumbnail", "Caching state for [{}]", id);
|
||||||
|
it = thumids.insert({id, ThumExists(titleUTF_getter, id, flag)}).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
void attach(HINSTANCE hmodule)
|
||||||
|
{
|
||||||
|
// Reverse lookup function head (PUSH RDI) for ThumExists() specific signature, quietly fail if invalid
|
||||||
|
intptr_t TX_ThumExists = patch_pipeline(
|
||||||
|
hmodule,
|
||||||
|
[](HMODULE hmodule, intptr_t addr) { return find_pattern_from(hmodule, "83f801750c4084ff750732c0", "XXXXXXXXXXXX", 0, 0, 0); },
|
||||||
|
[](HMODULE hmodule, intptr_t addr) { return find_pattern_from(hmodule, "4057", "XX", 0, 0, addr, true); }
|
||||||
|
);
|
||||||
|
log_info("hooks::wmisc::thumbnail", "Hooking ThumExists({})", reinterpret_cast<void *>(TX_ThumExists));
|
||||||
|
detour::trampoline_try(reinterpret_cast<void *>(TX_ThumExists), reinterpret_cast<void *>(on_thum_exists_), reinterpret_cast<void **>(&ThumExists));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace hooks::wmisc::bmsound
|
||||||
|
{
|
||||||
|
typedef void (*BmswLogInit_t)(void *cb);
|
||||||
|
extern "C" void __cdecl on_log_msg(char level, const char *scope, const char *msg)
|
||||||
|
{
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case 'I':
|
||||||
|
log_info(scope, "{}", msg);
|
||||||
|
break;
|
||||||
|
case 'W':
|
||||||
|
log_warning(scope, "{}", msg);
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
log_fatal(scope, "{}", msg);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
default:
|
||||||
|
log_misc(scope, "{}", msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void attach(HINSTANCE hmodule)
|
||||||
|
{
|
||||||
|
BmswLogInit_t BmswLogInit = nullptr;
|
||||||
|
HMODULE bmsw;
|
||||||
|
if ((bmsw = libutils::try_library(MODULE_PATH / "bmsound-wine.dll")))
|
||||||
|
{
|
||||||
|
BmswLogInit = (BmswLogInit_t) GetProcAddress(bmsw, "BmswLogInit");
|
||||||
|
}
|
||||||
|
if (BmswLogInit) //_REM: keep 0.2.x backward compatibility until 0.3.0
|
||||||
|
{
|
||||||
|
BmswLogInit(reinterpret_cast<void *>(on_log_msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace hooks::wmisc::cmovieplayer
|
||||||
|
{
|
||||||
|
typedef void (*GetWmvChunk_t)(uint8_t *unk);
|
||||||
|
static GetWmvChunk_t GetWmvChunk_;
|
||||||
|
|
||||||
|
void on_get_wmv_chunk_(uint8_t *unk)
|
||||||
|
{
|
||||||
|
size_t chunksz = *(uint32_t *) (unk + 0x10);
|
||||||
|
void *readbuf = (void *) *(intptr_t *) (unk + 0x08);
|
||||||
|
int *readsz = (int *) (unk + 0x14);
|
||||||
|
|
||||||
|
//_REV: For now simply disable broken video stream
|
||||||
|
*readsz = 0;
|
||||||
|
}
|
||||||
|
void attach(HINSTANCE hmodule)
|
||||||
|
{
|
||||||
|
// Remove crashing movie
|
||||||
|
intptr_t TX_ThumExists = find_pattern_from(hmodule, "40534883ec20448b4110488bd9488b51088b09ff150000000089431485c0791d448bc0488d1500000000488d0d000000004883c4205b48ff25000000004883c4205bc3", "XXXXXXXXXXXXXXXXXXXXX????XXXXXXXXXXXXX????XXX????XXXXXXXX????XXXXXX", 0, 0, 0);
|
||||||
|
log_info("hooks::wmisc::cmovieplayer", "Hooking GetWmvChunk({})", reinterpret_cast<void *>(TX_ThumExists));
|
||||||
|
if (detour::trampoline_try(reinterpret_cast<void *>(TX_ThumExists), reinterpret_cast<void *>(on_get_wmv_chunk_), reinterpret_cast<void **>(&GetWmvChunk_)))
|
||||||
|
{
|
||||||
|
log_warning("hooks::wmisc::cmovieplayer", "Video playback for wmv won't work");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace hooks::wmisc::dmoeffector
|
||||||
|
{
|
||||||
|
typedef HRESULT (STDAPICALLTYPE *DllRegisterServer_t)();
|
||||||
|
|
||||||
|
HMODULE LoadLibraryRsrc(const char *rsrcname) {
|
||||||
|
// Unpack library blob
|
||||||
|
HRSRC hrsrc = FindResourceA(nullptr, rsrcname, RT_RCDATA);
|
||||||
|
void* rsrcdata = LockResource(LoadResource(nullptr, hrsrc));
|
||||||
|
DWORD rsrcsz = SizeofResource(nullptr, hrsrc);
|
||||||
|
|
||||||
|
// _REV: could use tmpfs instead if bmsound_wine provides tempfile wrapper in future
|
||||||
|
// Store as temporary file (no direct way to in-memory load without involving custom loaders like MemoryModule)
|
||||||
|
char tempPath[MAX_PATH];
|
||||||
|
char tempFile[MAX_PATH];
|
||||||
|
GetTempPathA(MAX_PATH, tempPath);
|
||||||
|
GetTempFileNameA(tempPath, rsrcname, 0, tempFile);
|
||||||
|
MoveFileExA(tempFile, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); // wine blocks DeleteFileA operations on LoadLibraryA filepaths
|
||||||
|
FILE *fh = fopen(tempFile, "wb");
|
||||||
|
fwrite(rsrcdata, rsrcsz, 1, fh);
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
// Map temporary library buffer
|
||||||
|
HMODULE hmodule = LoadLibraryA(tempFile);
|
||||||
|
return hmodule;
|
||||||
|
}
|
||||||
|
void attach(HINSTANCE hmodule)
|
||||||
|
{
|
||||||
|
HMODULE libdmo = LoadLibraryRsrc("DMO_BLOB");
|
||||||
|
if(libdmo)
|
||||||
|
{
|
||||||
|
log_info("hooks::wmisc::dmoeffector", "Registering COM server for DMO({})", reinterpret_cast<void *>(libdmo));
|
||||||
|
auto DllRegisterServer = (DllRegisterServer_t)GetProcAddress(libdmo, "DllRegisterServer");
|
||||||
|
if(DllRegisterServer && SUCCEEDED(DllRegisterServer())) return;
|
||||||
|
}
|
||||||
|
log_warning("hooks::wmisc::dmoeffector", "Loading embedded dsdmo.dll failed, error code: {}", GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace hooks::wmisc
|
||||||
|
{
|
||||||
|
static bool patchmodel_ = true;
|
||||||
|
void skip_patching_by_model(bool val)
|
||||||
|
{
|
||||||
|
patchmodel_ = !val;
|
||||||
|
}
|
||||||
|
void apply_performance_hacks(HINSTANCE hmodule, const char *model, const char *ext)
|
||||||
|
{
|
||||||
|
if (!patchmodel_ && strcmp(model, "FORCE") != 0) return;
|
||||||
|
|
||||||
|
log_info("hooks::wmisc", "Enabling performance patches for {}-{}", model, ext);
|
||||||
|
long extl = strtol(ext, nullptr, 10);
|
||||||
|
switch (to_hash(model))
|
||||||
|
{
|
||||||
|
case to_hash("LDJ"):
|
||||||
|
dmoeffector::attach(hmodule);
|
||||||
|
thumbnail::attach(hmodule);
|
||||||
|
msacm::attach(hmodule);
|
||||||
|
bmsound::attach(hmodule);
|
||||||
|
break;
|
||||||
|
case to_hash("M39"):
|
||||||
|
msacm::attach(hmodule);
|
||||||
|
bmsound::attach(hmodule);
|
||||||
|
break;
|
||||||
|
case to_hash("KFC"):
|
||||||
|
dmoeffector::attach(hmodule);
|
||||||
|
msacm::attach(hmodule);
|
||||||
|
bmsound::attach(hmodule);
|
||||||
|
if (extl > 2019020600 && extl < 2021011800) // SDVX5
|
||||||
|
{
|
||||||
|
cmovieplayer::attach(hmodule);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case to_hash("FORCE"):
|
||||||
|
switch (to_hash(ext))
|
||||||
|
{
|
||||||
|
case to_hash("thumbnail"):
|
||||||
|
thumbnail::attach(hmodule);
|
||||||
|
break;
|
||||||
|
case to_hash("msacm"):
|
||||||
|
msacm::attach(hmodule);
|
||||||
|
break;
|
||||||
|
case to_hash("bmsound"):
|
||||||
|
bmsound::attach(hmodule);
|
||||||
|
break;
|
||||||
|
case to_hash("cmovieplayer"):
|
||||||
|
cmovieplayer::attach(hmodule);
|
||||||
|
break;
|
||||||
|
case to_hash("dmoeffector"):
|
||||||
|
dmoeffector::attach(hmodule);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace hooks::wmisc
|
||||||
|
{
|
||||||
|
void skip_patching_by_model(bool val);
|
||||||
|
void apply_performance_hacks(HINSTANCE hmodule, const char *model, const char *ext);
|
||||||
|
}
|
||||||
@@ -71,6 +71,7 @@
|
|||||||
#include "games/mfg/mfg.h"
|
#include "games/mfg/mfg.h"
|
||||||
#include "games/pc/pc.h"
|
#include "games/pc/pc.h"
|
||||||
#include "games/museca/museca.h"
|
#include "games/museca/museca.h"
|
||||||
|
#include "hooks/develhook.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
#include "hooks/audio/asio_proxy.h"
|
#include "hooks/audio/asio_proxy.h"
|
||||||
@@ -84,6 +85,8 @@
|
|||||||
#include "hooks/networkhook.h"
|
#include "hooks/networkhook.h"
|
||||||
#include "hooks/icmphook_net.h"
|
#include "hooks/icmphook_net.h"
|
||||||
#include "hooks/unisintrhook.h"
|
#include "hooks/unisintrhook.h"
|
||||||
|
#include "hooks/sndbhook.h"
|
||||||
|
#include "hooks/wmischook.h"
|
||||||
#include "launcher/launcher.h"
|
#include "launcher/launcher.h"
|
||||||
#include "launcher/logger.h"
|
#include "launcher/logger.h"
|
||||||
#include "launcher/signal.h"
|
#include "launcher/signal.h"
|
||||||
@@ -144,7 +147,7 @@ std::string LOG_FILE_PATH = "";
|
|||||||
int LAUNCHER_ARGC = 0;
|
int LAUNCHER_ARGC = 0;
|
||||||
char **LAUNCHER_ARGV = nullptr;
|
char **LAUNCHER_ARGV = nullptr;
|
||||||
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
||||||
|
games::Game *GAME_INSTANCE = nullptr;
|
||||||
std::mutex CARD_OVERRIDES_LOCK;
|
std::mutex CARD_OVERRIDES_LOCK;
|
||||||
std::string CARD_OVERRIDES[2];
|
std::string CARD_OVERRIDES[2];
|
||||||
|
|
||||||
@@ -2386,6 +2389,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::core::HEAP_SIZE = 536870912; // 512MB
|
avs::core::HEAP_SIZE = 536870912; // 512MB
|
||||||
games.push_back(new games::pc::PCGame());
|
games.push_back(new games::pc::PCGame());
|
||||||
}
|
}
|
||||||
|
GAME_INSTANCE = games.back();
|
||||||
|
|
||||||
// apply user heap size, if defined
|
// apply user heap size, if defined
|
||||||
if (user_heap_size > 0) {
|
if (user_heap_size > 0) {
|
||||||
@@ -2535,11 +2539,18 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
// load game
|
// load game
|
||||||
avs::game::load_dll();
|
avs::game::load_dll();
|
||||||
|
|
||||||
|
// devel attach
|
||||||
|
hooks::devel::attach();
|
||||||
|
|
||||||
// attach games
|
// attach games
|
||||||
for (auto game : games) {
|
for (auto game : games) {
|
||||||
game->attach();
|
game->attach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wine fixes
|
||||||
|
hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, avs::game::MODEL, avs::game::EXT);
|
||||||
|
hooks::soundbank::init(avs::game::DLL_INSTANCE, avs::game::MODEL, avs::game::EXT);
|
||||||
|
|
||||||
#if SPICE64 && !SPICE_XP
|
#if SPICE64 && !SPICE_XP
|
||||||
if (!cfg::CONFIGURATOR_STANDALONE) {
|
if (!cfg::CONFIGURATOR_STANDALONE) {
|
||||||
if (games::iidx::TDJ_CAMERA) {
|
if (games::iidx::TDJ_CAMERA) {
|
||||||
@@ -2751,13 +2762,15 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
game->post_attach();
|
game->post_attach();
|
||||||
}
|
}
|
||||||
|
|
||||||
// game start
|
// cleanup procedure
|
||||||
log_info("launcher", "calling game entry");
|
launcher::on_shutdown = [&]() {
|
||||||
avs::game::entry_main();
|
|
||||||
|
|
||||||
// clear presence
|
// clear presence
|
||||||
richpresence::shutdown();
|
richpresence::shutdown();
|
||||||
|
|
||||||
|
// cleanup wine fixes
|
||||||
|
hooks::soundbank::deinit(avs::game::DLL_INSTANCE);
|
||||||
|
|
||||||
// detach games
|
// detach games
|
||||||
for (auto game : games) {
|
for (auto game : games) {
|
||||||
game->detach();
|
game->detach();
|
||||||
@@ -2846,6 +2859,14 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
#if SPICE64 && !SPICE_XP
|
#if SPICE64 && !SPICE_XP
|
||||||
games::iidx::camera_release();
|
games::iidx::camera_release();
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// devel start
|
||||||
|
hooks::devel::entry_main();
|
||||||
|
|
||||||
|
// game start
|
||||||
|
log_info("launcher", "calling game entry");
|
||||||
|
avs::game::entry_main();
|
||||||
|
|
||||||
// shutdown
|
// shutdown
|
||||||
log_warning("launcher", "end");
|
log_warning("launcher", "end");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include "cfg/option.h"
|
#include "cfg/option.h"
|
||||||
|
#include "games/game.h"
|
||||||
|
|
||||||
namespace rawinput {
|
namespace rawinput {
|
||||||
class RawInputManager;
|
class RawInputManager;
|
||||||
@@ -21,6 +22,7 @@ extern std::string LOG_FILE_PATH;
|
|||||||
extern int LAUNCHER_ARGC;
|
extern int LAUNCHER_ARGC;
|
||||||
extern char **LAUNCHER_ARGV;
|
extern char **LAUNCHER_ARGV;
|
||||||
extern std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
extern std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
||||||
|
extern games::Game *GAME_INSTANCE;
|
||||||
|
|
||||||
extern std::unique_ptr<api::Controller> API_CONTROLLER;
|
extern std::unique_ptr<api::Controller> API_CONTROLLER;
|
||||||
extern std::unique_ptr<rawinput::RawInputManager> RI_MGR;
|
extern std::unique_ptr<rawinput::RawInputManager> RI_MGR;
|
||||||
|
|||||||
@@ -2108,7 +2108,9 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.category = "Audio Conversion",
|
.category = "Audio Conversion",
|
||||||
.elements = {
|
.elements = {
|
||||||
{"asio", "ASIO"},
|
{"asio", "ASIO"},
|
||||||
{"waveout", "broken, do not use"}
|
{"waveout", "broken, do not use"},
|
||||||
|
{"pipewire", "Pipewire (Linux)"},
|
||||||
|
{"none", "None"}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
namespace launcher {
|
namespace launcher {
|
||||||
|
|
||||||
|
std::function<void()> on_shutdown = []() {};
|
||||||
|
|
||||||
void stop_subsystems() {
|
void stop_subsystems() {
|
||||||
// note that it is possible for stop_subsystems to be called multiple times
|
// note that it is possible for stop_subsystems to be called multiple times
|
||||||
// (e.g., crashing, and then closing the window)
|
// (e.g., crashing, and then closing the window)
|
||||||
@@ -37,9 +39,6 @@ namespace launcher {
|
|||||||
// before shutting down logger, dump any deferred log messages
|
// before shutting down logger, dump any deferred log messages
|
||||||
deferredlogs::dump_to_logger();
|
deferredlogs::dump_to_logger();
|
||||||
|
|
||||||
// flush/stop logger
|
|
||||||
logger::stop();
|
|
||||||
|
|
||||||
// stop ea server
|
// stop ea server
|
||||||
easrv_shutdown();
|
easrv_shutdown();
|
||||||
|
|
||||||
@@ -58,6 +57,14 @@ namespace launcher {
|
|||||||
|
|
||||||
// unload nvapi and free library (if loaded)
|
// unload nvapi and free library (if loaded)
|
||||||
nvapi::unload();
|
nvapi::unload();
|
||||||
|
|
||||||
|
// dynamic main cleanup _BUG: not thread safe, required?
|
||||||
|
on_shutdown();
|
||||||
|
on_shutdown = []() {};
|
||||||
|
|
||||||
|
// flush/stop logger
|
||||||
|
logger::stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kill(UINT exit_code) {
|
void kill(UINT exit_code) {
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace launcher {
|
namespace launcher {
|
||||||
|
extern std::function<void()> on_shutdown;
|
||||||
void stop_subsystems();
|
void stop_subsystems();
|
||||||
void kill(UINT exit_code = EXIT_FAILURE);
|
void kill(UINT exit_code = EXIT_FAILURE);
|
||||||
void shutdown(UINT exit_code = EXIT_SUCCESS);
|
void shutdown(UINT exit_code = EXIT_SUCCESS);
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// enable touch functions - set version to windows 7
|
||||||
|
// mingw otherwise doesn't load touch stuff
|
||||||
|
#define _WIN32_WINNT 0x0601
|
||||||
|
|
||||||
|
#include "wintouchemu.h"
|
||||||
|
|
||||||
|
#include "util/detour.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
|
||||||
|
#define TOUCH_SIMULATE_FAT_FINGERS 0
|
||||||
|
#define TOUCH_DEBUG_VERBOSE 0
|
||||||
|
|
||||||
|
#if TOUCH_DEBUG_VERBOSE
|
||||||
|
#define log_debug(module, format_str, ...) logger::push( \
|
||||||
|
LOG_FORMAT("M", module, format_str, ## __VA_ARGS__), logger::Style::GREY)
|
||||||
|
#else
|
||||||
|
#define log_debug(module, format_str, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nativetouchhook {
|
||||||
|
|
||||||
|
static decltype(GetTouchInputInfo) *GetTouchInputInfo_orig = nullptr;
|
||||||
|
|
||||||
|
static void strip_contact_size(PTOUCHINPUT point) {
|
||||||
|
|
||||||
|
#if TOUCH_SIMULATE_FAT_FINGERS
|
||||||
|
point->dwMask |= 0x004;
|
||||||
|
point->cxContact = 80 * 100;
|
||||||
|
point->cyContact = 60 * 100;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// most monitors do not set TOUCHEVENTFMASK_CONTACTAREA, but for
|
||||||
|
// monitors that do set it, IIDX can get very confused (SDVX is not
|
||||||
|
// affected)
|
||||||
|
//
|
||||||
|
// while the test menu and the touch "glow" seem to work properly,
|
||||||
|
// interacting with subscreen menu items or entering PIN becomes
|
||||||
|
// very unpredictable
|
||||||
|
//
|
||||||
|
// to fix this, simply remove the contact area width and height
|
||||||
|
//
|
||||||
|
// note: test menu > I/O > touch test gives 5 numbers:
|
||||||
|
// n: x, y, w, h
|
||||||
|
// where
|
||||||
|
// n is the nth touch input since boot
|
||||||
|
// x, y are coordinates (center of finger)
|
||||||
|
// w, h are contact width and height
|
||||||
|
//
|
||||||
|
// when TOUCHEVENTFMASK_CONTACTAREA is not set, w/h will
|
||||||
|
// automatically be seen as 1x1, which works perfectly fine
|
||||||
|
|
||||||
|
log_debug(
|
||||||
|
"touch::native",
|
||||||
|
"[{}, {}] dwMask = 0x{:x}, cxContact = {}, cyContact = {}",
|
||||||
|
point->x / 100,
|
||||||
|
point->y / 100,
|
||||||
|
point->dwMask,
|
||||||
|
point->cxContact,
|
||||||
|
point->cyContact);
|
||||||
|
|
||||||
|
point->dwMask &= ~(0x004ul); // clear TOUCHEVENTFMASK_CONTACTAREA
|
||||||
|
point->cxContact = 0;
|
||||||
|
point->cyContact = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL WINAPI GetTouchInputInfoHook(
|
||||||
|
HTOUCHINPUT hTouchInput, UINT cInputs, PTOUCHINPUT pInputs, int cbSize) {
|
||||||
|
|
||||||
|
// call the original fist
|
||||||
|
const auto result = GetTouchInputInfo_orig(hTouchInput, cInputs, pInputs, cbSize);
|
||||||
|
if (result == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cInputs; i++) {
|
||||||
|
PTOUCHINPUT point = &pInputs[i];
|
||||||
|
strip_contact_size(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hook(HMODULE module) {
|
||||||
|
GetTouchInputInfo_orig = detour::iat_try("GetTouchInputInfo", GetTouchInputInfoHook, module);
|
||||||
|
if (GetTouchInputInfo_orig != nullptr) {
|
||||||
|
log_misc("touch::native", "GetTouchInputInfo hooked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace nativetouchhook {
|
||||||
|
void hook(HMODULE module);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
|
|
||||||
|
#include "avs/game.h"
|
||||||
#include "hooks/graphics/graphics.h"
|
#include "hooks/graphics/graphics.h"
|
||||||
#include "overlay/overlay.h"
|
#include "overlay/overlay.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@@ -82,6 +83,25 @@ namespace nativetouch::transform {
|
|||||||
return overlay::OVERLAY->transform_touch_point(&position->x, &position->y);
|
return overlay::OVERLAY->transform_touch_point(&position->x, &position->y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the digitizer is mapped to the zero-based primary display, while SDVX
|
||||||
|
// still expects portrait coordinates when its image is rendered in landscape:
|
||||||
|
// (x, y) -> (width * (1 - y / height), height * x / width).
|
||||||
|
static bool transform_sdvx_landscape_touch_position(POINT *position) {
|
||||||
|
const auto landscape_width = static_cast<LONG>(GRAPHICS_FS_CUSTOM_RESOLUTION.has_value() ?
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION.value().first : GRAPHICS_FS_ORIGINAL_HEIGHT);
|
||||||
|
const auto landscape_height = static_cast<LONG>(GRAPHICS_FS_CUSTOM_RESOLUTION.has_value() ?
|
||||||
|
GRAPHICS_FS_CUSTOM_RESOLUTION.value().second : GRAPHICS_FS_ORIGINAL_WIDTH);
|
||||||
|
if (landscape_width <= 0 || landscape_height <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto input_x = position->x;
|
||||||
|
position->x = landscape_width -
|
||||||
|
MulDiv(position->y, landscape_width, landscape_height);
|
||||||
|
position->y = MulDiv(input_x, landscape_height, landscape_width);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// convert physical screen coordinates to game touch coordinates for a known target
|
// convert physical screen coordinates to game touch coordinates for a known target
|
||||||
bool screen_to_game(HWND window, POINT *position) {
|
bool screen_to_game(HWND window, POINT *position) {
|
||||||
if (settings::SYNTHETIC_TOUCH_USES_CLIENT_COORDINATES) {
|
if (settings::SYNTHETIC_TOUCH_USES_CLIENT_COORDINATES) {
|
||||||
@@ -127,6 +147,12 @@ namespace nativetouch::transform {
|
|||||||
return screen_to_game(window, position);
|
return screen_to_game(window, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exception: sdvx windowed subscreen does not use the subscreen overlay transform
|
||||||
|
if (GRAPHICS_WINDOWED && window == SDVX_SUBSCREEN_WINDOW) {
|
||||||
|
POINT client_position = *position;
|
||||||
|
return screen_to_game_client(window, &client_position);
|
||||||
|
}
|
||||||
|
|
||||||
// if this game has a subscreen overlay that can transform touch input
|
// if this game has a subscreen overlay that can transform touch input
|
||||||
// but the window is hidden or not under the cursor, reject mouse-as-touch
|
// but the window is hidden or not under the cursor, reject mouse-as-touch
|
||||||
// (e.g., iidx/sdvx are rejected here, but nostalgia is allowed)
|
// (e.g., iidx/sdvx are rejected here, but nostalgia is allowed)
|
||||||
@@ -144,6 +170,13 @@ namespace nativetouch::transform {
|
|||||||
const auto dedicated_subscreen = is_tdj_dedicated_subscreen(TDJ_SUBSCREEN_WINDOW);
|
const auto dedicated_subscreen = is_tdj_dedicated_subscreen(TDJ_SUBSCREEN_WINDOW);
|
||||||
const auto active_overlay = has_active_overlay_transform();
|
const auto active_overlay = has_active_overlay_transform();
|
||||||
|
|
||||||
|
// special case for SDVX landscape mode
|
||||||
|
if (!dedicated_subscreen && !active_overlay &&
|
||||||
|
GRAPHICS_FS_ORIENTATION_SWAP && avs::game::is_model("KFC")) {
|
||||||
|
return transform_sdvx_landscape_touch_position(position) ?
|
||||||
|
Result::Transformed : Result::Rejected;
|
||||||
|
}
|
||||||
|
|
||||||
// no dedicated subscreen or active overlay mapping; pass the point through unchanged
|
// no dedicated subscreen or active overlay mapping; pass the point through unchanged
|
||||||
if (!dedicated_subscreen && !active_overlay) {
|
if (!dedicated_subscreen && !active_overlay) {
|
||||||
return Result::Unchanged;
|
return Result::Unchanged;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
|
||||||
|
// set version to Windows 8 to enable Windows 8 touch functions
|
||||||
|
#define _WIN32_WINNT 0x0602
|
||||||
|
|
||||||
|
#include "touch_indicators.h"
|
||||||
|
#include "util/libutils.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
|
||||||
|
static HINSTANCE USER32_INSTANCE = nullptr;
|
||||||
|
typedef BOOL (WINAPI *SetWindowFeedbackSetting_t)(HWND, FEEDBACK_TYPE, DWORD, UINT32, const VOID *);
|
||||||
|
static SetWindowFeedbackSetting_t pSetWindowFeedbackSetting = nullptr;
|
||||||
|
|
||||||
|
void disable_touch_indicators(HWND hwnd) {
|
||||||
|
|
||||||
|
if (USER32_INSTANCE == nullptr) {
|
||||||
|
USER32_INSTANCE = libutils::load_library("user32.dll");
|
||||||
|
}
|
||||||
|
if (USER32_INSTANCE == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSetWindowFeedbackSetting == nullptr) {
|
||||||
|
pSetWindowFeedbackSetting = libutils::try_proc<SetWindowFeedbackSetting_t>(
|
||||||
|
USER32_INSTANCE, "SetWindowFeedbackSetting");
|
||||||
|
}
|
||||||
|
if (pSetWindowFeedbackSetting == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("touch_indicators", "disable visual feedback for touch events for HWND={}", fmt::ptr(hwnd));
|
||||||
|
|
||||||
|
BOOL enabled = FALSE;
|
||||||
|
pSetWindowFeedbackSetting(
|
||||||
|
hwnd,
|
||||||
|
FEEDBACK_TOUCH_CONTACTVISUALIZATION,
|
||||||
|
0, sizeof(enabled), &enabled);
|
||||||
|
pSetWindowFeedbackSetting(
|
||||||
|
hwnd,
|
||||||
|
FEEDBACK_TOUCH_TAP,
|
||||||
|
0, sizeof(enabled), &enabled);
|
||||||
|
pSetWindowFeedbackSetting(
|
||||||
|
hwnd,
|
||||||
|
FEEDBACK_TOUCH_DOUBLETAP,
|
||||||
|
0, sizeof(enabled), &enabled);
|
||||||
|
pSetWindowFeedbackSetting(
|
||||||
|
hwnd,
|
||||||
|
FEEDBACK_TOUCH_PRESSANDHOLD,
|
||||||
|
0, sizeof(enabled), &enabled);
|
||||||
|
pSetWindowFeedbackSetting(
|
||||||
|
hwnd,
|
||||||
|
FEEDBACK_TOUCH_RIGHTTAP,
|
||||||
|
0, sizeof(enabled), &enabled);
|
||||||
|
pSetWindowFeedbackSetting(
|
||||||
|
hwnd,
|
||||||
|
FEEDBACK_GESTURE_PRESSANDTAP,
|
||||||
|
0, sizeof(enabled), &enabled);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
void disable_touch_indicators(HWND hwnd);
|
||||||
+169
-134
@@ -9,187 +9,145 @@
|
|||||||
#include "util/memutils.h"
|
#include "util/memutils.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
|
|
||||||
intptr_t find_pattern(std::vector<uint8_t> &data, intptr_t base, const uint8_t *pattern,
|
intptr_t find_pattern(std::span<const unsigned char> data, intptr_t base, const uint8_t *pattern,
|
||||||
const char *mask, intptr_t offset, intptr_t usage)
|
const char *mask, intptr_t offset, intptr_t usage, bool reverse)
|
||||||
{
|
{
|
||||||
|
return find_pattern_from(data, base, pattern, mask, offset, usage, 0, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
// build pattern
|
intptr_t find_pattern(const std::vector<uint8_t> &data, intptr_t base, const uint8_t *pattern,
|
||||||
std::vector<std::pair<uint8_t, bool>> pattern_vector;
|
const char *mask, intptr_t offset, intptr_t usage, bool reverse)
|
||||||
size_t mask_size = strlen(mask);
|
{
|
||||||
for (size_t i = 0; i < mask_size; i++) {
|
return find_pattern_from(std::span<const unsigned char>(data), base, pattern, mask, offset, usage, 0, reverse);
|
||||||
pattern_vector.emplace_back(pattern[i], mask[i] == 'X');
|
|
||||||
}
|
|
||||||
|
|
||||||
// the scan loop
|
|
||||||
auto data_begin = data.begin();
|
|
||||||
auto cur_usage = 0;
|
|
||||||
while (true) {
|
|
||||||
|
|
||||||
// search for the pattern
|
|
||||||
auto search_result = std::search(data_begin, data.end(), pattern_vector.begin(), pattern_vector.end(),
|
|
||||||
[&](uint8_t c, std::pair<uint8_t, bool> pat) {
|
|
||||||
return (!pat.second) || c == pat.first;
|
|
||||||
});
|
|
||||||
|
|
||||||
// check for a match
|
|
||||||
if (search_result != data.end()) {
|
|
||||||
|
|
||||||
// return the result if we hit the usage count
|
|
||||||
if (cur_usage == usage) {
|
|
||||||
return (std::distance(data.begin(), search_result) + base) + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment the found count
|
|
||||||
++cur_usage;
|
|
||||||
data_begin = ++search_result;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t find_pattern(HMODULE module, const uint8_t *pattern, const char *mask,
|
intptr_t find_pattern(HMODULE module, const uint8_t *pattern, const char *mask,
|
||||||
intptr_t offset, intptr_t result_usage)
|
intptr_t offset, intptr_t result_usage, bool reverse)
|
||||||
{
|
{
|
||||||
// get module information
|
return find_pattern_from(module, pattern, mask, offset, result_usage, 0, reverse);
|
||||||
MODULEINFO module_info {};
|
|
||||||
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(module_info))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto size = static_cast<size_t>(module_info.SizeOfImage);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// copy data
|
|
||||||
std::vector<uint8_t> data(size);
|
|
||||||
memcpy(data.data(), module_info.lpBaseOfDll, size);
|
|
||||||
|
|
||||||
// find pattern
|
|
||||||
return find_pattern(
|
|
||||||
data,
|
|
||||||
reinterpret_cast<intptr_t>(module_info.lpBaseOfDll),
|
|
||||||
pattern,
|
|
||||||
mask,
|
|
||||||
offset,
|
|
||||||
result_usage);
|
|
||||||
} catch (const std::bad_alloc &e) {
|
|
||||||
log_warning("sigscan", "failed to allocate buffer of size {} for image data", size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t find_pattern(HMODULE module, const std::string &pattern, const char *mask,
|
intptr_t find_pattern(HMODULE module, const std::string &pattern, const char *mask,
|
||||||
intptr_t offset, intptr_t result_usage)
|
intptr_t offset, intptr_t result_usage, bool reverse)
|
||||||
{
|
{
|
||||||
std::string pattern_str(pattern);
|
return find_pattern_from(module, pattern, mask, offset, result_usage, 0, reverse);
|
||||||
auto pattern_bin = std::make_unique<uint8_t[]>(pattern.length() / 2);
|
|
||||||
if (!hex2bin(pattern_str.c_str(), pattern_bin.get())) {
|
|
||||||
log_warning("sigscan", "hex2bin failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return find_pattern(module, pattern_bin.get(), mask, offset, result_usage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
||||||
intptr_t find_pattern_from(std::vector<uint8_t> &data, intptr_t base, const uint8_t *pattern,
|
intptr_t find_pattern_from(std::span<const unsigned char> data, intptr_t base, const uint8_t *pattern,
|
||||||
const char *mask, intptr_t offset, intptr_t usage, intptr_t start_from)
|
const char *mask, intptr_t offset, intptr_t usage, intptr_t start_from, bool reverse)
|
||||||
{
|
{
|
||||||
|
|
||||||
// build pattern
|
// build pattern
|
||||||
std::vector<std::pair<uint8_t, bool>> pattern_vector;
|
std::vector<std::pair<uint8_t, bool>> pattern_vector;
|
||||||
size_t mask_size = strlen(mask);
|
size_t mask_size = strlen(mask);
|
||||||
for (size_t i = 0; i < mask_size; i++) {
|
for (size_t i = 0; i < mask_size; i++) {
|
||||||
pattern_vector.emplace_back(pattern[i], mask[i] == 'X');
|
pattern_vector.emplace_back(pattern[i], mask[i] == 'X');
|
||||||
}
|
}
|
||||||
|
if (reverse) std::reverse(pattern_vector.begin(), pattern_vector.end());
|
||||||
|
|
||||||
// the scan loop
|
// the scan loop
|
||||||
auto data_begin = data.begin();
|
auto on_search = [&](uint8_t c, std::pair<uint8_t, bool> pat)
|
||||||
std::advance(data_begin, start_from);
|
{
|
||||||
|
return (!pat.second) || c == pat.first;
|
||||||
|
};
|
||||||
auto cur_usage = 0;
|
auto cur_usage = 0;
|
||||||
while (true) {
|
if (!reverse)
|
||||||
|
{
|
||||||
|
auto data_begin = data.begin() + start_from;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// search for the pattern
|
||||||
|
auto search_result = std::search(data_begin, data.end(), pattern_vector.begin(), pattern_vector.end(), on_search);
|
||||||
|
|
||||||
// search for the pattern
|
// check for a match
|
||||||
auto search_result = std::search(data_begin, data.end(), pattern_vector.begin(), pattern_vector.end(),
|
if (search_result != data.end())
|
||||||
[&](uint8_t c, std::pair<uint8_t, bool> pat) {
|
{
|
||||||
return (!pat.second) || c == pat.first;
|
|
||||||
});
|
|
||||||
|
|
||||||
// check for a match
|
// return the result if we hit the usage count
|
||||||
if (search_result != data.end()) {
|
if (cur_usage == usage)
|
||||||
|
{
|
||||||
|
return (std::distance(data.begin(), search_result) + base) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
// return the result if we hit the usage count
|
// increment the found count
|
||||||
if (cur_usage == usage) {
|
++cur_usage;
|
||||||
return (std::distance(data.begin(), search_result) + base) + offset;
|
data_begin = ++search_result;
|
||||||
}
|
}
|
||||||
|
else break;
|
||||||
// increment the found count
|
|
||||||
++cur_usage;
|
|
||||||
data_begin = ++search_result;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto data_begin = std::make_reverse_iterator(start_from ? data.begin() + start_from + 1 : data.end());
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
// search for the pattern
|
||||||
|
auto search_result = std::search(data_begin, data.rend(), pattern_vector.begin(), pattern_vector.end(), on_search);
|
||||||
|
|
||||||
|
// check for a match
|
||||||
|
if (search_result != data.rend())
|
||||||
|
{
|
||||||
|
|
||||||
|
// return the result if we hit the usage count
|
||||||
|
if (cur_usage == usage)
|
||||||
|
{
|
||||||
|
return (std::distance(data.begin(), search_result.base()) - pattern_vector.size() + base) + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment the found count
|
||||||
|
++cur_usage;
|
||||||
|
data_begin = ++search_result;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t find_pattern_from(HMODULE module, const uint8_t *pattern, const char *mask,
|
intptr_t find_pattern_from(const std::vector<uint8_t> &data, intptr_t base, const uint8_t *pattern,
|
||||||
intptr_t offset, intptr_t result_usage, intptr_t start_from)
|
const char *mask, intptr_t offset, intptr_t usage, intptr_t start_from, bool reverse)
|
||||||
{
|
{
|
||||||
// get module information
|
return find_pattern_from(std::span<const unsigned char>(data), base, pattern, mask, offset, usage, start_from, reverse);
|
||||||
MODULEINFO module_info {};
|
}
|
||||||
if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(module_info))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto size = static_cast<size_t>(module_info.SizeOfImage);
|
intptr_t find_pattern_from(HMODULE module, const uint8_t *pattern, const char *mask,
|
||||||
|
intptr_t offset, intptr_t result_usage, intptr_t start_from, bool reverse)
|
||||||
try {
|
{
|
||||||
|
intptr_t base;
|
||||||
// copy data
|
auto data = get_module_data(module, &base);
|
||||||
std::vector<uint8_t> data(size);
|
return find_pattern_from(
|
||||||
memcpy(data.data(), module_info.lpBaseOfDll, size);
|
data,
|
||||||
|
base,
|
||||||
// find pattern
|
pattern,
|
||||||
return find_pattern_from(
|
mask,
|
||||||
data,
|
offset,
|
||||||
reinterpret_cast<intptr_t>(module_info.lpBaseOfDll),
|
result_usage,
|
||||||
pattern,
|
start_from,
|
||||||
mask,
|
reverse);
|
||||||
offset,
|
|
||||||
result_usage,
|
|
||||||
start_from);
|
|
||||||
} catch (const std::bad_alloc &e) {
|
|
||||||
log_warning("sigscan", "failed to allocate buffer of size {} for image data", size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t find_pattern_from(HMODULE module, const std::string &pattern, const char *mask,
|
intptr_t find_pattern_from(HMODULE module, const std::string &pattern, const char *mask,
|
||||||
intptr_t offset, intptr_t result_usage, intptr_t start_from)
|
intptr_t offset, intptr_t result_usage, intptr_t start_from, bool reverse)
|
||||||
{
|
{
|
||||||
std::string pattern_str(pattern);
|
|
||||||
auto pattern_bin = std::make_unique<uint8_t[]>(pattern.length() / 2);
|
auto pattern_bin = std::make_unique<uint8_t[]>(pattern.length() / 2);
|
||||||
if (!hex2bin(pattern_str.c_str(), pattern_bin.get())) {
|
if (!hex2bin(pattern.c_str(), pattern_bin.get())) {
|
||||||
log_warning("sigscan", "hex2bin failed");
|
log_warning("sigscan", "hex2bin failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return find_pattern_from(module, pattern_bin.get(), mask, offset, result_usage, start_from);
|
return find_pattern_from(module, pattern_bin.get(), mask, offset, result_usage, start_from, reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
intptr_t replace_pattern(HMODULE module, const uint8_t *pattern, const char *mask, intptr_t offset,
|
intptr_t replace_pattern_from(HMODULE module, const uint8_t *pattern, const char *mask, intptr_t offset,
|
||||||
intptr_t usage, const uint8_t *replace_data, const char *replace_mask)
|
intptr_t usage, intptr_t start_from, const uint8_t *replace_data, const char *replace_mask, bool reverse)
|
||||||
{
|
{
|
||||||
|
|
||||||
// find result
|
// find result
|
||||||
auto result = find_pattern(module, pattern, mask, offset, usage);
|
auto result = find_pattern_from(module, pattern, mask, offset, usage, start_from, reverse);
|
||||||
|
|
||||||
// check result
|
// check result
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -211,8 +169,8 @@ intptr_t replace_pattern(HMODULE module, const uint8_t *pattern, const char *mas
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t replace_pattern(HMODULE module, const std::string &signature,
|
intptr_t replace_pattern_from(HMODULE module, const std::string &signature,
|
||||||
const std::string &replacement, intptr_t offset, intptr_t usage)
|
const std::string &replacement, intptr_t offset, intptr_t usage, intptr_t start_from, bool reverse)
|
||||||
{
|
{
|
||||||
// build pattern
|
// build pattern
|
||||||
std::string pattern_str(signature);
|
std::string pattern_str(signature);
|
||||||
@@ -261,17 +219,31 @@ intptr_t replace_pattern(HMODULE module, const std::string &signature,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do the replacement
|
// do the replacement
|
||||||
return replace_pattern(
|
return replace_pattern_from(
|
||||||
module,
|
module,
|
||||||
pattern_bin.get(),
|
pattern_bin.get(),
|
||||||
signature_mask.c_str(),
|
signature_mask.c_str(),
|
||||||
offset,
|
offset,
|
||||||
usage,
|
usage,
|
||||||
|
start_from,
|
||||||
replace_data_bin.get(),
|
replace_data_bin.get(),
|
||||||
replace_mask.c_str()
|
replace_mask.c_str(),
|
||||||
|
reverse
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intptr_t replace_pattern(HMODULE module, const std::string &signature,
|
||||||
|
const std::string &replacement, intptr_t offset, intptr_t usage, bool reverse)
|
||||||
|
{
|
||||||
|
return replace_pattern_from(module, signature, replacement, offset, usage, 0, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
intptr_t replace_pattern(HMODULE module, const uint8_t *pattern, const char *mask, intptr_t offset,
|
||||||
|
intptr_t usage, const uint8_t *replace_data, const char *replace_mask, bool reverse)
|
||||||
|
{
|
||||||
|
return replace_pattern_from(module, pattern, mask, offset, usage, 0, replace_data, replace_mask, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_date_stamp, uint32_t* address_of_entry_point) {
|
bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_date_stamp, uint32_t* address_of_entry_point) {
|
||||||
std::ifstream file(dll_path, std::ios::binary);
|
std::ifstream file(dll_path, std::ios::binary);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@@ -304,3 +276,66 @@ bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_dat
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intptr_t find_asm_leacstr_from(HMODULE module, reg_t reg, const char *cstr)
|
||||||
|
{
|
||||||
|
// get module information
|
||||||
|
intptr_t base;
|
||||||
|
auto data = get_module_data(module, &base);
|
||||||
|
const unsigned char *modbegp = data.data();
|
||||||
|
const unsigned char *modendp = data.data() + data.size();
|
||||||
|
|
||||||
|
// search cstr
|
||||||
|
const unsigned char *cstr_addr = std::search(
|
||||||
|
modbegp,
|
||||||
|
modendp,
|
||||||
|
reinterpret_cast<const unsigned char *>(cstr),
|
||||||
|
reinterpret_cast<const unsigned char *>(cstr) + strlen(cstr)
|
||||||
|
);
|
||||||
|
if (cstr_addr == modendp)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__i386__)
|
||||||
|
// find LEA REG, [abs32]
|
||||||
|
if (reg.t != GPR_32) return 0;
|
||||||
|
unsigned char asmop[6] = { 0x8D, reg.v, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
int32_t dist32 = reinterpret_cast<int32_t>(cstr_addr);
|
||||||
|
memcpy(asmop + (sizeof(asmop) - 4), &dist32, 4);
|
||||||
|
return reinterpret_cast<intptr_t>(std::search(
|
||||||
|
modbegp,
|
||||||
|
modendp,
|
||||||
|
asmop,
|
||||||
|
asmop + sizeof(asmop)
|
||||||
|
)) % reinterpret_cast<intptr_t>(modendp);
|
||||||
|
#elif defined(__x86_64__)
|
||||||
|
// find LEA REG, [RIP + rel32]
|
||||||
|
unsigned char rex = reg.t == GPR_EXT ? 0x4C : 0x48;
|
||||||
|
unsigned char asmop[7] = {rex, 0x8D, reg.v, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
for (const unsigned char *addr = modbegp; addr < modendp - sizeof(asmop); addr++)
|
||||||
|
{
|
||||||
|
auto dist32 = static_cast<int32_t>(reinterpret_cast<intptr_t>(cstr_addr) - reinterpret_cast<intptr_t>(addr + sizeof(asmop)));
|
||||||
|
memcpy(asmop + (sizeof(asmop) - 4), &dist32, 4);
|
||||||
|
if (memcmp(addr, asmop, sizeof(asmop)) == 0) return reinterpret_cast<intptr_t>(addr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::span<const unsigned char> get_module_data(HMODULE module, intptr_t *base)
|
||||||
|
{
|
||||||
|
// get module information
|
||||||
|
size_t sz = 0;
|
||||||
|
MODULEINFO module_info {};
|
||||||
|
if (GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(module_info))) {
|
||||||
|
sz = static_cast<size_t>(module_info.SizeOfImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap data
|
||||||
|
std::span<const unsigned char> data(static_cast<const unsigned char*>(module_info.lpBaseOfDll), sz);
|
||||||
|
*base = reinterpret_cast<intptr_t>(module_info.lpBaseOfDll);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|||||||
+119
-10
@@ -5,39 +5,63 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <span>
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#include "psapi.h"
|
#include "psapi.h"
|
||||||
|
|
||||||
intptr_t find_pattern(
|
intptr_t find_pattern(
|
||||||
std::vector<unsigned char> &data,
|
std::span<const unsigned char> data,
|
||||||
intptr_t base,
|
intptr_t base,
|
||||||
const unsigned char *pattern,
|
const unsigned char *pattern,
|
||||||
const char *mask,
|
const char *mask,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t usage);
|
intptr_t usage,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
|
intptr_t find_pattern(
|
||||||
|
const std::vector<unsigned char> &data,
|
||||||
|
intptr_t base,
|
||||||
|
const unsigned char *pattern,
|
||||||
|
const char *mask,
|
||||||
|
intptr_t offset,
|
||||||
|
intptr_t usage,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t find_pattern(
|
intptr_t find_pattern(
|
||||||
HMODULE module,
|
HMODULE module,
|
||||||
const unsigned char *pattern,
|
const unsigned char *pattern,
|
||||||
const char *mask,
|
const char *mask,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t usage);
|
intptr_t usage,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t find_pattern(
|
intptr_t find_pattern(
|
||||||
HMODULE module,
|
HMODULE module,
|
||||||
const std::string &pattern,
|
const std::string &pattern,
|
||||||
const char *mask,
|
const char *mask,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t result_usage);
|
intptr_t result_usage,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t find_pattern_from(
|
intptr_t find_pattern_from(
|
||||||
std::vector<unsigned char> &data,
|
std::span<const unsigned char> data,
|
||||||
intptr_t base,
|
intptr_t base,
|
||||||
const unsigned char *pattern,
|
const unsigned char *pattern,
|
||||||
const char *mask,
|
const char *mask,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t usage,
|
intptr_t usage,
|
||||||
intptr_t start_from);
|
intptr_t start_from,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
|
intptr_t find_pattern_from(
|
||||||
|
const std::vector<unsigned char> &data,
|
||||||
|
intptr_t base,
|
||||||
|
const unsigned char *pattern,
|
||||||
|
const char *mask,
|
||||||
|
intptr_t offset,
|
||||||
|
intptr_t usage,
|
||||||
|
intptr_t start_from,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t find_pattern_from(
|
intptr_t find_pattern_from(
|
||||||
HMODULE module,
|
HMODULE module,
|
||||||
@@ -45,7 +69,8 @@ intptr_t find_pattern_from(
|
|||||||
const char *mask,
|
const char *mask,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t usage,
|
intptr_t usage,
|
||||||
intptr_t start_from);
|
intptr_t start_from,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t find_pattern_from(
|
intptr_t find_pattern_from(
|
||||||
HMODULE module,
|
HMODULE module,
|
||||||
@@ -53,7 +78,8 @@ intptr_t find_pattern_from(
|
|||||||
const char *mask,
|
const char *mask,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t result_usage,
|
intptr_t result_usage,
|
||||||
intptr_t start_from);
|
intptr_t start_from,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t replace_pattern(
|
intptr_t replace_pattern(
|
||||||
HMODULE module,
|
HMODULE module,
|
||||||
@@ -62,13 +88,96 @@ intptr_t replace_pattern(
|
|||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t usage,
|
intptr_t usage,
|
||||||
const unsigned char *replace_data,
|
const unsigned char *replace_data,
|
||||||
const char *replace_mask);
|
const char *replace_mask,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
intptr_t replace_pattern(
|
intptr_t replace_pattern(
|
||||||
HMODULE module,
|
HMODULE module,
|
||||||
const std::string &signature,
|
const std::string &signature,
|
||||||
const std::string &replacement,
|
const std::string &replacement,
|
||||||
intptr_t offset,
|
intptr_t offset,
|
||||||
intptr_t usage);
|
intptr_t usage,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
|
intptr_t replace_pattern_from(
|
||||||
|
HMODULE module,
|
||||||
|
const unsigned char *pattern,
|
||||||
|
const char *mask,
|
||||||
|
intptr_t offset,
|
||||||
|
intptr_t usage,
|
||||||
|
intptr_t start_from,
|
||||||
|
const unsigned char *replace_data,
|
||||||
|
const char *replace_mask,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
|
intptr_t replace_pattern_from(
|
||||||
|
HMODULE module,
|
||||||
|
const std::string &signature,
|
||||||
|
const std::string &replacement,
|
||||||
|
intptr_t offset,
|
||||||
|
intptr_t usage,
|
||||||
|
intptr_t start_from,
|
||||||
|
bool reverse = false);
|
||||||
|
|
||||||
bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_date_stamp, uint32_t* address_of_entry_point);
|
bool get_pe_identifier(const std::filesystem::path& dll_path, uint32_t* time_date_stamp, uint32_t* address_of_entry_point);
|
||||||
|
|
||||||
|
union reg_t{
|
||||||
|
struct{
|
||||||
|
unsigned char t;
|
||||||
|
unsigned char v;
|
||||||
|
};
|
||||||
|
unsigned short s;
|
||||||
|
constexpr reg_t(unsigned char t, unsigned char v) : s(v << 8 | t) {}
|
||||||
|
constexpr reg_t(unsigned short s) : s(s) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum REGTYPE : unsigned char
|
||||||
|
{
|
||||||
|
GPR_32,
|
||||||
|
GPR_64,
|
||||||
|
GPR_EXT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum REG : unsigned short
|
||||||
|
{
|
||||||
|
EAX = reg_t(GPR_32, 0x05).s,
|
||||||
|
ECX = reg_t(GPR_32, 0x0D).s,
|
||||||
|
EDX = reg_t(GPR_32, 0x15).s,
|
||||||
|
EBX = reg_t(GPR_32, 0x1D).s,
|
||||||
|
ESP = reg_t(GPR_32, 0x25).s,
|
||||||
|
EBP = reg_t(GPR_32, 0x2D).s,
|
||||||
|
ESI = reg_t(GPR_32, 0x35).s,
|
||||||
|
EDI = reg_t(GPR_32, 0x3D).s,
|
||||||
|
RAX = reg_t(GPR_64, 0x05).s,
|
||||||
|
RCX = reg_t(GPR_64, 0x0D).s,
|
||||||
|
RDX = reg_t(GPR_64, 0x15).s,
|
||||||
|
RBX = reg_t(GPR_64, 0x1D).s,
|
||||||
|
RSP = reg_t(GPR_64, 0x25).s,
|
||||||
|
RBP = reg_t(GPR_64, 0x2D).s,
|
||||||
|
RSI = reg_t(GPR_64, 0x35).s,
|
||||||
|
RDI = reg_t(GPR_64, 0x3D).s,
|
||||||
|
R8 = reg_t(GPR_EXT, 0x05).s,
|
||||||
|
R9 = reg_t(GPR_EXT, 0x0D).s,
|
||||||
|
R10 = reg_t(GPR_EXT, 0x15).s,
|
||||||
|
R11 = reg_t(GPR_EXT, 0x1D).s,
|
||||||
|
R12 = reg_t(GPR_EXT, 0x25).s,
|
||||||
|
R13 = reg_t(GPR_EXT, 0x2D).s,
|
||||||
|
R14 = reg_t(GPR_EXT, 0x35).s,
|
||||||
|
R15 = reg_t(GPR_EXT, 0x3D).s
|
||||||
|
};
|
||||||
|
|
||||||
|
intptr_t find_asm_leacstr_from(
|
||||||
|
HMODULE module,
|
||||||
|
reg_t reg,
|
||||||
|
const char *cstr);
|
||||||
|
|
||||||
|
std::span<const unsigned char> get_module_data(HMODULE hmodule, intptr_t *base);
|
||||||
|
|
||||||
|
template <typename... Funcs>
|
||||||
|
intptr_t patch_pipeline(HMODULE module, Funcs&&... cbs) {
|
||||||
|
intptr_t base;
|
||||||
|
if(!get_module_data(module, &base).size()) return 0;
|
||||||
|
intptr_t addr = base; //_REV: needs implementing module updating logic in case of traversing between libraries
|
||||||
|
((addr && (addr = std::forward<Funcs>(cbs)(module, addr - base))), ...); // stop on first mismatch
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
@@ -28,6 +28,11 @@ static const char HEX_LOOKUP_UPPERCASE[16] = {
|
|||||||
|
|
||||||
const char *inet_ntop(short af, const void *src, char *dst, DWORD size);
|
const char *inet_ntop(short af, const void *src, char *dst, DWORD size);
|
||||||
|
|
||||||
|
static inline constexpr unsigned int to_hash(const char *str, int h = 0)
|
||||||
|
{
|
||||||
|
return !str[h] ? 5381 : (to_hash(str, h + 1) * 33) ^ str[h];
|
||||||
|
}
|
||||||
|
|
||||||
// make a window's native title bar follow the Windows dark/light app theme.
|
// make a window's native title bar follow the Windows dark/light app theme.
|
||||||
// pass force_dark=true to always use the dark caption regardless of the system theme.
|
// pass force_dark=true to always use the dark caption regardless of the system theme.
|
||||||
void set_window_dark_titlebar(HWND hWnd, bool force_dark = false);
|
void set_window_dark_titlebar(HWND hWnd, bool force_dark = false);
|
||||||
|
|||||||
Reference in New Issue
Block a user