From 6013ac18231e9ad0a14ed98ad75369519661808d Mon Sep 17 00:00:00 2001 From: oltolm Date: Sat, 30 Aug 2025 13:01:52 +0200 Subject: [PATCH 1/8] refactor: Fix trivial compiler warnings (#1675) --- .../HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp | 4 ++-- src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.cpp | 2 +- src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp | 2 -- src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp | 4 ++-- src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp | 4 ++-- src/util/ChunkedHeap/ChunkedHeap.h | 2 +- 6 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp b/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp index 583d5905..fc037537 100644 --- a/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp @@ -276,7 +276,7 @@ void IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext) for(auto& seg : ppcImlGenContext->segmentList2) { raLivenessRange* cur; - while(cur = seg->raInfo.linkedList_allSubranges) + while ((cur = seg->raInfo.linkedList_allSubranges)) IMLRA_DeleteRange(ppcImlGenContext, cur); seg->raInfo.linkedList_allSubranges = nullptr; seg->raInfo.linkedList_perVirtualRegister.clear(); @@ -632,4 +632,4 @@ sint32 IMLRA_CalculateAdditionalCostAfterSplit(raLivenessRange* subrange, raInst cost = newCost - baseCost; return cost; -} \ No newline at end of file +} diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.cpp index 74547a03..64cbbb6b 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.cpp @@ -80,7 +80,7 @@ private: D3DKMT_OPENADAPTERFROMHDC OpenAdapterData; - *phAdapter = NULL; + *phAdapter = 0; *pOutput = 0; HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp index ba657ff7..8f7a7e03 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp @@ -1,5 +1,3 @@ -#pragma once - #include "nn_olv_InitializeTypes.h" #include "CafeSystem.h" #include "Cafe/OS/libs/nn_act/nn_act.h" diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp index 21952ceb..a2ab461f 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp @@ -38,12 +38,12 @@ namespace nn if (!pParam->communityId) return OLV_RESULT_INVALID_PARAMETER; - snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%lu.delete", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); + snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%u.delete", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); } else { if (pParam->communityId) - snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%lu", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); + snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%u", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); else snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities", g_DiscoveryResults.apiEndpoint); } diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp index 912e7a11..f3878188 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp @@ -36,9 +36,9 @@ namespace nn char requestUrl[512]; if (pParam->flags & UploadFavoriteToCommunityDataParam::FLAG_DELETION) - snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%lu.unfavorite", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); + snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%u.unfavorite", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); else - snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%lu.favorite", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); + snprintf(requestUrl, sizeof(requestUrl), "%s/v1/communities/%u.favorite", g_DiscoveryResults.apiEndpoint, pParam->communityId.value()); CurlRequestHelper req; req.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE); diff --git a/src/util/ChunkedHeap/ChunkedHeap.h b/src/util/ChunkedHeap/ChunkedHeap.h index 21a1b868..88a0bdfd 100644 --- a/src/util/ChunkedHeap/ChunkedHeap.h +++ b/src/util/ChunkedHeap/ChunkedHeap.h @@ -283,7 +283,7 @@ private: { if (itr.chunkIndex != dbgRange.chunkIndex) continue; - if (itr.offset < (dbgRange.offset + dbgRange.size) && (itr.offset + itr.size) >(dbgRange.offset)) + if (itr.offset < (dbgRange.offset + dbgRange.size) && (itr.offset + itr.size) > dbgRange.offset) cemu_assert_error(); } From 9267e72ef92fb30af35cc0e6c9b2afbc3dd703c7 Mon Sep 17 00:00:00 2001 From: oltolm Date: Sat, 30 Aug 2025 20:39:48 +0200 Subject: [PATCH 2/8] refactor: Fix pugixml deprecation warnings (#1677) --- .../libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp | 6 +++--- .../OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp | 12 ++++++------ .../OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp index 6e7632e9..f9da4d4f 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp @@ -87,7 +87,7 @@ namespace nn if (httpCode != 200) return OLV_RESULT_STATUS(httpCode + 4000); - std::string request_name = doc.select_single_node("//request_name").node().child_value(); + std::string request_name = doc.select_node("//request_name").node().child_value(); if (request_name.size() == 0) { cemuLog_log(LogType::Force, "Community download response doesn't contain "); @@ -100,7 +100,7 @@ namespace nn return OLV_RESULT_INVALID_XML; } - pugi::xml_node communities = doc.select_single_node("//communities").node(); + pugi::xml_node communities = doc.select_node("//communities").node(); if (!communities) { cemuLog_log(LogType::Force, "Community download response doesn't contain "); @@ -231,4 +231,4 @@ namespace nn return res; } } -} \ No newline at end of file +} diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp index a2ab461f..3277c9db 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp @@ -223,12 +223,12 @@ namespace nn if (pOutData) { - std::string_view app_data = doc.select_single_node("//app_data").node().child_value(); - std::string_view community_id = doc.select_single_node("//community_id").node().child_value(); - std::string_view name = doc.select_single_node("//name").node().child_value(); - std::string_view description = doc.select_single_node("//description").node().child_value(); - std::string_view pid = doc.select_single_node("//pid").node().child_value(); - std::string_view icon = doc.select_single_node("//icon").node().child_value(); + std::string_view app_data = doc.select_node("//app_data").node().child_value(); + std::string_view community_id = doc.select_node("//community_id").node().child_value(); + std::string_view name = doc.select_node("//name").node().child_value(); + std::string_view description = doc.select_node("//description").node().child_value(); + std::string_view pid = doc.select_node("//pid").node().child_value(); + std::string_view icon = doc.select_node("//icon").node().child_value(); if (app_data.size() != 0) { diff --git a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp index f3878188..4b5fbbf1 100644 --- a/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp +++ b/src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp @@ -88,12 +88,12 @@ namespace nn if (pOutData) { - std::string_view app_data = doc.select_single_node("//app_data").node().child_value(); - std::string_view community_id = doc.select_single_node("//community_id").node().child_value(); - std::string_view name = doc.select_single_node("//name").node().child_value(); - std::string_view description = doc.select_single_node("//description").node().child_value(); - std::string_view pid = doc.select_single_node("//pid").node().child_value(); - std::string_view icon = doc.select_single_node("//icon").node().child_value(); + std::string_view app_data = doc.select_node("//app_data").node().child_value(); + std::string_view community_id = doc.select_node("//community_id").node().child_value(); + std::string_view name = doc.select_node("//name").node().child_value(); + std::string_view description = doc.select_node("//description").node().child_value(); + std::string_view pid = doc.select_node("//pid").node().child_value(); + std::string_view icon = doc.select_node("//icon").node().child_value(); if (app_data.size() != 0) { @@ -169,4 +169,4 @@ namespace nn return OLV_RESULT_SUCCESS; } } -} \ No newline at end of file +} From 5a3809be16f2e196ee8bc117b6e6759d83313506 Mon Sep 17 00:00:00 2001 From: RedBlackAka <140876408+RedBlackAka@users.noreply.github.com> Date: Fri, 5 Sep 2025 12:40:51 +0200 Subject: [PATCH 3/8] windows: Add NSIS Windows installer (#1645) License, user-install only and cleanups, mention in README --- .github/workflows/build.yml | 38 ++++-- .github/workflows/deploy_release.yml | 10 +- README.md | 2 +- src/resource/installer.nsi | 172 +++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 15 deletions(-) create mode 100644 src/resource/installer.nsi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e798c1a7..145256ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,14 +67,14 @@ jobs: - name: "cmake" run: | cmake -S . -B build ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja - + - name: "Build Cemu" run: | cmake --build build - + - name: Prepare artifact run: mv bin/Cemu_release bin/Cemu - + - name: Upload artifact uses: actions/upload-artifact@v4 with: @@ -138,7 +138,7 @@ jobs: - name: "Bootstrap vcpkg" run: | ./dependencies/vcpkg/bootstrap-vcpkg.bat - + - name: 'Setup NuGet Credentials for vcpkg' shell: 'bash' run: | @@ -152,7 +152,7 @@ jobs: `./dependencies/vcpkg/vcpkg.exe fetch nuget | tail -n 1` \ setapikey "${{ secrets.GITHUB_TOKEN }}" \ -source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" - + - name: "cmake" run: | mkdir -p build @@ -160,7 +160,7 @@ jobs: echo "[INFO] BUILD_FLAGS: ${{ env.BUILD_FLAGS }}" echo "[INFO] BUILD_MODE: ${{ env.BUILD_MODE }}" cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DVCPKG_INSTALL_OPTIONS="--clean-after-build" - + - name: "Build Cemu" run: | cd build @@ -168,13 +168,25 @@ jobs: - name: Prepare artifact run: Rename-Item bin/Cemu_release.exe Cemu.exe - + + - name: Build NSIS Installer + shell: cmd + run: | + cd src\resource + makensis /DPRODUCT_VERSION=${{ inputs.next_version_major }}.${{ inputs.next_version_minor }} installer.nsi + - name: Upload artifact uses: actions/upload-artifact@v4 with: name: cemu-bin-windows-x64 path: ./bin/Cemu.exe + - name: Upload NSIS Installer + uses: actions/upload-artifact@v4 + with: + name: cemu-installer-windows-x64 + path: ./src/resource/cemu-${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}-windows-x64-installer.exe + build-macos: runs-on: macos-14 strategy: @@ -185,7 +197,7 @@ jobs: uses: actions/checkout@v4 with: submodules: "recursive" - + - name: Setup release mode parameters run: | echo "BUILD_MODE=release" >> $GITHUB_ENV @@ -197,7 +209,7 @@ jobs: run: | echo "[INFO] Version ${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}" echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEMULATOR_VERSION_MAJOR=${{ inputs.next_version_major }} -DEMULATOR_VERSION_MINOR=${{ inputs.next_version_minor }}" >> $GITHUB_ENV - + - name: "Install system dependencies" run: | brew update @@ -218,7 +230,7 @@ jobs: - name: "Bootstrap vcpkg" run: | bash ./dependencies/vcpkg/bootstrap-vcpkg.sh - + - name: 'Setup NuGet Credentials for vcpkg' shell: 'bash' run: | @@ -232,7 +244,7 @@ jobs: mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \ setapikey "${{ secrets.GITHUB_TOKEN }}" \ -source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" - + - name: "cmake" run: | mkdir build @@ -242,7 +254,7 @@ jobs: -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} \ -DMACOS_BUNDLE=ON \ -G Ninja - + - name: "Build Cemu" run: | cmake --build build @@ -258,7 +270,7 @@ jobs: hdiutil create ./bin/tmp.dmg -ov -volname "Cemu" -fs HFS+ -srcfolder "./bin/Cemu_app" hdiutil convert ./bin/tmp.dmg -format UDZO -o bin/Cemu.dmg rm bin/tmp.dmg - + - name: Upload artifact uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/deploy_release.yml b/.github/workflows/deploy_release.yml index df8e186d..dfcce040 100644 --- a/.github/workflows/deploy_release.yml +++ b/.github/workflows/deploy_release.yml @@ -93,6 +93,11 @@ jobs: name: cemu-bin-windows-x64 path: cemu-bin-windows-x64 + - uses: actions/download-artifact@v4 + with: + name: cemu-installer-windows-x64 + path: cemu-installer-windows-x64 + - uses: actions/download-artifact@v4 with: pattern: cemu-bin-macos* @@ -102,7 +107,7 @@ jobs: run: | mkdir upload sudo apt install zip - + - name: Set version dependent vars run: | echo "Version: ${{ needs.calculate-version.outputs.next_version }}" @@ -120,6 +125,9 @@ jobs: zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }} rm -r ./${{ env.CEMU_FOLDER_NAME }} + - name: Create release from windows-installer + run: cp cemu-installer-windows-x64/cemu-${{ env.CEMU_VERSION }}-windows-x64-installer.exe upload/cemu-${{ env.CEMU_VERSION }}-windows-x64-installer.exe + - name: Create appimage run: | VERSION=${{ env.CEMU_VERSION }} diff --git a/README.md b/README.md index dfd35791..82af322c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Cemu is currently only available for 64-bit Windows, Linux & macOS devices. You can download the latest Cemu releases for Windows, Linux and Mac from the [GitHub Releases](https://github.com/cemu-project/Cemu/releases/). For Linux you can also find Cemu on [flathub](https://flathub.org/apps/info.cemu.Cemu). -On Windows Cemu is currently only available in a portable format so no installation is required besides extracting it in a safe place. +On Windows, Cemu is available both as an installer and in a portable format, where no installation is required besides extracting it in a safe place. The native macOS build is currently purely experimental and should not be considered stable or ready for issue-free gameplay. There are also known issues with degraded performance due to the use of MoltenVK and Rosetta for ARM Macs. We appreciate your patience while we improve Cemu for macOS. diff --git a/src/resource/installer.nsi b/src/resource/installer.nsi new file mode 100644 index 00000000..9d35c738 --- /dev/null +++ b/src/resource/installer.nsi @@ -0,0 +1,172 @@ +; Copyright Dolphin Emulator Project / Azahar Emulator Project / Team Cemu +; Licensed under MPL 2.0 with permission from authors + +; Usage: +; get the latest nsis: https://nsis.sourceforge.io/Download +; probably also want vscode extension: https://marketplace.visualstudio.com/items?itemName=idleberg.nsis + +; Require /DPRODUCT_VERSION for makensis. +!ifndef PRODUCT_VERSION + !error "PRODUCT_VERSION must be defined" +!endif + +ManifestDPIAware true + +!define PRODUCT_NAME "Cemu" +!define PRODUCT_PUBLISHER "Team Cemu" +!define PRODUCT_WEB_SITE "https://cemu.info/" +!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe" +!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" + +!define BINARY_SOURCE_DIR "..\..\bin" + +Name "${PRODUCT_NAME}" +OutFile "cemu-${PRODUCT_VERSION}-windows-x64-installer.exe" +SetCompressor /SOLID lzma +InstallDir "$LOCALAPPDATA\Cemu" +ShowInstDetails show +ShowUnInstDetails show + +!include "MUI2.nsh" +; Custom page plugin +!include "nsDialogs.nsh" + +; MUI Settings +!define MUI_ICON "logo_icon.ico" +!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" + +; License page +!insertmacro MUI_PAGE_LICENSE "..\..\LICENSE.txt" +; Desktop Shortcut page +Page custom desktopShortcutPageCreate desktopShortcutPageLeave +; Directory page +!insertmacro MUI_PAGE_DIRECTORY +; Instfiles page +!insertmacro MUI_PAGE_INSTFILES +; Finish page +!define MUI_FINISHPAGE_RUN "$INSTDIR\Cemu.exe" +!insertmacro MUI_PAGE_FINISH + +; Uninstaller pages +!insertmacro MUI_UNPAGE_INSTFILES + +; Variables +Var DesktopShortcutPageDialog +Var DesktopShortcutCheckbox +Var DesktopShortcut + +; Language files +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_LANGUAGE "SimpChinese" +!insertmacro MUI_LANGUAGE "TradChinese" +!insertmacro MUI_LANGUAGE "Danish" +!insertmacro MUI_LANGUAGE "Dutch" +!insertmacro MUI_LANGUAGE "French" +!insertmacro MUI_LANGUAGE "German" +!insertmacro MUI_LANGUAGE "Hungarian" +!insertmacro MUI_LANGUAGE "Italian" +!insertmacro MUI_LANGUAGE "Japanese" +!insertmacro MUI_LANGUAGE "Korean" +!insertmacro MUI_LANGUAGE "Lithuanian" +!insertmacro MUI_LANGUAGE "Norwegian" +!insertmacro MUI_LANGUAGE "Polish" +!insertmacro MUI_LANGUAGE "PortugueseBR" +!insertmacro MUI_LANGUAGE "Romanian" +!insertmacro MUI_LANGUAGE "Russian" +!insertmacro MUI_LANGUAGE "Spanish" +!insertmacro MUI_LANGUAGE "Swedish" +!insertmacro MUI_LANGUAGE "Turkish" +!insertmacro MUI_LANGUAGE "Vietnamese" + +; MUI end ------ + +Function .onInit + StrCpy $DesktopShortcut 1 + + !insertmacro MUI_LANGDLL_DISPLAY +FunctionEnd + +Function desktopShortcutPageCreate + !insertmacro MUI_HEADER_TEXT "Create Desktop Shortcut" "Would you like to create a desktop shortcut?" + nsDialogs::Create 1018 + Pop $DesktopShortcutPageDialog + ${If} $DesktopShortcutPageDialog == error + Abort + ${EndIf} + + ${NSD_CreateCheckbox} 0u 0u 100% 12u "Create a desktop shortcut" + Pop $DesktopShortcutCheckbox + ${NSD_SetState} $DesktopShortcutCheckbox $DesktopShortcut + + nsDialogs::Show +FunctionEnd + +Function desktopShortcutPageLeave + ${NSD_GetState} $DesktopShortcutCheckbox $DesktopShortcut +FunctionEnd + +Section "Base" + ExecWait '"$INSTDIR\uninst.exe" /S _?=$INSTDIR' + + SectionIn RO + + SetOutPath "$INSTDIR" + + ; The binplaced build output will be included verbatim. + File /r "${BINARY_SOURCE_DIR}\*" + + ; Create start menu and desktop shortcuts + CreateShortCut "$SMPROGRAMS\$(^Name).lnk" "$INSTDIR\Cemu.exe" + ${If} $DesktopShortcut == 1 + CreateShortCut "$DESKTOP\$(^Name).lnk" "$INSTDIR\Cemu.exe" + ${EndIf} +SectionEnd + +!include "FileFunc.nsh" + +Section -Post + WriteUninstaller "$INSTDIR\uninst.exe" + + WriteRegStr HKCU "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\Cemu.exe" + + ; Write metadata for add/remove programs applet + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\Cemu.exe" + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" + WriteRegStr HKCU "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR" + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKCU "${PRODUCT_UNINST_KEY}" "EstimatedSize" "$0" + + WriteRegStr HKCU "Software\Classes\.wud" "" "$(^Name)" + WriteRegStr HKCU "Software\Classes\.wux" "" "$(^Name)" + WriteRegStr HKCU "Software\Classes\.wua" "" "$(^Name)" + WriteRegStr HKCU "Software\Classes\$(^Name)\DefaultIcon" "" "$INSTDIR\Cemu.exe,0" + WriteRegStr HKCU "Software\Classes\$(^Name)\Shell\open\command" "" '"$INSTDIR\Cemu.exe" %1' +SectionEnd + +Section Uninstall + Delete "$DESKTOP\$(^Name).lnk" + Delete "$SMPROGRAMS\$(^Name).lnk" + +; Be a bit careful to not delete files a user may have put into the install directory + Delete "$INSTDIR\Cemu.exe" + Delete "$INSTDIR\uninst.exe" + RMDir /r "$INSTDIR\gameProfiles" + RMDir /r "$INSTDIR\resources" + RMDir "$INSTDIR" + + DeleteRegKey HKCU "Software\Classes\.wud" + DeleteRegKey HKCU "Software\Classes\.wux" + DeleteRegKey HKCU "Software\Classes\.wua" + DeleteRegKey HKCU "Software\Classes\$(^Name)" + + DeleteRegKey HKCU "Software\Classes\discord-460807638964371468" + + DeleteRegKey HKCU "${PRODUCT_UNINST_KEY}" + DeleteRegKey HKCU "${PRODUCT_DIR_REGKEY}" + + SetAutoClose true +SectionEnd From 158c4e17a28f25173bd9a5dabb7018d37ac958d9 Mon Sep 17 00:00:00 2001 From: Michael Schroder Date: Tue, 9 Sep 2025 12:05:06 -0700 Subject: [PATCH 4/8] input: Add support for Wii Remote Plus by handling the inactive MotionPlus extension events (#1683) --- src/input/api/Wiimote/WiimoteControllerProvider.cpp | 3 +++ src/input/api/Wiimote/WiimoteMessages.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/input/api/Wiimote/WiimoteControllerProvider.cpp b/src/input/api/Wiimote/WiimoteControllerProvider.cpp index c2454319..b55c9cd4 100644 --- a/src/input/api/Wiimote/WiimoteControllerProvider.cpp +++ b/src/input/api/Wiimote/WiimoteControllerProvider.cpp @@ -344,6 +344,9 @@ void WiimoteControllerProvider::reader_thread() new_state.m_extension = {}; request_status(index); break; + case kExtensionMotionPlusInactive: + cemuLog_logDebug(LogType::Force,"Extension Type Received: Inactive MotionPlus"); + break; default: cemuLog_logDebug(LogType::Force,"Unknown extension: {:#x}", be_type.value()); new_state.m_extension = {}; diff --git a/src/input/api/Wiimote/WiimoteMessages.h b/src/input/api/Wiimote/WiimoteMessages.h index 32dd4658..1ab09183 100644 --- a/src/input/api/Wiimote/WiimoteMessages.h +++ b/src/input/api/Wiimote/WiimoteMessages.h @@ -53,6 +53,7 @@ enum ExtensionType : uint64 kExtensionDrums = 0x0100A4200103, kExtensionBalanceBoard = 0x2A2C, + kExtensionMotionPlusInactive = 0xa4200005, kExtensionMotionPlus = 0xa6200005, kExtensionPartialyInserted = 0xffffffffffff, From 492116a6baa5b3384666c671e7dbe819dfe5f4a9 Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Thu, 11 Sep 2025 13:13:24 +0200 Subject: [PATCH 5/8] VPAD: report gamepad volume slider position even when audio playback is disabled or failed to init --- src/Cafe/OS/libs/snd_core/ax_out.cpp | 3 +-- src/gui/wxgui/GeneralSettings2.cpp | 13 +++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Cafe/OS/libs/snd_core/ax_out.cpp b/src/Cafe/OS/libs/snd_core/ax_out.cpp index fe32cfb4..55e97966 100644 --- a/src/Cafe/OS/libs/snd_core/ax_out.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_out.cpp @@ -413,13 +413,12 @@ namespace snd_core } } + g_padVolume = GetConfig().pad_volume; if (!g_padAudio) { try { g_padAudio = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::Gamepad, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16); - if(g_padAudio) - g_padVolume = g_padAudio->GetVolume(); } catch (std::runtime_error& ex) { diff --git a/src/gui/wxgui/GeneralSettings2.cpp b/src/gui/wxgui/GeneralSettings2.cpp index f937549d..85648be6 100644 --- a/src/gui/wxgui/GeneralSettings2.cpp +++ b/src/gui/wxgui/GeneralSettings2.cpp @@ -1191,10 +1191,9 @@ void GeneralSettings2::OnVolumeChanged(wxCommandEvent& event) if(event.GetEventObject() == m_pad_volume) { if (g_padAudio) - { g_padAudio->SetVolume(event.GetInt()); - g_padVolume = event.GetInt(); - } + + g_padVolume = event.GetInt(); } else if (event.GetEventObject() == m_tv_volume) { @@ -1216,11 +1215,8 @@ void GeneralSettings2::OnInputVolumeChanged(wxCommandEvent& event) { std::shared_lock lock(g_audioMutex); if (g_padAudio) - { g_padAudio->SetInputVolume(event.GetInt()); - g_padVolume = event.GetInt(); - } - + event.Skip(); } @@ -1913,11 +1909,12 @@ void GeneralSettings2::UpdateAudioDevice() else channels = CemuConfig::AudioChannelsToNChannels(config.pad_channels); + g_padVolume = m_pad_volume->GetValue(); + try { g_padAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, description->GetDescription(), 48000, channels, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16); g_padAudio->SetVolume(m_pad_volume->GetValue()); - g_padVolume = m_pad_volume->GetValue(); } catch (std::runtime_error& ex) { From 3c1f920d6ca5ad08595c6f64e12ecdd3b5f008e4 Mon Sep 17 00:00:00 2001 From: SamoZ256 <96914946+SamoZ256@users.noreply.github.com> Date: Sat, 20 Sep 2025 00:54:24 +0200 Subject: [PATCH 6/8] macOS: bump minimum version (#1690) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 23f5f611..33a994d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ if (ENABLE_VCPKG) OUTPUT_VARIABLE is_vcpkg_shallow OUTPUT_STRIP_TRAILING_WHITESPACE ) - + if(is_vcpkg_shallow STREQUAL "true") message(STATUS "vcpkg is shallow. Unshallowing it now...") execute_process( @@ -93,7 +93,7 @@ endif() if (APPLE) enable_language(OBJC OBJCXX) - set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0") + set(CMAKE_OSX_DEPLOYMENT_TARGET "13.4") endif() if (UNIX AND NOT APPLE) From 84f12eea65dd185bc7b849303d515d189efb1642 Mon Sep 17 00:00:00 2001 From: oltolm Date: Mon, 22 Sep 2025 01:25:57 +0200 Subject: [PATCH 7/8] UI: fix sorting after style switch (#1693) --- src/gui/wxgui/components/wxGameList.cpp | 10 +++++++--- src/gui/wxgui/components/wxGameList.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/gui/wxgui/components/wxGameList.cpp b/src/gui/wxgui/components/wxGameList.cpp index f807042c..f760e0b3 100644 --- a/src/gui/wxgui/components/wxGameList.cpp +++ b/src/gui/wxgui/components/wxGameList.cpp @@ -514,6 +514,9 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2, return CafeTitleList::GetGameInfo(id).GetRegion(); }; + if (!sortData->asc) + std::swap(titleId1, titleId2); + switch(sortData->column) { default: @@ -542,7 +545,7 @@ std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2, int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) { const auto sort_data = (SortData*)sortData; - return sort_data->dir * order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data)); + return order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data)); } void wxGameList::SortEntries(int column) @@ -566,7 +569,7 @@ void wxGameList::SortEntries(int column) case ColumnRegion: case ColumnTitleID: { - SortData data{this, ItemColumns{column}, ascending ? 1 : -1}; + SortData data{this, ItemColumns{column}, ascending}; SortItems(SortFunction, (wxIntPtr)&data); ShowSortIndicator(column, ascending); break; @@ -1677,7 +1680,8 @@ void wxGameList::CreateShortcut(GameInfo2& gameInfo) hres = shellLinkFile->Save(outputPath.wc_str(), TRUE); } } - if (!SUCCEEDED(hres)) { + if (FAILED(hres)) + { auto errorMsg = formatWxString(_("Failed to save shortcut to {}"), outputPath); wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR); } diff --git a/src/gui/wxgui/components/wxGameList.h b/src/gui/wxgui/components/wxGameList.h index ae2ea245..e4f90ca3 100644 --- a/src/gui/wxgui/components/wxGameList.h +++ b/src/gui/wxgui/components/wxGameList.h @@ -89,7 +89,7 @@ private: { wxGameList* thisptr; ItemColumns column; - int dir; + bool asc; }; int FindInsertPosition(TitleId titleId); From d54fb0ba78ce2ffac3caa399414af19ec1016f05 Mon Sep 17 00:00:00 2001 From: SamoZ256 <96914946+SamoZ256@users.noreply.github.com> Date: Sat, 27 Sep 2025 00:41:17 +0200 Subject: [PATCH 8/8] arm: flush denormals to zero (#1696) --- src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp index 2f89000b..19391bbd 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp @@ -15,6 +15,33 @@ #include "util/helpers/helpers.h" +#ifdef __arm64__ +#if defined(__clang__) +#include +#elif defined(_MSC_VER) +#include +#endif +#endif + +namespace { + +void enableFlushDenormalsToZero() +{ +#if defined(ARCH_X86_64) + _mm_setcsr(_mm_getcsr() | 0x8000); +#elif defined(__arm64__) +#if defined(__clang__) + __arm_wsr64("fpcr", __arm_rsr64("fpcr") | (1 << 24)); +#elif defined(__GNUC__) + __builtin_aarch64_set_fpcr(__builtin_aarch64_get_fpcr() | (1 << 24)); +#elif defined(_MSC_VER) + _WriteStatusReg(ARM64_FPCR, _ReadStatusReg(ARM64_FPCR) | (1 << 24)); +#endif +#endif +} + +} + SlimRWLock srwlock_activeThreadList; // public list of active threads @@ -1321,9 +1348,7 @@ namespace coreinit #endif OSHostThread* hostThread = (OSHostThread*)_thread; - #if defined(ARCH_X86_64) - _mm_setcsr(_mm_getcsr() | 0x8000); // flush denormals to zero - #endif + enableFlushDenormalsToZero(); PPCInterpreter_t* hCPU = &hostThread->ppcInstance; __OSLoadThread(hostThread->m_thread, hCPU, hostThread->selectedCore); @@ -1369,9 +1394,8 @@ namespace coreinit { SetThreadName(fmt::format("OSSched[core={}]", (uintptr_t)_assignedCoreIndex).c_str()); t_assignedCoreIndex = (sint32)(uintptr_t)_assignedCoreIndex; - #if defined(ARCH_X86_64) - _mm_setcsr(_mm_getcsr() | 0x8000); // flush denormals to zero - #endif + + enableFlushDenormalsToZero(); #if BOOST_OS_LINUX if (g_gdbstub)