diff --git a/.ci/pack.sh b/.ci/pack.sh
index 3609f38446..2aedbd4df1 100755
--- a/.ci/pack.sh
+++ b/.ci/pack.sh
@@ -7,13 +7,6 @@ REV_NAME="citra-${OS}-${TARGET}-${GITDATE}-${GITREV}"
# Find out what release we are building
if [[ "$GITHUB_REF_NAME" =~ ^canary- ]] || [[ "$GITHUB_REF_NAME" =~ ^nightly- ]]; then
RELEASE_NAME=$(echo $GITHUB_REF_NAME | cut -d- -f1)
- # For compatibility with existing installs, use mingw/osx in the archive and target names.
- if [ "$TARGET" = "msys2" ]; then
- REV_NAME="citra-${OS}-mingw-${GITDATE}-${GITREV}"
- RELEASE_NAME="${RELEASE_NAME}-mingw"
- elif [ "$OS" = "macos" ]; then
- REV_NAME="citra-osx-${TARGET}-${GITDATE}-${GITREV}"
- fi
else
RELEASE_NAME=head
fi
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index bdd05d4b0c..4e418689d9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -161,9 +161,16 @@ jobs:
- name: Set up MSVC
uses: ilammy/msvc-dev-cmd@v1
if: ${{ matrix.target == 'msvc' }}
- - name: Install MSVC extra tools
+ - name: Install extra tools (MSVC)
run: choco install ccache ninja wget
if: ${{ matrix.target == 'msvc' }}
+ - name: Set up Vulkan SDK (MSVC)
+ uses: humbletim/setup-vulkan-sdk@v1.2.0
+ if: ${{ matrix.target == 'msvc' }}
+ with:
+ vulkan-query-version: latest
+ vulkan-components: Glslang
+ vulkan-use-cache: true
- name: Set up MSYS2
uses: msys2/setup-msys2@v2
if: ${{ matrix.target == 'msys2' }}
@@ -172,16 +179,10 @@ jobs:
update: true
install: git make p7zip
pacboy: >-
- toolchain:p ccache:p cmake:p ninja:p
+ toolchain:p ccache:p cmake:p ninja:p glslang:p
qt6-base:p qt6-multimedia:p qt6-multimedia-wmf:p qt6-tools:p qt6-translations:p
- - name: Setup Vulkan SDK
- uses: humbletim/setup-vulkan-sdk@v1.2.0
- with:
- vulkan-query-version: latest
- vulkan-components: Glslang
- vulkan-use-cache: true
- - name: Test glslangValidator
- run: glslangValidator --version
+ - name: Test glslang
+ run: glslang --version || glslangValidator --version
- name: Disable line ending translation
run: git config --global core.autocrlf input
- name: Build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 12c511b052..64b42a09ef 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,7 @@ CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT
CMAKE_DEPENDENT_OPTION(ENABLE_DEDICATED_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
+option(ENABLE_SCRIPTING "Enable RPC server for scripting" ON)
CMAKE_DEPENDENT_OPTION(ENABLE_CUBEB "Enables the cubeb audio backend" ON "NOT IOS" OFF)
option(ENABLE_OPENAL "Enables the OpenAL audio backend" ON)
@@ -68,6 +69,8 @@ option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over FFmpeg)" ON "WIN32" OFF)
CMAKE_DEPENDENT_OPTION(ENABLE_AUDIOTOOLBOX "Use AudioToolbox decoder (preferred over FFmpeg)" ON "APPLE" OFF)
+CMAKE_DEPENDENT_OPTION(CITRA_ENABLE_BUNDLE_TARGET "Enable the distribution bundling target." ON "NOT ANDROID AND NOT IOS" OFF)
+
# Compile options
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF)
option(ENABLE_LTO "Enable link time optimization" OFF)
@@ -219,7 +222,7 @@ find_package(Threads REQUIRED)
if (ENABLE_QT)
if (NOT USE_SYSTEM_QT)
- download_qt(6.5.0)
+ download_qt(6.5.1)
endif()
find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent)
@@ -341,13 +344,6 @@ function(get_timestamp _var)
set(${_var} "${timestamp}" PARENT_SCOPE)
endfunction()
-# Prevent boost from linking against libs when building
-add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY
- -DBOOST_SYSTEM_NO_LIB
- -DBOOST_DATE_TIME_NO_LIB
- -DBOOST_REGEX_NO_LIB
-)
-
# generate git/build information
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REF_SPEC GIT_REV)
@@ -355,17 +351,23 @@ git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
get_timestamp(BUILD_DATE)
-if (NOT USE_SYSTEM_BOOST)
- add_definitions( -DBOOST_ALL_NO_LIB )
+# Boost
+# Prevent boost from linking against libs when building
+add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY
+ -DBOOST_SYSTEM_NO_LIB
+ -DBOOST_DATE_TIME_NO_LIB
+ -DBOOST_REGEX_NO_LIB
+)
+if (USE_SYSTEM_BOOST)
+ find_package(Boost 1.70.0 COMPONENTS container locale serialization iostreams REQUIRED)
endif()
enable_testing()
add_subdirectory(externals)
-# Boost
-if (USE_SYSTEM_BOOST)
- find_package(Boost 1.70.0 COMPONENTS serialization iostreams REQUIRED)
-else()
+# Boost (bundled)
+if (NOT USE_SYSTEM_BOOST)
+ add_definitions( -DBOOST_ALL_NO_LIB )
add_library(Boost::boost ALIAS boost)
add_library(Boost::serialization ALIAS boost_serialization)
add_library(Boost::iostreams ALIAS boost_iostreams)
@@ -397,7 +399,7 @@ else()
endif()
# Create target for outputting distributable bundles.
-if (NOT ANDROID AND NOT IOS)
+if (CITRA_ENABLE_BUNDLE_TARGET)
include(BundleTarget)
if (ENABLE_SDL2_FRONTEND)
bundle_target(citra)
diff --git a/CMakeModules/BundleTarget.cmake b/CMakeModules/BundleTarget.cmake
index a805d4954c..f5b1c06f42 100644
--- a/CMakeModules/BundleTarget.cmake
+++ b/CMakeModules/BundleTarget.cmake
@@ -189,6 +189,12 @@ else()
add_custom_command(
TARGET bundle
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/")
+ add_custom_command(
+ TARGET bundle
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/dist/")
+ add_custom_command(
+ TARGET bundle
+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/dist/icon.png" "${CMAKE_BINARY_DIR}/bundle/dist/citra.png")
add_custom_command(
TARGET bundle
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/license.txt" "${CMAKE_BINARY_DIR}/bundle/")
diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake
index 6448e1f251..7ec6c75702 100644
--- a/CMakeModules/DownloadExternals.cmake
+++ b/CMakeModules/DownloadExternals.cmake
@@ -54,7 +54,8 @@ function(download_qt target)
set(host_flag "--autodesktop")
set(host_prefix "${base_path}/${target}/${host_arch_path}")
endif()
- set(install_args install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} ${host_flag} -m qtmultimedia)
+ set(install_args install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} ${host_flag}
+ -m qtmultimedia --archives qttranslations qttools qtsvg qtbase)
endif()
if (NOT EXISTS "${prefix}")
diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake
index f0c8e7da63..ee077cbbd9 100644
--- a/CMakeModules/GenerateSCMRev.cmake
+++ b/CMakeModules/GenerateSCMRev.cmake
@@ -12,8 +12,16 @@ set(HASH_FILES
"${VIDEO_CORE}/renderer_opengl/gl_shader_gen.h"
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.cpp"
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.h"
+ "${VIDEO_CORE}/renderer_vulkan/vk_shader_gen.cpp"
+ "${VIDEO_CORE}/renderer_vulkan/vk_shader_gen.h"
+ "${VIDEO_CORE}/renderer_vulkan/vk_shader_gen_spv.cpp"
+ "${VIDEO_CORE}/renderer_vulkan/vk_shader_gen_spv.h"
+ "${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp"
+ "${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h"
"${VIDEO_CORE}/shader/shader.cpp"
"${VIDEO_CORE}/shader/shader.h"
+ "${VIDEO_CORE}/shader/shader_uniforms.cpp"
+ "${VIDEO_CORE}/shader/shader_uniforms.h"
"${VIDEO_CORE}/pica.cpp"
"${VIDEO_CORE}/pica.h"
"${VIDEO_CORE}/regs_framebuffer.h"
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 7d6df72b68..238a411824 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -298,6 +298,11 @@ QAbstractItemView:read-only {
alternate-background-color: #232629;
}
+/* Workaround for https://bugreports.qt.io/browse/QTBUG-115529 */
+QAbstractItemView:item {
+ border: 0px;
+}
+
QWidget:focus {
border: 1px solid #3daee9;
}
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
index c200819c55..12d05d7bff 100644
--- a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -481,6 +481,11 @@ QAbstractItemView QLineEdit {
padding: 2px;
}
+/* Workaround for https://bugreports.qt.io/browse/QTBUG-115529 */
+QAbstractItemView:item {
+ border: 0px;
+}
+
/* QAbstractScrollArea ----------------------------------------------------
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 4d79bd78b9..1d1df84050 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -12,27 +12,29 @@ include(DownloadExternals)
include(ExternalProject)
# Boost
-set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
-set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
-set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
-add_library(boost INTERFACE)
-target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
+if (NOT USE_SYSTEM_BOOST)
+ message(STATUS "Including vendored Boost library")
+ set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
+ set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "")
+ set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
+ add_library(boost INTERFACE)
+ target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
-# Boost::serialization
-file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
-add_library(boost_serialization STATIC ${boost_serialization_SRC})
-target_link_libraries(boost_serialization PUBLIC boost)
-
-# Boost::iostreams
-add_library(
- boost_iostreams
- STATIC
- ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/file_descriptor.cpp
- ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp
-)
-target_link_libraries(boost_iostreams PUBLIC boost)
+ # Boost::serialization
+ file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
+ add_library(boost_serialization STATIC ${boost_serialization_SRC})
+ target_link_libraries(boost_serialization PUBLIC boost)
+ # Boost::iostreams
+ add_library(
+ boost_iostreams
+ STATIC
+ ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/file_descriptor.cpp
+ ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp
+ )
+ target_link_libraries(boost_iostreams PUBLIC boost)
# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
+endif()
# Catch2
set(CATCH_INSTALL_DOCS OFF CACHE BOOL "")
@@ -95,6 +97,7 @@ set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "")
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "")
set(ENABLE_CTEST OFF CACHE BOOL "")
set(ENABLE_HLSL OFF CACHE BOOL "")
+set(BUILD_EXTERNAL OFF CACHE BOOL "")
add_subdirectory(glslang)
# inih
@@ -171,37 +174,39 @@ endif()
add_library(json-headers INTERFACE)
target_include_directories(json-headers INTERFACE ./json)
+# OpenSSL
+if (USE_SYSTEM_OPENSSL)
+ find_package(OpenSSL 1.1)
+ if (OPENSSL_FOUND)
+ set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
+ endif()
+endif()
+
+if (NOT OPENSSL_FOUND)
+ # LibreSSL
+ set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
+ set(OPENSSLDIR "/etc/ssl/")
+ add_subdirectory(libressl EXCLUDE_FROM_ALL)
+ target_include_directories(ssl INTERFACE ./libressl/include)
+ target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
+ get_directory_property(OPENSSL_LIBRARIES
+ DIRECTORY libressl
+ DEFINITION OPENSSL_LIBS)
+endif()
+
+# httplib
+add_library(httplib INTERFACE)
+target_include_directories(httplib INTERFACE ./httplib)
+target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT -DCPPHTTPLIB_NO_DEFAULT_USER_AGENT)
+target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
+
+if(ANDROID)
+ add_subdirectory(android-ifaddrs)
+ target_link_libraries(httplib INTERFACE ifaddrs)
+endif()
+
+# cpp-jwt
if (ENABLE_WEB_SERVICE)
- if (USE_SYSTEM_OPENSSL)
- find_package(OpenSSL 1.1)
- if (OPENSSL_FOUND)
- set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
- endif()
- endif()
-
- if (NOT OPENSSL_FOUND)
- # LibreSSL
- set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
- set(OPENSSLDIR "/etc/ssl/")
- add_subdirectory(libressl EXCLUDE_FROM_ALL)
- target_include_directories(ssl INTERFACE ./libressl/include)
- target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP)
- get_directory_property(OPENSSL_LIBRARIES
- DIRECTORY libressl
- DEFINITION OPENSSL_LIBS)
- endif()
-
- if(ANDROID)
- add_subdirectory(android-ifaddrs)
- endif()
-
- # httplib
- add_library(httplib INTERFACE)
- target_include_directories(httplib INTERFACE ./httplib)
- target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT -DCPPHTTPLIB_NO_DEFAULT_USER_AGENT)
- target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES})
-
- # cpp-jwt
add_library(cpp-jwt INTERFACE)
target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include)
target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON)
diff --git a/externals/boost b/externals/boost
index 700ae2eff3..3c27c785ad 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 700ae2eff3134792f09cea2b051666688b1d5b97
+Subproject commit 3c27c785ad0f8a742af02e620dc225673f3a12d8
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 4385cdf5fb..fddcc866d4 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -47,7 +47,7 @@ add_library(audio_core STATIC
create_target_directory_groups(audio_core)
-target_link_libraries(audio_core PUBLIC citra_common)
+target_link_libraries(audio_core PUBLIC citra_common citra_core)
target_link_libraries(audio_core PRIVATE SoundTouch teakra)
set_target_properties(audio_core PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
add_definitions(-DSOUNDTOUCH_INTEGER_SAMPLES)
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index ecb9448c11..e04b71783b 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -342,7 +342,7 @@ if (USE_DISCORD_PRESENCE)
endif()
if (ENABLE_WEB_SERVICE)
- target_compile_definitions(citra-qt PRIVATE -DENABLE_WEB_SERVICE)
+ target_link_libraries(citra-qt PRIVATE web_service)
endif()
if(UNIX AND NOT APPLE)
diff --git a/src/citra_qt/configuration/configure_graphics.cpp b/src/citra_qt/configuration/configure_graphics.cpp
index 300a2736d8..3951728e96 100644
--- a/src/citra_qt/configuration/configure_graphics.cpp
+++ b/src/citra_qt/configuration/configure_graphics.cpp
@@ -13,6 +13,7 @@ ConfigureGraphics::ConfigureGraphics(bool is_powered_on, QWidget* parent)
ui->setupUi(this);
ui->toggle_vsync_new->setEnabled(!is_powered_on);
+ ui->graphics_api_combo->setEnabled(!is_powered_on);
// Set the index to -1 to ensure the below lambda is called with setCurrentIndex
ui->graphics_api_combo->setCurrentIndex(-1);
@@ -28,9 +29,10 @@ ConfigureGraphics::ConfigureGraphics(bool is_powered_on, QWidget* parent)
});
connect(ui->toggle_hw_shader, &QCheckBox::toggled, this, [this] {
+ const bool enabled = ui->toggle_hw_shader->isEnabled();
const bool checked = ui->toggle_hw_shader->isChecked();
- ui->hw_shader_group->setEnabled(checked);
- ui->toggle_disk_shader_cache->setEnabled(checked);
+ ui->hw_shader_group->setEnabled(checked && enabled);
+ ui->toggle_disk_shader_cache->setEnabled(checked && enabled);
});
SetupPerGameUI();
diff --git a/src/citra_qt/configuration/configure_input.ui b/src/citra_qt/configuration/configure_input.ui
index 3e3e8e4f91..2d199e6673 100644
--- a/src/citra_qt/configuration/configure_input.ui
+++ b/src/citra_qt/configuration/configure_input.ui
@@ -13,7 +13,7 @@
ConfigureInput
-
+
-
-
@@ -63,654 +63,665 @@
-
-
-
-
-
-
- Face Buttons
-
-
- false
-
-
- false
-
-
-
-
-
-
-
-
-
- Y:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- X:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- B:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- A:
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Directional Pad
-
-
- false
-
-
- false
-
-
-
-
-
-
-
-
-
- Up:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Down:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Left:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Right:
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Misc.
-
-
- false
-
-
- false
-
-
-
-
-
-
-
-
-
- Start:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Select:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Home:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Power:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Circle Mod:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- GPIO14:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Debug:
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Circle Pad
-
-
- false
-
-
- false
-
-
-
-
-
-
-
-
-
- Up:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Right:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Left:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
- Set Analog Stick
-
-
-
- -
-
-
-
-
-
- Down:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
+
+
+ true
+
+
+
+
-
+
+
-
+
+
+ Face Buttons
+
+
+ false
+
+
+ false
+
+
+
-
+
+
-
+
+
+ Y:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ X:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ B:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ A:
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Directional Pad
+
+
+ false
+
+
+ false
+
+
+
-
+
+
-
+
+
+ Up:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Down:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Left:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Right:
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Misc.
+
+
+ false
+
+
+ false
+
+
+
-
+
+
-
+
+
+ Start:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Select:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Home:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Power:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Circle Mod:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ GPIO14:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Debug:
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Circle Pad
+
+
+ false
+
+
+ false
+
+
+
-
+
+
-
+
+
+ Up:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Right:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Left:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
- Deadzone: 0
-
-
- Qt::AlignHCenter
+ Set Analog Stick
+ -
+
+
-
+
+
+ Down:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+ Deadzone: 0
+
+
+ Qt::AlignHCenter
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
-
- -
-
-
- Qt::Horizontal
-
-
-
-
-
-
-
-
- -
-
-
- C-Stick
-
-
- false
-
-
- false
-
-
-
-
-
-
-
-
-
- Right:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Left:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- Up:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
- Set Analog Stick
-
-
-
- -
-
-
-
-
-
- Down:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
-
-
-
+
+
+ -
+
+
+ C-Stick
+
+
+ false
+
+
+ false
+
+
+
-
+
+
-
+
+
+ Right:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Left:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Up:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
- Deadzone: 0
-
-
- Qt::AlignHCenter
+ Set Analog Stick
+ -
+
+
-
+
+
+ Down:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
-
+
+
+ Deadzone: 0
+
+
+ Qt::AlignHCenter
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+
+
-
- -
-
-
- Qt::Horizontal
-
-
-
-
-
-
-
-
- -
-
-
- Shoulder Buttons
-
-
- false
-
-
- false
-
-
-
-
-
-
-
-
-
- ZR:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- ZL:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- L:
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- R:
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ -
+
+
+ Shoulder Buttons
+
+
+ false
+
+
+ false
+
+
+
-
+
+
-
+
+
+ ZR:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ ZL:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ L:
+
+
+
+ -
+
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ R:
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/src/citra_qt/configuration/configure_system.cpp b/src/citra_qt/configuration/configure_system.cpp
index 0a5c14a846..e63f5399ed 100644
--- a/src/citra_qt/configuration/configure_system.cpp
+++ b/src/citra_qt/configuration/configure_system.cpp
@@ -551,7 +551,6 @@ void ConfigureSystem::SetupPerGameUI() {
}
void ConfigureSystem::DownloadFromNUS() {
-#ifdef ENABLE_WEB_SERVICE
ui->button_start_download->setEnabled(false);
const auto mode =
@@ -590,5 +589,4 @@ void ConfigureSystem::DownloadFromNUS() {
}
ui->button_start_download->setEnabled(true);
-#endif
}
diff --git a/src/citra_qt/debugger/graphics/graphics.cpp b/src/citra_qt/debugger/graphics/graphics.cpp
index 1a3c0157c0..674b831001 100644
--- a/src/citra_qt/debugger/graphics/graphics.cpp
+++ b/src/citra_qt/debugger/graphics/graphics.cpp
@@ -64,15 +64,22 @@ void GPUCommandStreamItemModel::OnGXCommandFinishedInternal(int total_command_co
}
GPUCommandStreamWidget::GPUCommandStreamWidget(QWidget* parent)
- : QDockWidget(tr("Graphics Debugger"), parent) {
+ : QDockWidget(tr("Graphics Debugger"), parent), model(this) {
setObjectName(QStringLiteral("GraphicsDebugger"));
- GPUCommandStreamItemModel* command_model = new GPUCommandStreamItemModel(this);
- g_debugger.RegisterObserver(command_model);
-
- QListView* command_list = new QListView;
- command_list->setModel(command_model);
+ auto* command_list = new QListView;
+ command_list->setModel(&model);
command_list->setFont(GetMonospaceFont());
setWidget(command_list);
}
+
+void GPUCommandStreamWidget::showEvent(QShowEvent* event) {
+ g_debugger.RegisterObserver(&model);
+ QDockWidget::showEvent(event);
+}
+
+void GPUCommandStreamWidget::hideEvent(QHideEvent* event) {
+ g_debugger.UnregisterObserver(&model);
+ QDockWidget::hideEvent(event);
+}
diff --git a/src/citra_qt/debugger/graphics/graphics.h b/src/citra_qt/debugger/graphics/graphics.h
index 8837fb7922..9193c28219 100644
--- a/src/citra_qt/debugger/graphics/graphics.h
+++ b/src/citra_qt/debugger/graphics/graphics.h
@@ -37,5 +37,10 @@ class GPUCommandStreamWidget : public QDockWidget {
public:
GPUCommandStreamWidget(QWidget* parent = nullptr);
+protected:
+ void showEvent(QShowEvent* event) override;
+ void hideEvent(QHideEvent* event) override;
+
private:
+ GPUCommandStreamItemModel model;
};
diff --git a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
index 6711644e62..aaf733a7db 100644
--- a/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
@@ -16,6 +16,7 @@
#include "citra_qt/debugger/graphics/graphics_cmdlists.h"
#include "citra_qt/util/util.h"
#include "common/vector_math.h"
+#include "core/core.h"
#include "core/memory.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica_state.h"
@@ -166,7 +167,7 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
const auto format = texture.format;
const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config, format);
- const u8* src = memory.GetPhysicalPointer(config.GetPhysicalAddress());
+ const u8* src = system.Memory().GetPhysicalPointer(config.GetPhysicalAddress());
new_info_widget = new TextureInfoWidget(src, info);
}
if (command_info_widget) {
@@ -180,8 +181,8 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
}
#undef COMMAND_IN_RANGE
-GPUCommandListWidget::GPUCommandListWidget(Memory::MemorySystem& memory_, QWidget* parent)
- : QDockWidget(tr("Pica Command List"), parent), memory{memory_} {
+GPUCommandListWidget::GPUCommandListWidget(Core::System& system_, QWidget* parent)
+ : QDockWidget(tr("Pica Command List"), parent), system{system_} {
setObjectName(QStringLiteral("Pica Command List"));
GPUCommandListModel* model = new GPUCommandListModel(this);
diff --git a/src/citra_qt/debugger/graphics/graphics_cmdlists.h b/src/citra_qt/debugger/graphics/graphics_cmdlists.h
index 5ea4d125b3..4bd562a48f 100644
--- a/src/citra_qt/debugger/graphics/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics/graphics_cmdlists.h
@@ -11,8 +11,8 @@
class QPushButton;
class QTreeView;
-namespace Memory {
-class MemorySystem;
+namespace Core {
+class System;
}
class GPUCommandListModel : public QAbstractListModel {
@@ -42,7 +42,7 @@ class GPUCommandListWidget : public QDockWidget {
Q_OBJECT
public:
- explicit GPUCommandListWidget(Memory::MemorySystem& memory, QWidget* parent = nullptr);
+ explicit GPUCommandListWidget(Core::System& system, QWidget* parent = nullptr);
public slots:
void OnToggleTracing();
@@ -57,7 +57,7 @@ signals:
private:
std::unique_ptr pica_trace;
- Memory::MemorySystem& memory;
+ Core::System& system;
QTreeView* list_widget;
QWidget* command_info_widget;
QPushButton* toggle_tracing;
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index b447af3234..202be08c3b 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -448,7 +448,7 @@ void GMainWindow::InitializeDebugWidgets() {
graphicsWidget->hide();
debug_menu->addAction(graphicsWidget->toggleViewAction());
- graphicsCommandsWidget = new GPUCommandListWidget(system.Memory(), this);
+ graphicsCommandsWidget = new GPUCommandListWidget(system, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget);
graphicsCommandsWidget->hide();
debug_menu->addAction(graphicsCommandsWidget->toggleViewAction());
@@ -1071,8 +1071,10 @@ bool GMainWindow::LoadROM(const QString& filename) {
ShutdownGame();
}
- render_window->InitRenderTarget();
- secondary_window->InitRenderTarget();
+ if (!render_window->InitRenderTarget() || !secondary_window->InitRenderTarget()) {
+ LOG_CRITICAL(Frontend, "Failed to initialize render targets!");
+ return false;
+ }
const auto scope = render_window->Acquire();
@@ -1420,10 +1422,17 @@ void GMainWindow::UpdateSaveStates() {
actions_save_state[i]->setText(tr("Slot %1").arg(i + 1));
}
for (const auto& savestate : savestates) {
- const auto text = tr("Slot %1 - %2")
- .arg(savestate.slot)
- .arg(QDateTime::fromSecsSinceEpoch(savestate.time)
- .toString(QStringLiteral("yyyy-MM-dd hh:mm:ss")));
+ const bool display_name =
+ savestate.status == Core::SaveStateInfo::ValidationStatus::RevisionDismatch &&
+ !savestate.build_name.empty();
+ const auto text =
+ tr("Slot %1 - %2 %3")
+ .arg(savestate.slot)
+ .arg(QDateTime::fromSecsSinceEpoch(savestate.time)
+ .toString(QStringLiteral("yyyy-MM-dd hh:mm:ss")))
+ .arg(display_name ? QString::fromStdString(savestate.build_name) : QLatin1String())
+ .trimmed();
+
actions_load_state[savestate.slot - 1]->setEnabled(true);
actions_load_state[savestate.slot - 1]->setText(text);
actions_save_state[savestate.slot - 1]->setText(text);
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 18e4be6296..acbf79bfff 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -16,6 +16,7 @@
#include "common/common_paths.h"
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "common/scope_exit.h"
#include "common/string_util.h"
#ifdef _WIN32
@@ -324,31 +325,32 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
return AndroidStorage::CopyFile(srcFilename, std::string(GetParentPath(destFilename)),
std::string(GetFilename(destFilename)));
#else
- using CFilePointer = std::unique_ptr;
// Open input file
- CFilePointer input{fopen(srcFilename.c_str(), "rb"), std::fclose};
+ FILE* input = fopen(srcFilename.c_str(), "rb");
if (!input) {
LOG_ERROR(Common_Filesystem, "opening input failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
return false;
}
+ SCOPE_EXIT({ fclose(input); });
// open output file
- CFilePointer output{fopen(destFilename.c_str(), "wb"), std::fclose};
+ FILE* output = fopen(destFilename.c_str(), "wb");
if (!output) {
LOG_ERROR(Common_Filesystem, "opening output failed {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
return false;
}
+ SCOPE_EXIT({ fclose(output); });
// copy loop
std::array buffer;
- while (!feof(input.get())) {
+ while (!feof(input)) {
// read input
- std::size_t rnum = fread(buffer.data(), sizeof(char), buffer.size(), input.get());
+ std::size_t rnum = fread(buffer.data(), sizeof(char), buffer.size(), input);
if (rnum != buffer.size()) {
- if (ferror(input.get()) != 0) {
+ if (ferror(input) != 0) {
LOG_ERROR(Common_Filesystem, "failed reading from source, {} --> {}: {}",
srcFilename, destFilename, GetLastErrorMsg());
return false;
@@ -356,7 +358,7 @@ bool Copy(const std::string& srcFilename, const std::string& destFilename) {
}
// write output
- std::size_t wnum = fwrite(buffer.data(), sizeof(char), rnum, output.get());
+ std::size_t wnum = fwrite(buffer.data(), sizeof(char), rnum, output);
if (wnum != rnum) {
LOG_ERROR(Common_Filesystem, "failed writing to output, {} --> {}: {}", srcFilename,
destFilename, GetLastErrorMsg());
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f507b5dc4b..b25a8c3883 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -458,19 +458,14 @@ add_library(citra_core STATIC
mmio.h
movie.cpp
movie.h
+ nus_download.cpp
+ nus_download.h
perf_stats.cpp
perf_stats.h
precompiled_headers.h
- rpc/packet.cpp
- rpc/packet.h
- rpc/rpc_server.cpp
- rpc/rpc_server.h
- rpc/server.cpp
- rpc/server.h
- rpc/udp_server.cpp
- rpc/udp_server.h
savestate.cpp
savestate.h
+ savestate_data.h
system_titles.cpp
system_titles.h
telemetry_session.cpp
@@ -483,16 +478,26 @@ add_library(citra_core STATIC
create_target_directory_groups(citra_core)
target_link_libraries(citra_core PUBLIC citra_common PRIVATE audio_core network video_core)
-target_link_libraries(citra_core PRIVATE Boost::boost Boost::serialization Boost::iostreams)
+target_link_libraries(citra_core PRIVATE Boost::boost Boost::serialization Boost::iostreams httplib)
target_link_libraries(citra_core PUBLIC dds-ktx PRIVATE cryptopp fmt::fmt lodepng open_source_archives)
set_target_properties(citra_core PROPERTIES INTERPROCEDURAL_OPTIMIZATION ${ENABLE_LTO})
if (ENABLE_WEB_SERVICE)
- target_compile_definitions(citra_core PRIVATE -DENABLE_WEB_SERVICE -DCPPHTTPLIB_OPENSSL_SUPPORT)
- target_link_libraries(citra_core PRIVATE web_service ${OPENSSL_LIBS} httplib)
- if (ANDROID)
- target_link_libraries(citra_core PRIVATE ifaddrs)
- endif()
+ target_link_libraries(citra_core PRIVATE web_service)
+endif()
+
+if (ENABLE_SCRIPTING)
+ target_compile_definitions(citra_core PUBLIC -DENABLE_SCRIPTING)
+ target_sources(citra_core PRIVATE
+ rpc/packet.cpp
+ rpc/packet.h
+ rpc/rpc_server.cpp
+ rpc/rpc_server.h
+ rpc/server.cpp
+ rpc/server.h
+ rpc/udp_server.cpp
+ rpc/udp_server.h
+ )
endif()
if ("x86_64" IN_LIST ARCHITECTURE OR "arm64" IN_LIST ARCHITECTURE)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 97f71d7d65..de239fe21a 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -45,7 +45,9 @@
#include "core/hw/lcd.h"
#include "core/loader/loader.h"
#include "core/movie.h"
+#ifdef ENABLE_SCRIPTING
#include "core/rpc/server.h"
+#endif
#include "core/telemetry_session.h"
#include "network/network.h"
#include "video_core/custom_textures/custom_tex_manager.h"
@@ -418,7 +420,9 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
telemetry_session = std::make_unique();
+#ifdef ENABLE_SCRIPTING
rpc_server = std::make_unique(*this);
+#endif
service_manager = std::make_unique(*this);
archive_manager = std::make_unique(*this);
@@ -555,7 +559,9 @@ void System::Shutdown(bool is_deserializing) {
}
custom_tex_manager.reset();
telemetry_session.reset();
+#ifdef ENABLE_SCRIPTING
rpc_server.reset();
+#endif
archive_manager.reset();
service_manager.reset();
dsp_core.reset();
diff --git a/src/core/core.h b/src/core/core.h
index 4c401b736d..ae3310ca72 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -405,8 +405,10 @@ private:
/// Image interface
std::shared_ptr registered_image_interface;
+#ifdef ENABLE_SCRIPTING
/// RPC Server for scripting support
std::unique_ptr rpc_server;
+#endif
std::unique_ptr archive_manager;
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp
index c1a61126bf..84c989642b 100644
--- a/src/core/hle/service/ac/ac.cpp
+++ b/src/core/hle/service/ac/ac.cpp
@@ -151,6 +151,17 @@ void Module::Interface::RegisterDisconnectEvent(Kernel::HLERequestContext& ctx)
LOG_WARNING(Service_AC, "(STUBBED) called");
}
+void Module::Interface::GetConnectingProxyEnable(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp(ctx);
+ constexpr bool proxy_enabled = false;
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(proxy_enabled);
+
+ LOG_WARNING(Service_AC, "(STUBBED) called");
+}
+
void Module::Interface::IsConnected(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
u32 unk = rp.Pop();
diff --git a/src/core/hle/service/ac/ac.h b/src/core/hle/service/ac/ac.h
index 4203b0a934..38761150b9 100644
--- a/src/core/hle/service/ac/ac.h
+++ b/src/core/hle/service/ac/ac.h
@@ -120,6 +120,14 @@ public:
*/
void RegisterDisconnectEvent(Kernel::HLERequestContext& ctx);
+ /**
+ * AC::GetConnectingProxyEnable service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : bool, is proxy enabled
+ */
+ void GetConnectingProxyEnable(Kernel::HLERequestContext& ctx);
+
/**
* AC::IsConnected service function
* Outputs:
diff --git a/src/core/hle/service/ac/ac_i.cpp b/src/core/hle/service/ac/ac_i.cpp
index 84a643e8bc..f7766b3249 100644
--- a/src/core/hle/service/ac/ac_i.cpp
+++ b/src/core/hle/service/ac/ac_i.cpp
@@ -27,6 +27,7 @@ AC_I::AC_I(std::shared_ptr ac) : Module::Interface(std::move(ac), "ac:i"
{0x0027, &AC_I::GetInfraPriority, "GetInfraPriority"},
{0x002D, &AC_I::SetRequestEulaVersion, "SetRequestEulaVersion"},
{0x0030, &AC_I::RegisterDisconnectEvent, "RegisterDisconnectEvent"},
+ {0x0036, &AC_I::GetConnectingProxyEnable, "GetConnectingProxyEnable"},
{0x003C, nullptr, "GetAPSSIDList"},
{0x003E, &AC_I::IsConnected, "IsConnected"},
{0x0040, &AC_I::SetClientVersion, "SetClientVersion"},
diff --git a/src/core/hle/service/ac/ac_u.cpp b/src/core/hle/service/ac/ac_u.cpp
index d6d0a68679..12506962c5 100644
--- a/src/core/hle/service/ac/ac_u.cpp
+++ b/src/core/hle/service/ac/ac_u.cpp
@@ -27,6 +27,7 @@ AC_U::AC_U(std::shared_ptr ac) : Module::Interface(std::move(ac), "ac:u"
{0x0027, &AC_U::GetInfraPriority, "GetInfraPriority"},
{0x002D, &AC_U::SetRequestEulaVersion, "SetRequestEulaVersion"},
{0x0030, &AC_U::RegisterDisconnectEvent, "RegisterDisconnectEvent"},
+ {0x0036, &AC_U::GetConnectingProxyEnable, "GetConnectingProxyEnable"},
{0x003C, nullptr, "GetAPSSIDList"},
{0x003E, &AC_U::IsConnected, "IsConnected"},
{0x0040, &AC_U::SetClientVersion, "SetClientVersion"},
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 855deebd6c..8a7939ea10 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -31,9 +31,7 @@
#include "core/hle/service/fs/fs_user.h"
#include "core/loader/loader.h"
#include "core/loader/smdh.h"
-#ifdef ENABLE_WEB_SERVICE
-#include "web_service/nus_download.h"
-#endif
+#include "core/nus_download.h"
namespace Service::AM {
@@ -463,7 +461,6 @@ InstallStatus InstallCIA(const std::string& path,
}
InstallStatus InstallFromNus(u64 title_id, int version) {
-#ifdef ENABLE_WEB_SERVICE
LOG_DEBUG(Service_AM, "Downloading {:X}", title_id);
CIAFile install_file{GetTitleMediaType(title_id)};
@@ -472,7 +469,7 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
if (version != -1) {
path += fmt::format(".{}", version);
}
- auto tmd_response = WebService::NUS::Download(path);
+ auto tmd_response = Core::NUS::Download(path);
if (!tmd_response) {
LOG_ERROR(Service_AM, "Failed to download tmd for {:016X}", title_id);
return InstallStatus::ErrorFileNotFound;
@@ -481,7 +478,7 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
tmd.Load(*tmd_response);
path = fmt::format("/ccs/download/{:016X}/cetk", title_id);
- auto cetk_response = WebService::NUS::Download(path);
+ auto cetk_response = Core::NUS::Download(path);
if (!cetk_response) {
LOG_ERROR(Service_AM, "Failed to download cetk for {:016X}", title_id);
return InstallStatus::ErrorFileNotFound;
@@ -492,7 +489,7 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
for (std::size_t i = 0; i < content_count; ++i) {
const std::string filename = fmt::format("{:08x}", tmd.GetContentIDByIndex(i));
path = fmt::format("/ccs/download/{:016X}/{}", title_id, filename);
- const auto temp_response = WebService::NUS::Download(path);
+ const auto temp_response = Core::NUS::Download(path);
if (!temp_response) {
LOG_ERROR(Service_AM, "Failed to download content for {:016X}", title_id);
return InstallStatus::ErrorFileNotFound;
@@ -550,9 +547,6 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
return result;
}
return InstallStatus::Success;
-#else
- return InstallStatus::ErrorFileNotFound;
-#endif
}
u64 GetTitleUpdateId(u64 title_id) {
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index c1e0d446a6..2daa1116c3 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -620,9 +620,9 @@ void Module::Interface::SetData(Kernel::HLERequestContext& ctx) {
void Module::Interface::ReadData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
- const u32 dest_buffer_size = rp.Pop();
- const CecSystemInfoType info_type = rp.PopEnum();
- const u32 param_buffer_size = rp.Pop();
+ const auto dest_buffer_size = rp.Pop();
+ const auto info_type = rp.PopEnum();
+ const auto param_buffer_size = rp.Pop();
auto& param_buffer = rp.PopMappedBuffer();
auto& dest_buffer = rp.PopMappedBuffer();
@@ -631,22 +631,23 @@ void Module::Interface::ReadData(Kernel::HLERequestContext& ctx) {
std::vector buffer;
switch (info_type) {
case CecSystemInfoType::EulaVersion: {
- auto cfg = Service::CFG::GetModule(cecd->system);
- Service::CFG::EULAVersion version = cfg->GetEULAVersion();
- dest_buffer.Write(&version, 0, sizeof(version));
+ const auto cfg = Service::CFG::GetModule(cecd->system);
+ const auto version = cfg->GetEULAVersion();
+ buffer = {version.minor, version.major};
break;
}
case CecSystemInfoType::Eula:
- buffer = {0x01}; // Eula agreed
- dest_buffer.Write(buffer.data(), 0, buffer.size());
+ buffer = {true}; // Eula agreed
break;
case CecSystemInfoType::ParentControl:
- buffer = {0x00}; // No parent control
- dest_buffer.Write(buffer.data(), 0, buffer.size());
+ buffer = {false}; // No parent control
break;
default:
LOG_ERROR(Service_CECD, "Unknown system info type={:#x}", info_type);
+ buffer = {};
}
+ dest_buffer.Write(buffer.data(), 0,
+ std::min(static_cast(dest_buffer_size), buffer.size()));
rb.Push(RESULT_SUCCESS);
rb.PushMappedBuffer(param_buffer);
diff --git a/src/core/hle/service/http/http_c.cpp b/src/core/hle/service/http/http_c.cpp
index c0db50f5c8..c24767bcc4 100644
--- a/src/core/hle/service/http/http_c.cpp
+++ b/src/core/hle/service/http/http_c.cpp
@@ -314,6 +314,7 @@ void HTTP_C::ReceiveDataImpl(Kernel::HLERequestContext& ctx, bool timeout) {
} else {
LOG_WARNING(Service_HTTP, "(STUBBED) called");
}
+ [[maybe_unused]] Kernel::MappedBuffer& buffer = rp.PopMappedBuffer();
Kernel::MappedBuffer& buffer = rp.PopMappedBuffer();
diff --git a/src/core/hle/service/http/http_c.h b/src/core/hle/service/http/http_c.h
index 0e08aa7dff..41fb2183fc 100644
--- a/src/core/hle/service/http/http_c.h
+++ b/src/core/hle/service/http/http_c.h
@@ -17,12 +17,10 @@
#include
#include
#include
-#ifdef ENABLE_WEB_SERVICE
#if defined(__ANDROID__)
#include
#endif
#include
-#endif
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/service.h"
@@ -214,7 +212,6 @@ public:
bool uses_default_client_cert{};
#ifdef ENABLE_WEB_SERVICE
httplib::Response response;
-#endif
};
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 62f82d8ba3..f1e2801fb3 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -316,7 +316,7 @@ void Module::Interface::GetTagInfo2(Kernel::HLERequestContext& ctx) {
if (nfc->nfc_mode == CommunicationMode::TrainTag) {
LOG_ERROR(Service_NFC, "CommunicationMode {} not implemented", nfc->nfc_mode);
- IPC::RequestBuilder rb = rp.MakeBuilder(26, 0);
+ IPC::RequestBuilder rb = rp.MakeBuilder(25, 0);
rb.Push(RESULT_SUCCESS);
rb.PushRaw({});
return;
@@ -324,7 +324,7 @@ void Module::Interface::GetTagInfo2(Kernel::HLERequestContext& ctx) {
TagInfo2 tag_info{};
const auto result = nfc->device->GetTagInfo2(tag_info);
- IPC::RequestBuilder rb = rp.MakeBuilder(26, 0);
+ IPC::RequestBuilder rb = rp.MakeBuilder(25, 0);
rb.Push(result);
rb.PushRaw(tag_info);
}
@@ -383,10 +383,14 @@ void Module::Interface::OpenApplicationArea(Kernel::HLERequestContext& ctx) {
void Module::Interface::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
u32 access_id = rp.Pop();
- [[maybe_unused]] u32 size = rp.Pop();
+ u32 size = rp.Pop();
std::vector buffer = rp.PopStaticBuffer();
- LOG_CRITICAL(Service_NFC, "called, size={}", size);
+ LOG_INFO(Service_NFC, "called, size={}", size);
+
+ if (buffer.size() > size) {
+ buffer.resize(size);
+ }
if (nfc->nfc_mode != CommunicationMode::Amiibo) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@@ -402,8 +406,9 @@ void Module::Interface::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
+ u32 size = rp.Pop();
- LOG_INFO(Service_NFC, "called");
+ LOG_INFO(Service_NFC, "called, size={}", size);
nfc->device->RescheduleTagRemoveEvent();
@@ -413,7 +418,7 @@ void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) {
return;
}
- std::vector buffer(sizeof(ApplicationArea));
+ std::vector buffer(size);
const auto result = nfc->device->GetApplicationArea(buffer);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
@@ -423,11 +428,15 @@ void Module::Interface::ReadApplicationArea(Kernel::HLERequestContext& ctx) {
void Module::Interface::WriteApplicationArea(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
- [[maybe_unused]] u32 size = rp.Pop();
+ u32 size = rp.Pop();
std::vector tag_uuid_info = rp.PopStaticBuffer();
std::vector buffer = rp.PopStaticBuffer();
- LOG_CRITICAL(Service_NFC, "called, size={}", size);
+ LOG_INFO(Service_NFC, "called, size={}", size);
+
+ if (buffer.size() > size) {
+ buffer.resize(size);
+ }
if (nfc->nfc_mode != CommunicationMode::Amiibo) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@@ -540,7 +549,7 @@ void Module::Interface::GetIdentificationBlock(Kernel::HLERequestContext& ctx) {
ModelInfo model_info{};
const auto result = nfc->device->GetModelInfo(model_info);
- IPC::RequestBuilder rb = rp.MakeBuilder(0x1F, 0);
+ IPC::RequestBuilder rb = rp.MakeBuilder(14, 0);
rb.Push(result);
rb.PushRaw(model_info);
}
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
index 18ac135cc2..107ff8101c 100644
--- a/src/core/hle/service/nfc/nfc_device.cpp
+++ b/src/core/hle/service/nfc/nfc_device.cpp
@@ -1101,8 +1101,8 @@ void NfcDevice::BuildAmiiboWithoutKeys() {
}
void NfcDevice::RescheduleTagRemoveEvent() {
- /// The interval at which the amiibo will be removed automatically 1.5s
- static constexpr u64 amiibo_removal_interval = nsToCycles(1500 * 1000 * 1000);
+ /// The interval at which the amiibo will be removed automatically 3s
+ static constexpr u64 amiibo_removal_interval = msToCycles(3 * 1000);
system.CoreTiming().UnscheduleEvent(remove_amiibo_event, 0);
diff --git a/src/web_service/nus_download.cpp b/src/core/nus_download.cpp
similarity index 93%
rename from src/web_service/nus_download.cpp
rename to src/core/nus_download.cpp
index af7a068a69..d9d79ae2bb 100644
--- a/src/web_service/nus_download.cpp
+++ b/src/core/nus_download.cpp
@@ -5,9 +5,9 @@
#include
#include
#include "common/logging/log.h"
-#include "web_service/nus_download.h"
+#include "core/nus_download.h"
-namespace WebService::NUS {
+namespace Core::NUS {
std::optional> Download(const std::string& path) {
constexpr auto HOST = "http://nus.cdn.c.shop.nintendowifi.net";
@@ -46,4 +46,4 @@ std::optional> Download(const std::string& path) {
return std::vector(response.body.begin(), response.body.end());
}
-} // namespace WebService::NUS
+} // namespace Core::NUS
diff --git a/src/web_service/nus_download.h b/src/core/nus_download.h
similarity index 85%
rename from src/web_service/nus_download.h
rename to src/core/nus_download.h
index 34633b7677..8953906bf6 100644
--- a/src/web_service/nus_download.h
+++ b/src/core/nus_download.h
@@ -8,8 +8,8 @@
#include
#include "common/common_types.h"
-namespace WebService::NUS {
+namespace Core::NUS {
std::optional> Download(const std::string& path);
-}
+} // namespace Core::NUS
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index ecf8b9d4dd..e0ed958df1 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -15,18 +15,21 @@
#include "core/core.h"
#include "core/movie.h"
#include "core/savestate.h"
+#include "core/savestate_data.h"
#include "network/network.h"
namespace Core {
#pragma pack(push, 1)
struct CSTHeader {
- std::array filetype; /// Unique Identifier to check the file type (always "CST"0x1B)
- u64_le program_id; /// ID of the ROM being executed. Also called title_id
- std::array revision; /// Git hash of the revision this savestate was created with
- u64_le time; /// The time when this save state was created
+ std::array filetype; /// Unique Identifier to check the file type (always "CST"0x1B)
+ u64_le program_id; /// ID of the ROM being executed. Also called title_id
+ std::array revision; /// Git hash of the revision this savestate was created with
+ u64_le time; /// The time when this save state was created
+ std::array build_name; /// The build name (Canary/Nightly) with the version number
+ u32_le zero = 0; /// Should be zero, just in case.
- std::array reserved{}; /// Make heading 256 bytes so it has consistent size
+ std::array reserved{}; /// Make heading 256 bytes so it has consistent size
};
static_assert(sizeof(CSTHeader) == 256, "CSTHeader should be 256 bytes");
#pragma pack(pop)
@@ -58,11 +61,26 @@ static bool ValidateSaveState(const CSTHeader& header, SaveStateInfo& info, u64
return false;
}
const std::string revision = fmt::format("{:02x}", fmt::join(header.revision, ""));
+ const std::string build_name =
+ header.zero == 0 ? reinterpret_cast(header.build_name.data()) : "";
+
if (revision == Common::g_scm_rev) {
info.status = SaveStateInfo::ValidationStatus::OK;
} else {
- LOG_WARNING(Core, "Save state file {} created from a different revision {}", path,
- revision);
+ if (!build_name.empty()) {
+ info.build_name = build_name;
+ } else if (hash_to_version.find(revision) != hash_to_version.end()) {
+ info.build_name = hash_to_version.at(revision);
+ }
+ if (info.build_name.empty()) {
+ LOG_WARNING(Core, "Save state file {} created from a different revision {}", path,
+ revision);
+ } else {
+ LOG_WARNING(Core,
+ "Save state file {} created from a different build {} with revision {}",
+ path, info.build_name, revision);
+ }
+
info.status = SaveStateInfo::ValidationStatus::RevisionDismatch;
}
return true;
@@ -134,6 +152,10 @@ void System::SaveState(u32 slot) const {
header.time = std::chrono::duration_cast(
std::chrono::system_clock::now().time_since_epoch())
.count();
+ const std::string build_fullname = Common::g_build_fullname;
+ std::memset(header.build_name.data(), 0, sizeof(header.build_name));
+ std::memcpy(header.build_name.data(), build_fullname.c_str(),
+ std::min(build_fullname.length(), sizeof(header.build_name) - 1));
if (file.WriteBytes(&header, sizeof(header)) != sizeof(header) ||
file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
diff --git a/src/core/savestate.h b/src/core/savestate.h
index 84daf47789..2962cce864 100644
--- a/src/core/savestate.h
+++ b/src/core/savestate.h
@@ -4,6 +4,7 @@
#pragma once
+#include
#include
#include "common/common_types.h"
@@ -16,6 +17,7 @@ struct SaveStateInfo {
OK,
RevisionDismatch,
} status;
+ std::string build_name;
};
constexpr u32 SaveStateSlotCount = 10; // Maximum count of savestate slots
diff --git a/src/core/savestate_data.h b/src/core/savestate_data.h
new file mode 100644
index 0000000000..5ae9346b90
--- /dev/null
+++ b/src/core/savestate_data.h
@@ -0,0 +1,1427 @@
+// Copyright 2023 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include