mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-05-04 10:18:36 +00:00
update Cheat files
This commit is contained in:
parent
9ab8c1e433
commit
cbfd634a4b
217 changed files with 2263 additions and 1880 deletions
|
@ -1,250 +0,0 @@
|
||||||
# - Find SDL2
|
|
||||||
# Find the SDL2 headers and libraries
|
|
||||||
#
|
|
||||||
# SDL2::SDL2 - Imported target to use for building a library
|
|
||||||
# SDL2::SDL2main - Imported interface target to use if you want SDL and SDLmain.
|
|
||||||
# SDL2_FOUND - True if SDL2 was found.
|
|
||||||
# SDL2_DYNAMIC - If we found a DLL version of SDL (meaning you might want to copy a DLL from SDL2::SDL2)
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2015 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
|
||||||
#
|
|
||||||
# Copyright Sensics, Inc. 2015.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
# Set up architectures (for windows) and prefixes (for mingw builds)
|
|
||||||
if(WIN32)
|
|
||||||
if(MINGW)
|
|
||||||
include(MinGWSearchPathExtras OPTIONAL)
|
|
||||||
if(MINGWSEARCH_TARGET_TRIPLE)
|
|
||||||
set(SDL2_PREFIX ${MINGWSEARCH_TARGET_TRIPLE})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
|
||||||
set(SDL2_LIB_PATH_SUFFIX lib/x64)
|
|
||||||
if(NOT MSVC AND NOT SDL2_PREFIX)
|
|
||||||
set(SDL2_PREFIX x86_64-w64-mingw32)
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(SDL2_LIB_PATH_SUFFIX lib/x86)
|
|
||||||
if(NOT MSVC AND NOT SDL2_PREFIX)
|
|
||||||
set(SDL2_PREFIX i686-w64-mingw32)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(SDL2_PREFIX)
|
|
||||||
set(SDL2_ORIGPREFIXPATH ${CMAKE_PREFIX_PATH})
|
|
||||||
if(SDL2_ROOT_DIR)
|
|
||||||
list(APPEND CMAKE_PREFIX_PATH "${SDL2_ROOT_DIR}")
|
|
||||||
endif()
|
|
||||||
if(CMAKE_PREFIX_PATH)
|
|
||||||
foreach(_prefix ${CMAKE_PREFIX_PATH})
|
|
||||||
list(APPEND CMAKE_PREFIX_PATH "${_prefix}/${SDL2_PREFIX}")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
if(MINGWSEARCH_PREFIXES)
|
|
||||||
list(APPEND CMAKE_PREFIX_PATH ${MINGWSEARCH_PREFIXES})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Invoke pkgconfig for hints
|
|
||||||
find_package(PkgConfig QUIET)
|
|
||||||
set(SDL2_INCLUDE_HINTS)
|
|
||||||
set(SDL2_LIB_HINTS)
|
|
||||||
if(PKG_CONFIG_FOUND)
|
|
||||||
pkg_search_module(SDL2PC QUIET sdl2)
|
|
||||||
if(SDL2PC_INCLUDE_DIRS)
|
|
||||||
set(SDL2_INCLUDE_HINTS ${SDL2PC_INCLUDE_DIRS})
|
|
||||||
endif()
|
|
||||||
if(SDL2PC_LIBRARY_DIRS)
|
|
||||||
set(SDL2_LIB_HINTS ${SDL2PC_LIBRARY_DIRS})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
|
|
||||||
find_library(SDL2_LIBRARY
|
|
||||||
NAMES
|
|
||||||
SDL2
|
|
||||||
HINTS
|
|
||||||
${SDL2_LIB_HINTS}
|
|
||||||
PATHS
|
|
||||||
${SDL2_ROOT_DIR}
|
|
||||||
ENV SDL2DIR
|
|
||||||
PATH_SUFFIXES lib SDL2 ${SDL2_LIB_PATH_SUFFIX})
|
|
||||||
|
|
||||||
set(_sdl2_framework FALSE)
|
|
||||||
# Some special-casing if we've found/been given a framework.
|
|
||||||
# Handles whether we're given the library inside the framework or the framework itself.
|
|
||||||
if(APPLE AND "${SDL2_LIBRARY}" MATCHES "(/[^/]+)*.framework(/.*)?$")
|
|
||||||
set(_sdl2_framework TRUE)
|
|
||||||
set(SDL2_FRAMEWORK "${SDL2_LIBRARY}")
|
|
||||||
# Move up in the directory tree as required to get the framework directory.
|
|
||||||
while("${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework(/.*)$" AND NOT "${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework$")
|
|
||||||
get_filename_component(SDL2_FRAMEWORK "${SDL2_FRAMEWORK}" DIRECTORY)
|
|
||||||
endwhile()
|
|
||||||
if("${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework$")
|
|
||||||
set(SDL2_FRAMEWORK_NAME ${CMAKE_MATCH_1})
|
|
||||||
# If we found a framework, do a search for the header ahead of time that will be more likely to get the framework header.
|
|
||||||
find_path(SDL2_INCLUDE_DIR
|
|
||||||
NAMES
|
|
||||||
SDL_haptic.h # this file was introduced with SDL2
|
|
||||||
HINTS
|
|
||||||
"${SDL2_FRAMEWORK}/Headers/")
|
|
||||||
else()
|
|
||||||
# For some reason we couldn't get the framework directory itself.
|
|
||||||
# Shouldn't happen, but might if something is weird.
|
|
||||||
unset(SDL2_FRAMEWORK)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_path(SDL2_INCLUDE_DIR
|
|
||||||
NAMES
|
|
||||||
SDL_haptic.h # this file was introduced with SDL2
|
|
||||||
HINTS
|
|
||||||
${SDL2_INCLUDE_HINTS}
|
|
||||||
PATHS
|
|
||||||
${SDL2_ROOT_DIR}
|
|
||||||
ENV SDL2DIR
|
|
||||||
PATH_SUFFIXES include include/sdl2 include/SDL2 SDL2)
|
|
||||||
|
|
||||||
if(WIN32 AND SDL2_LIBRARY)
|
|
||||||
find_file(SDL2_RUNTIME_LIBRARY
|
|
||||||
NAMES
|
|
||||||
SDL2.dll
|
|
||||||
libSDL2.dll
|
|
||||||
HINTS
|
|
||||||
${SDL2_LIB_HINTS}
|
|
||||||
PATHS
|
|
||||||
${SDL2_ROOT_DIR}
|
|
||||||
ENV SDL2DIR
|
|
||||||
PATH_SUFFIXES bin lib ${SDL2_LIB_PATH_SUFFIX})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
if(WIN32 OR ANDROID OR IOS OR (APPLE AND NOT _sdl2_framework))
|
|
||||||
set(SDL2_EXTRA_REQUIRED SDL2_SDLMAIN_LIBRARY)
|
|
||||||
find_library(SDL2_SDLMAIN_LIBRARY
|
|
||||||
NAMES
|
|
||||||
SDL2main
|
|
||||||
PATHS
|
|
||||||
${SDL2_ROOT_DIR}
|
|
||||||
ENV SDL2DIR
|
|
||||||
PATH_SUFFIXES lib ${SDL2_LIB_PATH_SUFFIX})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MINGW AND NOT SDL2PC_FOUND)
|
|
||||||
find_library(SDL2_MINGW_LIBRARY mingw32)
|
|
||||||
find_library(SDL2_MWINDOWS_LIBRARY mwindows)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(SDL2_PREFIX)
|
|
||||||
# Restore things the way they used to be.
|
|
||||||
set(CMAKE_PREFIX_PATH ${SDL2_ORIGPREFIXPATH})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# handle the QUIETLY and REQUIRED arguments and set QUATLIB_FOUND to TRUE if
|
|
||||||
# all listed variables are TRUE
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(SDL2
|
|
||||||
DEFAULT_MSG
|
|
||||||
SDL2_LIBRARY
|
|
||||||
SDL2_INCLUDE_DIR
|
|
||||||
${SDL2_EXTRA_REQUIRED})
|
|
||||||
|
|
||||||
if(SDL2_FOUND)
|
|
||||||
if(NOT TARGET SDL2::SDL2)
|
|
||||||
# Create SDL2::SDL2
|
|
||||||
if(WIN32 AND SDL2_RUNTIME_LIBRARY)
|
|
||||||
set(SDL2_DYNAMIC TRUE)
|
|
||||||
add_library(SDL2::SDL2 SHARED IMPORTED)
|
|
||||||
set_target_properties(SDL2::SDL2
|
|
||||||
PROPERTIES
|
|
||||||
IMPORTED_IMPLIB "${SDL2_LIBRARY}"
|
|
||||||
IMPORTED_LOCATION "${SDL2_RUNTIME_LIBRARY}"
|
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}"
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
add_library(SDL2::SDL2 UNKNOWN IMPORTED)
|
|
||||||
if(SDL2_FRAMEWORK AND SDL2_FRAMEWORK_NAME)
|
|
||||||
# Handle the case that SDL2 is a framework and we were able to decompose it above.
|
|
||||||
set_target_properties(SDL2::SDL2 PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${SDL2_FRAMEWORK}/${SDL2_FRAMEWORK_NAME}")
|
|
||||||
elseif(_sdl2_framework AND SDL2_LIBRARY MATCHES "(/[^/]+)*.framework$")
|
|
||||||
# Handle the case that SDL2 is a framework and SDL_LIBRARY is just the framework itself.
|
|
||||||
|
|
||||||
# This takes the basename of the framework, without the extension,
|
|
||||||
# and sets it (as a child of the framework) as the imported location for the target.
|
|
||||||
# This is the library symlink inside of the framework.
|
|
||||||
set_target_properties(SDL2::SDL2 PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${SDL2_LIBRARY}/${CMAKE_MATCH_1}")
|
|
||||||
else()
|
|
||||||
# Handle non-frameworks (including non-Mac), as well as the case that we're given the library inside of the framework
|
|
||||||
set_target_properties(SDL2::SDL2 PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${SDL2_LIBRARY}")
|
|
||||||
endif()
|
|
||||||
set_target_properties(SDL2::SDL2
|
|
||||||
PROPERTIES
|
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
# Need Cocoa here, is always a framework
|
|
||||||
find_library(SDL2_COCOA_LIBRARY Cocoa)
|
|
||||||
list(APPEND SDL2_EXTRA_REQUIRED SDL2_COCOA_LIBRARY)
|
|
||||||
if(SDL2_COCOA_LIBRARY)
|
|
||||||
set_target_properties(SDL2::SDL2 PROPERTIES
|
|
||||||
IMPORTED_LINK_INTERFACE_LIBRARIES ${SDL2_COCOA_LIBRARY})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
# Compute what to do with SDL2main
|
|
||||||
set(SDL2MAIN_LIBRARIES SDL2::SDL2)
|
|
||||||
add_library(SDL2::SDL2main INTERFACE IMPORTED)
|
|
||||||
if(SDL2_SDLMAIN_LIBRARY)
|
|
||||||
add_library(SDL2::SDL2main_real STATIC IMPORTED)
|
|
||||||
set_target_properties(SDL2::SDL2main_real
|
|
||||||
PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${SDL2_SDLMAIN_LIBRARY}")
|
|
||||||
set(SDL2MAIN_LIBRARIES SDL2::SDL2main_real ${SDL2MAIN_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
if(MINGW)
|
|
||||||
# MinGW requires some additional libraries to appear earlier in the link line.
|
|
||||||
if(SDL2PC_LIBRARIES)
|
|
||||||
# Use pkgconfig-suggested extra libraries if available.
|
|
||||||
list(REMOVE_ITEM SDL2PC_LIBRARIES SDL2main SDL2)
|
|
||||||
set(SDL2MAIN_LIBRARIES ${SDL2PC_LIBRARIES} ${SDL2MAIN_LIBRARIES})
|
|
||||||
else()
|
|
||||||
# fall back to extra libraries specified in pkg-config in
|
|
||||||
# an official binary distro of SDL2 for MinGW I downloaded
|
|
||||||
if(SDL2_MINGW_LIBRARY)
|
|
||||||
set(SDL2MAIN_LIBRARIES ${SDL2_MINGW_LIBRARY} ${SDL2MAIN_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
if(SDL2_MWINDOWS_LIBRARY)
|
|
||||||
set(SDL2MAIN_LIBRARIES ${SDL2_MWINDOWS_LIBRARY} ${SDL2MAIN_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
set_target_properties(SDL2::SDL2main
|
|
||||||
PROPERTIES
|
|
||||||
INTERFACE_COMPILE_DEFINITIONS "main=SDL_main")
|
|
||||||
endif()
|
|
||||||
set_target_properties(SDL2::SDL2main
|
|
||||||
PROPERTIES
|
|
||||||
INTERFACE_LINK_LIBRARIES "${SDL2MAIN_LIBRARIES}")
|
|
||||||
endif()
|
|
||||||
mark_as_advanced(SDL2_ROOT_DIR)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
mark_as_advanced(SDL2_LIBRARY
|
|
||||||
SDL2_RUNTIME_LIBRARY
|
|
||||||
SDL2_INCLUDE_DIR
|
|
||||||
SDL2_SDLMAIN_LIBRARY
|
|
||||||
SDL2_COCOA_LIBRARY
|
|
||||||
SDL2_MINGW_LIBRARY
|
|
||||||
SDL2_MWINDOWS_LIBRARY)
|
|
||||||
|
|
|
@ -6,6 +6,10 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
cmake_policy(SET CMP0079 NEW) # let target_link_libraries() link to a target defined in a different directory
|
cmake_policy(SET CMP0079 NEW) # let target_link_libraries() link to a target defined in a different directory
|
||||||
cmake_policy(SET CMP0080 OLD) # allow using BundleUtilities at configure time
|
cmake_policy(SET CMP0080 OLD) # allow using BundleUtilities at configure time
|
||||||
|
|
||||||
|
if (POLICY CMP0099)
|
||||||
|
cmake_policy(SET CMP0099 NEW) # Propagate INTERFACE_LINK_OPTIONS from private dependencies, used by MacOS framework builds of SDL
|
||||||
|
endif()
|
||||||
|
|
||||||
# Weird chicken-and-egg problem: We can't check the compiler before the project() call, but we have to set the policies before it.
|
# Weird chicken-and-egg problem: We can't check the compiler before the project() call, but we have to set the policies before it.
|
||||||
# So we do this in two steps: Set the policies if they exist, then error out afterwards if we end up being MSVC and they don't exist.
|
# So we do this in two steps: Set the policies if they exist, then error out afterwards if we end up being MSVC and they don't exist.
|
||||||
if (POLICY CMP0117)
|
if (POLICY CMP0117)
|
||||||
|
@ -693,7 +697,11 @@ endif()
|
||||||
add_subdirectory(Externals/imgui)
|
add_subdirectory(Externals/imgui)
|
||||||
add_subdirectory(Externals/implot)
|
add_subdirectory(Externals/implot)
|
||||||
add_subdirectory(Externals/glslang)
|
add_subdirectory(Externals/glslang)
|
||||||
add_subdirectory(Externals/spirv_cross)
|
# SPIRV-Cross is used on Windows for GLSL to HLSL conversion for the Direct3D 11 and Direct3D 12
|
||||||
|
# video backends, and on Apple devices for the Metal video backend.
|
||||||
|
if(WIN32 OR APPLE)
|
||||||
|
add_subdirectory(Externals/spirv_cross)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ENABLE_VULKAN)
|
if(ENABLE_VULKAN)
|
||||||
add_definitions(-DHAS_VULKAN)
|
add_definitions(-DHAS_VULKAN)
|
||||||
|
|
|
@ -499,7 +499,6 @@ a9010014 39200002
|
||||||
04456F08 C0028008
|
04456F08 C0028008
|
||||||
0445650C 3BFF0004
|
0445650C 3BFF0004
|
||||||
E2000001 80008000
|
E2000001 80008000
|
||||||
|
|
||||||
*Board animations happen faster.
|
*Board animations happen faster.
|
||||||
|
|
||||||
$QOL - Increased Capsule Throwing Speed [gamemasterplc]
|
$QOL - Increased Capsule Throwing Speed [gamemasterplc]
|
||||||
|
@ -523,7 +522,7 @@ $QOL - Instant Text Display [gamemasterplc]
|
||||||
0404a560 38000000
|
0404a560 38000000
|
||||||
*Text is displayed instantly.
|
*Text is displayed instantly.
|
||||||
|
|
||||||
$QOL - Show Controller Port Number of Who Paused in Mini-Games [gamemasterplc]
|
$QOL - Show Controller Port Number of Who Paused [gamemasterplc]
|
||||||
C2040178 00000002
|
C2040178 00000002
|
||||||
807F0050 906D0000
|
807F0050 906D0000
|
||||||
38600000 00000000
|
38600000 00000000
|
||||||
|
@ -710,30 +709,30 @@ C20C8FA0 0000001B
|
||||||
*Improves the RNG of what items are received.
|
*Improves the RNG of what items are received.
|
||||||
*Null items can be retrieved. To Dispose of throw on any space.
|
*Null items can be retrieved. To Dispose of throw on any space.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Happens on the First Turn [Nayla]
|
$Mechanics: "Last 5 Turns" Event - Happens on the First Turn [Nayla]
|
||||||
0480CB88 2C040001
|
0480CB88 2C040001
|
||||||
0408CB8C 41800048
|
0408CB8C 41800048
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is x3 Coins on Spaces [Nayla]
|
$Mechanics: "Last 5 Turns" Event - is x3 Coins on Spaces [Nayla]
|
||||||
040FB87C 38A00000
|
040FB87C 38A00000
|
||||||
040FB8EC 3A600000
|
040FB8EC 3A600000
|
||||||
*Last 5 Turns Event is always x3 Coins on Spaces.
|
*Last 5 Turns Event is always x3 Coins on Spaces.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is 5 Star Spaces [Nayla]
|
$Mechanics: "Last 5 Turns" Event - is 5 Star Spaces [Nayla]
|
||||||
040FB87C 38A00003
|
040FB87C 38A00003
|
||||||
040FB8EC 3A600003
|
040FB8EC 3A600003
|
||||||
*Last 5 Turns Event is always 5 Star Spaces.
|
*Last 5 Turns Event is always 5 Star Spaces.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is Capsule Spaces on Every Space [Nayla]
|
$Mechanics: "Last 5 Turns" Event - is All Capsule Spaces [Nayla]
|
||||||
040FB87C 38A00001
|
040FB87C 38A00001
|
||||||
040FB8EC 3A600001
|
040FB8EC 3A600001
|
||||||
*Last 5 Turns Event forces all spaces to Have Capsule Events.
|
*Last 5 Turns Event forces all spaces to Have Capsule Events.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is Disabled [Nayla]
|
$Mechanics: "Last 5 Turns" Event - is Disabled [Nayla]
|
||||||
0408D1F4 41800048
|
0408D1F4 41800048
|
||||||
*Last 5 Turns Event never happens.
|
*Last 5 Turns Event never happens.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is Red Spaces are Bowser Spaces [Nayla]
|
$Mechanics: "Last 5 Turns" Event - is Red Spaces are Bowser Spaces [Nayla]
|
||||||
040FB87C 38A00002
|
040FB87C 38A00002
|
||||||
040FB8EC 3A6000012
|
040FB8EC 3A6000012
|
||||||
*Last 5 Turns Event forces Red Spaces to turn into Bowser Spaces.
|
*Last 5 Turns Event forces Red Spaces to turn into Bowser Spaces.
|
||||||
|
@ -785,7 +784,7 @@ B00D8CD4 AAAD8CD4
|
||||||
|
|
||||||
$Mechanics - Same Space Duels Always Happen [Nayla]
|
$Mechanics - Same Space Duels Always Happen [Nayla]
|
||||||
04094740 60000000
|
04094740 60000000
|
||||||
*Duels never happen if you are on the same space.
|
*Duels always happen if you are on the same space
|
||||||
|
|
||||||
$Mechanics - Same Space Duels Don't Happen [Nayla]
|
$Mechanics - Same Space Duels Don't Happen [Nayla]
|
||||||
04094740 48000030
|
04094740 48000030
|
||||||
|
|
|
@ -508,7 +508,7 @@ $QOL - Instant Text Display [Celerizer]
|
||||||
0404f51c 38000000
|
0404f51c 38000000
|
||||||
*Text is displayed instantly.
|
*Text is displayed instantly.
|
||||||
|
|
||||||
$QOL - Show Controller Port Number of Who Paused in Mini-Games [Celerizer]
|
$QOL - Show Controller Port Number of Who Paused [Celerizer]
|
||||||
C20456D4 00000002
|
C20456D4 00000002
|
||||||
807F0050 906D0000
|
807F0050 906D0000
|
||||||
38600000 00000000
|
38600000 00000000
|
||||||
|
@ -543,6 +543,12 @@ F6000001 80008180
|
||||||
80A405A0 38800001
|
80A405A0 38800001
|
||||||
14000000 38A0FFFF
|
14000000 38A0FFFF
|
||||||
E0000000 80008000
|
E0000000 80008000
|
||||||
|
F6000002 80008180
|
||||||
|
5460D808 54640FFE
|
||||||
|
7C040050 5400283E
|
||||||
|
14000020 3C80FFFF
|
||||||
|
14000024 6084FFFF
|
||||||
|
E0000000 80008000
|
||||||
*Unlocks Everything in the game.
|
*Unlocks Everything in the game.
|
||||||
|
|
||||||
$Board - Faire Square: Free Whomps [gamemasterplc]
|
$Board - Faire Square: Free Whomps [gamemasterplc]
|
||||||
|
@ -791,7 +797,7 @@ $Mechanics - Gain 20 Coins on Blue Spaces
|
||||||
$Mechanics - Gain 40 Coins on Blue Spaces
|
$Mechanics - Gain 40 Coins on Blue Spaces
|
||||||
0415F1E8 3BC00028
|
0415F1E8 3BC00028
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Happens on the First Turn [Ralf]
|
$Mechanics: "Last 5 Turns" Event - Happens on the First Turn [Ralf]
|
||||||
06005170 0000001C
|
06005170 0000001C
|
||||||
3C608026 88835B74
|
3C608026 88835B74
|
||||||
88035B75 7C040050
|
88035B75 7C040050
|
||||||
|
@ -800,7 +806,7 @@ $Mechanics - Last 5 Turns Happens on the First Turn [Ralf]
|
||||||
0414B6C8 60000000
|
0414B6C8 60000000
|
||||||
0414B704 4BEB9A6D
|
0414B704 4BEB9A6D
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Happens after Turn 5 [Ralf]
|
$Mechanics: "Last 5 Turns" Event - Happens after Turn 5 [Ralf]
|
||||||
06005170 0000001C
|
06005170 0000001C
|
||||||
3C608026 88835B74
|
3C608026 88835B74
|
||||||
88035B75 7C040050
|
88035B75 7C040050
|
||||||
|
@ -809,24 +815,24 @@ $Mechanics - Last 5 Turns Happens after Turn 5 [Ralf]
|
||||||
0414B6C8 60000000
|
0414B6C8 60000000
|
||||||
0414B704 4BEB9A6D
|
0414B704 4BEB9A6D
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is x3 Coins on Spaces [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is x3 Coins on Spaces [gamemasterplc]
|
||||||
04202314 38000000
|
04202314 38000000
|
||||||
*Last 5 Turns Event is always x3 Coins on spaces.
|
*Last 5 Turns Event is always x3 Coins on spaces.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is 40 Coin Bonus [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is 40 Coin Bonus [gamemasterplc]
|
||||||
04202314 38000001
|
04202314 38000001
|
||||||
*Last 5 Turns Event is always a 40 coin bonus for last place.
|
*Last 5 Turns Event is always a 40 coin bonus for last place.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is 5 Character Spaces [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is 5 Character Spaces [gamemasterplc]
|
||||||
04202314 38000002 [gamemasterplc]
|
04202314 38000002 [gamemasterplc]
|
||||||
*Last 5 Turns Event is always 5 extra character spaces for last place.
|
*Last 5 Turns Event is always 5 extra character spaces for last place.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is Bowser Revolution [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is Bowser Revolution [gamemasterplc]
|
||||||
04202314 38000003
|
04202314 38000003
|
||||||
*Last 5 Turns Event is always a Bowser Revolution.
|
*Last 5 Turns Event is always a Bowser Revolution.
|
||||||
*This makes everyones coins equal.
|
*This makes everyones coins equal.
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns is Disabled [Ralf]
|
$Mechanics: "Last 5 Turns" Event - is Disabled [Ralf]
|
||||||
0414B6C8 4800007C
|
0414B6C8 4800007C
|
||||||
*Last 5 Turns event is disabled
|
*Last 5 Turns event is disabled
|
||||||
|
|
||||||
|
|
|
@ -629,7 +629,7 @@ $QOL - Instant Text Display [gamemasterplc]
|
||||||
04050a70 38800000
|
04050a70 38800000
|
||||||
*Text is displayed instantly.
|
*Text is displayed instantly.
|
||||||
|
|
||||||
$QOL - Show Controller Port Number of Who Paused in Mini-Games [gamemasterplc]
|
$QOL - Show Controller Port Number of Who Paused [gamemasterplc]
|
||||||
c2047400 00000002
|
c2047400 00000002
|
||||||
807f0050 906d0000
|
807f0050 906d0000
|
||||||
38600000 00000000
|
38600000 00000000
|
||||||
|
@ -1039,10 +1039,6 @@ $Mechanics - Hammer Bro Orb Steals 20 Coins [Ralf]
|
||||||
*Hammer Bro steals 20 coins instead of 10 when landing on his space.
|
*Hammer Bro steals 20 coins instead of 10 when landing on his space.
|
||||||
|
|
||||||
$Mechanics - Happening Star Becomes Star Star [Airsola]
|
$Mechanics - Happening Star Becomes Star Star [Airsola]
|
||||||
204e4ae0 48000210
|
|
||||||
044e4a38 48000014
|
|
||||||
044e4a6c 38000000
|
|
||||||
e2000001 80008000
|
|
||||||
204e16ec 8903001f
|
204e16ec 8903001f
|
||||||
044e16ec 8903003b
|
044e16ec 8903003b
|
||||||
e2000001 80008000
|
e2000001 80008000
|
||||||
|
@ -1050,7 +1046,6 @@ e2000001 80008000
|
||||||
044e1a0c 8903003b
|
044e1a0c 8903003b
|
||||||
e2000001 80008000
|
e2000001 80008000
|
||||||
*The Happening Star will become a bonus star awarded to the player who held the highest amount of stars at any point of the game. Recommended only for Windmillville, or Pyramid Park.
|
*The Happening Star will become a bonus star awarded to the player who held the highest amount of stars at any point of the game. Recommended only for Windmillville, or Pyramid Park.
|
||||||
*Incompatible with Fixed Bonus Star because it implements it.
|
|
||||||
|
|
||||||
$Mechanics - Improved Duel Results [Airsola]
|
$Mechanics - Improved Duel Results [Airsola]
|
||||||
c21d8ed0 00000007
|
c21d8ed0 00000007
|
||||||
|
@ -1071,38 +1066,38 @@ C21D8ED0 00000003
|
||||||
60000000 00000000
|
60000000 00000000
|
||||||
*(X) -> 1/2 Coins
|
*(X) -> 1/2 Coins
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Happens on the First Turn [Ralf]
|
$Mechanics: "Last 5 Turns" Event - Happens on the First Turn [Ralf]
|
||||||
04152070 2C040001
|
04152070 2C040001
|
||||||
04152074 4080011C
|
04152074 4080011C
|
||||||
041521AC 2C040001
|
041521AC 2C040001
|
||||||
041521B0 41800044
|
041521B0 41800044
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Happens after Turn 5 [Ralf]
|
$Mechanics: "Last 5 Turns" Event - Happens after Turn 5 [Ralf]
|
||||||
04152070 2C040006
|
04152070 2C040006
|
||||||
04152074 4080011C
|
04152074 4080011C
|
||||||
041521AC 2C040006
|
041521AC 2C040006
|
||||||
041521B0 41800044
|
041521B0 41800044
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Always x3 Coins on Spaces [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is x3 Coins on Spaces [gamemasterplc]
|
||||||
042311A8 38000000
|
042311A8 38000000
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Always 10 More Koopa Kid Spaces [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is Always 10 More Koopa Kid Spaces [gamemasterplc]
|
||||||
042311A8 38000001
|
042311A8 38000001
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Always 40 Coin Bonus [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is Always 40 Coin Bonus [gamemasterplc]
|
||||||
042311A8 38000002
|
042311A8 38000002
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Always Stars are 10 Coins [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is Always Stars are 10 Coins [gamemasterplc]
|
||||||
042311A8 38000003
|
042311A8 38000003
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Always Red Spaces are Bowser Spaces [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is Always Red Spaces are Bowser Spaces [gamemasterplc]
|
||||||
042311A8 38000004
|
042311A8 38000004
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Always Chain Chomp Ride for 5 Coins (Pyramid Park) [gamemasterplc]
|
$Mechanics: "Last 5 Turns" Event - is Always Chain Chomp Ride for 5 Coins (Pyramid Park) [gamemasterplc]
|
||||||
042311A8 38000005
|
042311A8 38000005
|
||||||
*Only use on Pyramid Park
|
*Only use on Pyramid Park
|
||||||
|
|
||||||
$Mechanics - Last 5 Turns Event Is Disabled [Ralf]
|
$Mechanics: "Last 5 Turns" Event - is Disabled [Ralf]
|
||||||
04152074 60000000
|
04152074 60000000
|
||||||
041521B0 48000044
|
041521B0 48000044
|
||||||
|
|
||||||
|
@ -1137,10 +1132,6 @@ $Mechanics - Microphone Always Off [gamemasterplc]
|
||||||
*Microphone game setting stays off while playing Mario Party 7.
|
*Microphone game setting stays off while playing Mario Party 7.
|
||||||
|
|
||||||
$Mechanics - Orb Star Becomes Coin Star [Airsola]
|
$Mechanics - Orb Star Becomes Coin Star [Airsola]
|
||||||
204e4ae0 48000210
|
|
||||||
044e4a38 48000014
|
|
||||||
044e4a6c 38000000
|
|
||||||
e2000001 80008000
|
|
||||||
204e16b0 a8ca003c
|
204e16b0 a8ca003c
|
||||||
044e16b0 a8ca002c
|
044e16b0 a8ca002c
|
||||||
e2000001 80008000
|
e2000001 80008000
|
||||||
|
@ -1148,8 +1139,6 @@ e2000001 80008000
|
||||||
044e18d4 a8c3002c
|
044e18d4 a8c3002c
|
||||||
e2000001 80008000
|
e2000001 80008000
|
||||||
*The return of the classic Coin Star.
|
*The return of the classic Coin Star.
|
||||||
*Incompatible with Fixed Bonus Star because it implements it.
|
|
||||||
|
|
||||||
|
|
||||||
$Mechanics - Orbs Can Only Be Placed On Your Current Space [gamemasterplc]
|
$Mechanics - Orbs Can Only Be Placed On Your Current Space [gamemasterplc]
|
||||||
041e7128 60000000
|
041e7128 60000000
|
||||||
|
@ -1162,7 +1151,7 @@ $Mechanics - Piranha Plant Takes ALL Coins [gamemasterplc]
|
||||||
$Mechanics - Slow Shroom Orb Rolls 1-3 [gamemasterplc]
|
$Mechanics - Slow Shroom Orb Rolls 1-3 [gamemasterplc]
|
||||||
0418CCC8 38000003
|
0418CCC8 38000003
|
||||||
0418D1AC 40820020
|
0418D1AC 40820020
|
||||||
*Orb is morew balanced.
|
*Orb is more balanced.
|
||||||
|
|
||||||
$Mechanics - Slow Shroom Orb Rolls 1-5 [gamemasterplc]
|
$Mechanics - Slow Shroom Orb Rolls 1-5 [gamemasterplc]
|
||||||
0418ccc8 38000005
|
0418ccc8 38000005
|
||||||
|
@ -1172,7 +1161,6 @@ $Mechanics - Slow Shroom Orb Rolls 1-5 [gamemasterplc]
|
||||||
$Mechanics - Stars Cost 40 coins [Ralf]
|
$Mechanics - Stars Cost 40 coins [Ralf]
|
||||||
0418876c 3b800005
|
0418876c 3b800005
|
||||||
04188774 3b80000A
|
04188774 3b80000A
|
||||||
|
|
||||||
*Only works in Grand Canal and Bowser's Enchanted Inferno
|
*Only works in Grand Canal and Bowser's Enchanted Inferno
|
||||||
|
|
||||||
$Mechanics - Use Multiple Orbs in the Same Turn [Ralf]
|
$Mechanics - Use Multiple Orbs in the Same Turn [Ralf]
|
||||||
|
@ -1229,7 +1217,7 @@ $Minigame: La Bomba - Always 4 Bombs [Airsola, Rain]
|
||||||
044e8cf4 00000004
|
044e8cf4 00000004
|
||||||
e2000001 80008000
|
e2000001 80008000
|
||||||
|
|
||||||
$Minigame: Jump Man - Player is Slower
|
$Minigame: Jump Man - Player is Slower [gamemasterplc]
|
||||||
204EF0C0 40768000
|
204EF0C0 40768000
|
||||||
044EF0B8 3C430C12
|
044EF0B8 3C430C12
|
||||||
E2000001 80008000
|
E2000001 80008000
|
||||||
|
@ -1263,7 +1251,7 @@ $Minigame: Target Tag - All Targets Worth 50 Points [gamemasterplc]
|
||||||
044EAC28 38800032
|
044EAC28 38800032
|
||||||
E2000001 80008000
|
E2000001 80008000
|
||||||
|
|
||||||
$Minigame: Vine Country - DK is Faster
|
$Minigame: Vine Country - DK is Faster [gamemasterplc]
|
||||||
204E5EE8 901F0174
|
204E5EE8 901F0174
|
||||||
044E5EE4 3803FFFE
|
044E5EE4 3803FFFE
|
||||||
E2000001 80008000
|
E2000001 80008000
|
||||||
|
|
2
Externals/MoltenVK/CMakeLists.txt
vendored
2
Externals/MoltenVK/CMakeLists.txt
vendored
|
@ -1,6 +1,6 @@
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
|
|
||||||
set(MOLTENVK_VERSION "v1.2.2")
|
set(MOLTENVK_VERSION "v1.2.3")
|
||||||
|
|
||||||
ExternalProject_Add(MoltenVK
|
ExternalProject_Add(MoltenVK
|
||||||
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
|
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
|
||||||
|
|
2
Externals/SDL/SDL
vendored
2
Externals/SDL/SDL
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit f741adc86c8f5e7fc5c1863cf0d5e08b899d6209
|
Subproject commit ac13ca9ab691e13e8eebe9684740ddcb0d716203
|
2
Externals/rcheevos/rcheevos
vendored
2
Externals/rcheevos/rcheevos
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit c5304a61bcf256ae80fcd1c8f64ad9646aaea757
|
Subproject commit d9e990e6d13527532b7e2bb23164a1f3b7f33bb5
|
|
@ -1,6 +1,6 @@
|
||||||
# Dolphin - A GameCube and Wii Emulator
|
# Dolphin - A GameCube and Wii Emulator
|
||||||
|
|
||||||
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci/) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://explore.transifex.com/delroth/dolphin-emu/)
|
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci/) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://app.transifex.com/delroth/dolphin-emu/dashboard/)
|
||||||
|
|
||||||
Dolphin is an emulator for running GameCube and Wii games on Windows,
|
Dolphin is an emulator for running GameCube and Wii games on Windows,
|
||||||
Linux, macOS, and recent Android devices. It's licensed under the terms
|
Linux, macOS, and recent Android devices. It's licensed under the terms
|
||||||
|
|
|
@ -40,7 +40,6 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO If this is ever modified, change application_id in strings.xml
|
|
||||||
applicationId "org.dolphinemu.dolphinemu"
|
applicationId "org.dolphinemu.dolphinemu"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 33
|
targetSdkVersion 33
|
||||||
|
@ -74,6 +73,7 @@ android {
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resValue 'string', 'app_name_suffixed', 'Dolphin Emulator'
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources true
|
||||||
proguardFiles getDefaultProguardFile(
|
proguardFiles getDefaultProguardFile(
|
||||||
|
@ -86,13 +86,14 @@ android {
|
||||||
// Signed by debug key disallowing distribution on Play Store.
|
// Signed by debug key disallowing distribution on Play Store.
|
||||||
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
|
||||||
debug {
|
debug {
|
||||||
// TODO If this is ever modified, change application_id in debug/strings.xml
|
resValue 'string', 'app_name_suffixed', 'Dolphin Debug'
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
versionNameSuffix '-debug'
|
versionNameSuffix '-debug'
|
||||||
jniDebuggable true
|
jniDebuggable true
|
||||||
}
|
}
|
||||||
|
|
||||||
benchmark {
|
benchmark {
|
||||||
|
resValue 'string', 'app_name_suffixed', 'Dolphin Benchmark'
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
matchingFallbacks = ['release']
|
matchingFallbacks = ['release']
|
||||||
debuggable false
|
debuggable false
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".DolphinApplication"
|
android:name=".DolphinApplication"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name_suffixed"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:preserveLegacyExternalStorage="true"
|
android:preserveLegacyExternalStorage="true"
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.CustomFilePickerActivity"
|
android:name=".activities.CustomFilePickerActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name_suffixed"
|
||||||
android:theme="@style/Theme.Dolphin.FilePicker">
|
android:theme="@style/Theme.Dolphin.FilePicker">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
|
@ -54,12 +54,11 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
|
|
||||||
override fun queryRoots(projection: Array<String>?): Cursor {
|
override fun queryRoots(projection: Array<String>?): Cursor {
|
||||||
val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION)
|
val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION)
|
||||||
rootDirectory = rootDirectory ?: DirectoryInitialization.getUserDirectoryPath(context)
|
|
||||||
rootDirectory ?: return result
|
rootDirectory ?: return result
|
||||||
|
|
||||||
result.newRow().apply {
|
result.newRow().apply {
|
||||||
add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID)
|
add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID)
|
||||||
add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name))
|
add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name_suffixed))
|
||||||
add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dolphin)
|
add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dolphin)
|
||||||
add(
|
add(
|
||||||
DocumentsContract.Root.COLUMN_FLAGS,
|
DocumentsContract.Root.COLUMN_FLAGS,
|
||||||
|
@ -73,7 +72,6 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
|
|
||||||
override fun queryDocument(documentId: String, projection: Array<String>?): Cursor {
|
override fun queryDocument(documentId: String, projection: Array<String>?): Cursor {
|
||||||
val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION)
|
val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION)
|
||||||
rootDirectory = rootDirectory ?: DirectoryInitialization.getUserDirectoryPath(context)
|
|
||||||
rootDirectory ?: return result
|
rootDirectory ?: return result
|
||||||
val file = documentIdToPath(documentId)
|
val file = documentIdToPath(documentId)
|
||||||
appendDocument(file, result)
|
appendDocument(file, result)
|
||||||
|
@ -102,7 +100,9 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
documentId: String,
|
documentId: String,
|
||||||
mode: String,
|
mode: String,
|
||||||
signal: CancellationSignal?
|
signal: CancellationSignal?
|
||||||
): ParcelFileDescriptor {
|
): ParcelFileDescriptor? {
|
||||||
|
rootDirectory ?: return null
|
||||||
|
|
||||||
val file = documentIdToPath(documentId)
|
val file = documentIdToPath(documentId)
|
||||||
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))
|
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,9 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
parentDocumentId: String,
|
parentDocumentId: String,
|
||||||
mimeType: String,
|
mimeType: String,
|
||||||
displayName: String
|
displayName: String
|
||||||
): String {
|
): String? {
|
||||||
|
rootDirectory ?: return null
|
||||||
|
|
||||||
val folder = documentIdToPath(parentDocumentId)
|
val folder = documentIdToPath(parentDocumentId)
|
||||||
val file = findFileNameForNewFile(File(folder, displayName))
|
val file = findFileNameForNewFile(File(folder, displayName))
|
||||||
if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
|
if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
|
||||||
|
@ -122,56 +124,40 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
return pathToDocumentId(file)
|
return pathToDocumentId(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copyDocument(sourceDocumentId: String, targetParentDocumentId: String): String {
|
override fun deleteDocument(documentId: String) {
|
||||||
val file = documentIdToPath(sourceDocumentId)
|
rootDirectory ?: return
|
||||||
val target = documentIdToPath(targetParentDocumentId)
|
|
||||||
val copy = copyRecursively(file, File(target, file.name))
|
|
||||||
return pathToDocumentId(copy)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeDocument(documentId: String, parentDocumentId: String) {
|
|
||||||
val file = documentIdToPath(documentId)
|
val file = documentIdToPath(documentId)
|
||||||
file.deleteRecursively()
|
file.deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun moveDocument(
|
override fun renameDocument(documentId: String, displayName: String): String? {
|
||||||
sourceDocumentId: String,
|
rootDirectory ?: return null
|
||||||
sourceParentDocumentId: String,
|
|
||||||
targetParentDocumentId: String
|
val file = documentIdToPath(documentId)
|
||||||
): String {
|
val dest = findFileNameForNewFile(File(file.parentFile, displayName))
|
||||||
val copy = copyDocument(sourceDocumentId, targetParentDocumentId)
|
file.renameTo(dest)
|
||||||
val file = documentIdToPath(sourceDocumentId)
|
return pathToDocumentId(dest)
|
||||||
file.delete()
|
|
||||||
return copy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun renameDocument(documentId: String, displayName: String): String {
|
override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean
|
||||||
val file = documentIdToPath(documentId)
|
= documentId.startsWith(parentDocumentId)
|
||||||
file.renameTo(findFileNameForNewFile(File(file.parentFile, displayName)))
|
|
||||||
return pathToDocumentId(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean {
|
|
||||||
val file = documentIdToPath(documentId)
|
|
||||||
val folder = documentIdToPath(parentDocumentId)
|
|
||||||
return file.relativeToOrNull(folder) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun appendDocument(file: File, cursor: MatrixCursor) {
|
private fun appendDocument(file: File, cursor: MatrixCursor) {
|
||||||
var flags = 0
|
var flags = 0
|
||||||
if (file.isDirectory && file.canWrite()) {
|
if (file.canWrite()) {
|
||||||
flags = DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE
|
flags = if (file.isDirectory) {
|
||||||
} else if (file.canWrite()) {
|
DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE
|
||||||
flags = DocumentsContract.Document.FLAG_SUPPORTS_WRITE
|
} else {
|
||||||
|
DocumentsContract.Document.FLAG_SUPPORTS_WRITE
|
||||||
|
}
|
||||||
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_DELETE
|
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_DELETE
|
||||||
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_REMOVE
|
|
||||||
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_MOVE
|
|
||||||
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_COPY
|
|
||||||
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_RENAME
|
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_RENAME
|
||||||
|
// The system will handle copy + move for us
|
||||||
}
|
}
|
||||||
|
|
||||||
val name = if (file == rootDirectory) {
|
val name = if (file == rootDirectory) {
|
||||||
context!!.getString(R.string.app_name)
|
context!!.getString(R.string.app_name_suffixed)
|
||||||
} else {
|
} else {
|
||||||
file.name
|
file.name
|
||||||
}
|
}
|
||||||
|
@ -217,22 +203,6 @@ class DocumentProvider : DocumentsProvider() {
|
||||||
unusedFile = File("$pathWithoutExtension.$i.$extension")
|
unusedFile = File("$pathWithoutExtension.$i.$extension")
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return file
|
return unusedFile
|
||||||
}
|
|
||||||
|
|
||||||
private fun copyRecursively(src: File, dst: File): File {
|
|
||||||
val actualDst = findFileNameForNewFile(dst)
|
|
||||||
if (src.isDirectory) {
|
|
||||||
actualDst.mkdirs()
|
|
||||||
val children = src.listFiles()
|
|
||||||
if (children !== null) {
|
|
||||||
for (file in children) {
|
|
||||||
copyRecursively(file, File(actualDst, file.name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
src.copyTo(actualDst)
|
|
||||||
}
|
|
||||||
return actualDst
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ public final class MainActivity extends AppCompatActivity
|
||||||
setInsets();
|
setInsets();
|
||||||
ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain);
|
ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain);
|
||||||
|
|
||||||
|
mBinding.toolbarMain.setTitle(R.string.app_name);
|
||||||
setSupportActionBar(mBinding.toolbarMain);
|
setSupportActionBar(mBinding.toolbarMain);
|
||||||
|
|
||||||
// Set up the FAB.
|
// Set up the FAB.
|
||||||
|
|
|
@ -137,12 +137,12 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_loadCodes(JNIEnv* e
|
||||||
jint revision)
|
jint revision)
|
||||||
{
|
{
|
||||||
const std::string game_id = GetJString(env, jGameID);
|
const std::string game_id = GetJString(env, jGameID);
|
||||||
IniFile game_ini_local;
|
Common::IniFile game_ini_local;
|
||||||
|
|
||||||
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
|
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
|
||||||
// will always be stored in GS/${GAMEID}.ini
|
// will always be stored in GS/${GAMEID}.ini
|
||||||
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
|
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
|
||||||
const IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
|
const Common::IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
|
||||||
|
|
||||||
const std::vector<ActionReplay::ARCode> codes =
|
const std::vector<ActionReplay::ARCode> codes =
|
||||||
ActionReplay::LoadCodes(game_ini_default, game_ini_local);
|
ActionReplay::LoadCodes(game_ini_default, game_ini_local);
|
||||||
|
@ -167,7 +167,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCh
|
||||||
const std::string game_id = GetJString(env, jGameID);
|
const std::string game_id = GetJString(env, jGameID);
|
||||||
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
|
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
|
||||||
|
|
||||||
IniFile game_ini_local;
|
Common::IniFile game_ini_local;
|
||||||
game_ini_local.Load(ini_path);
|
game_ini_local.Load(ini_path);
|
||||||
ActionReplay::SaveCodes(&game_ini_local, vector);
|
ActionReplay::SaveCodes(&game_ini_local, vector);
|
||||||
game_ini_local.Save(ini_path);
|
game_ini_local.Save(ini_path);
|
||||||
|
|
|
@ -146,12 +146,12 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_loadCodes(JNIEnv
|
||||||
jint revision)
|
jint revision)
|
||||||
{
|
{
|
||||||
const std::string game_id = GetJString(env, jGameID);
|
const std::string game_id = GetJString(env, jGameID);
|
||||||
IniFile game_ini_local;
|
Common::IniFile game_ini_local;
|
||||||
|
|
||||||
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
|
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
|
||||||
// will always be stored in GS/${GAMEID}.ini
|
// will always be stored in GS/${GAMEID}.ini
|
||||||
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
|
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
|
||||||
const IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
|
const Common::IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
|
||||||
|
|
||||||
const std::vector<Gecko::GeckoCode> codes = Gecko::LoadCodes(game_ini_default, game_ini_local);
|
const std::vector<Gecko::GeckoCode> codes = Gecko::LoadCodes(game_ini_default, game_ini_local);
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_Geck
|
||||||
const std::string game_id = GetJString(env, jGameID);
|
const std::string game_id = GetJString(env, jGameID);
|
||||||
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
|
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
|
||||||
|
|
||||||
IniFile game_ini_local;
|
Common::IniFile game_ini_local;
|
||||||
game_ini_local.Load(ini_path);
|
game_ini_local.Load(ini_path);
|
||||||
Gecko::SaveCodes(game_ini_local, vector);
|
Gecko::SaveCodes(game_ini_local, vector);
|
||||||
game_ini_local.Save(ini_path);
|
game_ini_local.Save(ini_path);
|
||||||
|
|
|
@ -124,12 +124,12 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_loadCodes(JNIEnv
|
||||||
jint revision)
|
jint revision)
|
||||||
{
|
{
|
||||||
const std::string game_id = GetJString(env, jGameID);
|
const std::string game_id = GetJString(env, jGameID);
|
||||||
IniFile game_ini_local;
|
Common::IniFile game_ini_local;
|
||||||
|
|
||||||
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
|
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
|
||||||
// will always be stored in GS/${GAMEID}.ini
|
// will always be stored in GS/${GAMEID}.ini
|
||||||
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
|
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
|
||||||
const IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
|
const Common::IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
|
||||||
|
|
||||||
std::vector<PatchEngine::Patch> patches;
|
std::vector<PatchEngine::Patch> patches;
|
||||||
PatchEngine::LoadPatchSection("OnFrame", &patches, game_ini_default, game_ini_local);
|
PatchEngine::LoadPatchSection("OnFrame", &patches, game_ini_default, game_ini_local);
|
||||||
|
@ -154,7 +154,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_Patc
|
||||||
const std::string game_id = GetJString(env, jGameID);
|
const std::string game_id = GetJString(env, jGameID);
|
||||||
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
|
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
|
||||||
|
|
||||||
IniFile game_ini_local;
|
Common::IniFile game_ini_local;
|
||||||
game_ini_local.Load(ini_path);
|
game_ini_local.Load(ini_path);
|
||||||
PatchEngine::SavePatchSection(&game_ini_local, vector);
|
PatchEngine::SavePatchSection(&game_ini_local, vector);
|
||||||
game_ini_local.Save(ini_path);
|
game_ini_local.Save(ini_path);
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "jni/AndroidCommon/AndroidCommon.h"
|
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||||
#include "jni/AndroidCommon/IDCache.h"
|
#include "jni/AndroidCommon/IDCache.h"
|
||||||
|
|
||||||
|
using Common::IniFile;
|
||||||
|
|
||||||
static IniFile::Section* GetSectionPointer(JNIEnv* env, jobject obj)
|
static IniFile::Section* GetSectionPointer(JNIEnv* env, jobject obj)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<IniFile::Section*>(
|
return reinterpret_cast<IniFile::Section*>(
|
||||||
|
|
|
@ -91,7 +91,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro
|
||||||
ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj);
|
ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj);
|
||||||
|
|
||||||
// Loading an empty IniFile section clears everything.
|
// Loading an empty IniFile section clears everything.
|
||||||
IniFile::Section section;
|
Common::IniFile::Section section;
|
||||||
|
|
||||||
controller->LoadConfig(§ion);
|
controller->LoadConfig(§ion);
|
||||||
controller->UpdateReferences(g_controller_interface);
|
controller->UpdateReferences(g_controller_interface);
|
||||||
|
@ -103,7 +103,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro
|
||||||
{
|
{
|
||||||
ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj);
|
ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj);
|
||||||
|
|
||||||
IniFile ini;
|
Common::IniFile ini;
|
||||||
ini.Load(GetJString(env, j_path));
|
ini.Load(GetJString(env, j_path));
|
||||||
|
|
||||||
controller->LoadConfig(ini.GetOrCreateSection("Profile"));
|
controller->LoadConfig(ini.GetOrCreateSection("Profile"));
|
||||||
|
@ -118,7 +118,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro
|
||||||
|
|
||||||
File::CreateFullPath(path);
|
File::CreateFullPath(path);
|
||||||
|
|
||||||
IniFile ini;
|
Common::IniFile ini;
|
||||||
|
|
||||||
EmulatedControllerFromJava(env, obj)->SaveConfig(ini.GetOrCreateSection("Profile"));
|
EmulatedControllerFromJava(env, obj)->SaveConfig(ini.GetOrCreateSection("Profile"));
|
||||||
ini.Save(path);
|
ini.Save(path);
|
||||||
|
|
|
@ -3092,7 +3092,7 @@ void ARM64FloatEmitter::FMOV(ARM64Reg Rd, uint8_t imm8)
|
||||||
// Vector
|
// Vector
|
||||||
void ARM64FloatEmitter::ADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
|
void ARM64FloatEmitter::ADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
|
||||||
{
|
{
|
||||||
EmitThreeSame(0, IntLog2(size) - 3, 0b10000, Rd, Rn, Rm);
|
EmitThreeSame(0, MathUtil::IntLog2(size) - 3, 0b10000, Rd, Rn, Rm);
|
||||||
}
|
}
|
||||||
void ARM64FloatEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
|
void ARM64FloatEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,8 +41,8 @@ add_library(common
|
||||||
DebugInterface.h
|
DebugInterface.h
|
||||||
DynamicLibrary.cpp
|
DynamicLibrary.cpp
|
||||||
DynamicLibrary.h
|
DynamicLibrary.h
|
||||||
ENetUtil.cpp
|
ENet.cpp
|
||||||
ENetUtil.h
|
ENet.h
|
||||||
EnumFormatter.h
|
EnumFormatter.h
|
||||||
EnumMap.h
|
EnumMap.h
|
||||||
Event.h
|
Event.h
|
||||||
|
@ -80,7 +80,6 @@ add_library(common
|
||||||
Logging/Log.h
|
Logging/Log.h
|
||||||
Logging/LogManager.cpp
|
Logging/LogManager.cpp
|
||||||
Logging/LogManager.h
|
Logging/LogManager.h
|
||||||
MathUtil.cpp
|
|
||||||
MathUtil.h
|
MathUtil.h
|
||||||
Matrix.cpp
|
Matrix.cpp
|
||||||
Matrix.h
|
Matrix.h
|
||||||
|
@ -299,7 +298,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
target_link_libraries(common PUBLIC dl rt)
|
target_link_libraries(common PUBLIC dl rt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
if(WIN32)
|
||||||
target_sources(common PRIVATE HRWrap.h HRWrap.cpp)
|
target_sources(common PRIVATE HRWrap.h HRWrap.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#define strerror_r(err, buf, len) strerror_s(buf, len, err)
|
#define strerror_r(err, buf, len) strerror_s(buf, len, err)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
constexpr size_t BUFFER_SIZE = 256;
|
constexpr size_t BUFFER_SIZE = 256;
|
||||||
|
|
||||||
// Wrapper function to get last strerror(errno) string.
|
// Wrapper function to get last strerror(errno) string.
|
||||||
|
@ -73,3 +75,4 @@ std::optional<std::wstring> GetModuleName(void* hInstance)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace Common
|
||||||
|
|
|
@ -39,6 +39,8 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||||
}
|
}
|
||||||
#endif // WIN32 ndef
|
#endif // WIN32 ndef
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
// Wrapper function to get last strerror(errno) string.
|
// Wrapper function to get last strerror(errno) string.
|
||||||
// This function might change the error code.
|
// This function might change the error code.
|
||||||
std::string LastStrerrorString();
|
std::string LastStrerrorString();
|
||||||
|
@ -51,3 +53,4 @@ std::string GetLastErrorString();
|
||||||
// Obtains a full path to the specified module.
|
// Obtains a full path to the specified module.
|
||||||
std::optional<std::wstring> GetModuleName(void* hInstance);
|
std::optional<std::wstring> GetModuleName(void* hInstance);
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace Common
|
||||||
|
|
|
@ -170,7 +170,7 @@ static std::optional<std::wstring> GetModulePath(const wchar_t* name)
|
||||||
if (module == nullptr)
|
if (module == nullptr)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
return GetModuleName(module);
|
return Common::GetModuleName(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetModuleVersion(const wchar_t* name, Version* version)
|
static bool GetModuleVersion(const wchar_t* name, Version* version)
|
||||||
|
|
|
@ -3,42 +3,45 @@
|
||||||
|
|
||||||
#include "Common/Crypto/bn.h"
|
#include "Common/Crypto/bn.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
static void bn_zero(u8* d, int n)
|
static void bn_zero(u8* d, const size_t n)
|
||||||
{
|
{
|
||||||
std::memset(d, 0, n);
|
std::memset(d, 0, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bn_copy(u8* d, const u8* a, int n)
|
static void bn_copy(u8* d, const u8* a, const size_t n)
|
||||||
{
|
{
|
||||||
std::memcpy(d, a, n);
|
std::memcpy(d, a, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bn_compare(const u8* a, const u8* b, int n)
|
int bn_compare(const u8* a, const u8* b, const size_t n)
|
||||||
{
|
{
|
||||||
return std::memcmp(a, b, n);
|
return std::memcmp(a, b, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bn_sub_modulus(u8* a, const u8* N, int n)
|
void bn_sub_modulus(u8* a, const u8* N, const size_t n)
|
||||||
{
|
{
|
||||||
u8 c = 0;
|
u8 c = 0;
|
||||||
for (int i = n - 1; i >= 0; --i)
|
for (size_t i = n; i > 0;)
|
||||||
{
|
{
|
||||||
|
--i;
|
||||||
u32 dig = N[i] + c;
|
u32 dig = N[i] + c;
|
||||||
c = (a[i] < dig);
|
c = (a[i] < dig);
|
||||||
a[i] -= dig;
|
a[i] -= dig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n)
|
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, const size_t n)
|
||||||
{
|
{
|
||||||
u8 c = 0;
|
u8 c = 0;
|
||||||
for (int i = n - 1; i >= 0; --i)
|
for (size_t i = n; i > 0;)
|
||||||
{
|
{
|
||||||
|
--i;
|
||||||
u32 dig = a[i] + b[i] + c;
|
u32 dig = a[i] + b[i] + c;
|
||||||
c = (dig >= 0x100);
|
c = (dig >= 0x100);
|
||||||
d[i] = dig;
|
d[i] = dig;
|
||||||
|
@ -51,11 +54,11 @@ void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n)
|
||||||
bn_sub_modulus(d, N, n);
|
bn_sub_modulus(d, N, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n)
|
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, const size_t n)
|
||||||
{
|
{
|
||||||
bn_zero(d, n);
|
bn_zero(d, n);
|
||||||
|
|
||||||
for (int i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
for (u8 mask = 0x80; mask != 0; mask >>= 1)
|
for (u8 mask = 0x80; mask != 0; mask >>= 1)
|
||||||
{
|
{
|
||||||
|
@ -66,13 +69,13 @@ void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en)
|
void bn_exp(u8* d, const u8* a, const u8* N, const size_t n, const u8* e, const size_t en)
|
||||||
{
|
{
|
||||||
u8 t[512];
|
u8 t[512];
|
||||||
|
|
||||||
bn_zero(d, n);
|
bn_zero(d, n);
|
||||||
d[n - 1] = 1;
|
d[n - 1] = 1;
|
||||||
for (int i = 0; i < en; i++)
|
for (size_t i = 0; i < en; i++)
|
||||||
{
|
{
|
||||||
for (u8 mask = 0x80; mask != 0; mask >>= 1)
|
for (u8 mask = 0x80; mask != 0; mask >>= 1)
|
||||||
{
|
{
|
||||||
|
@ -86,7 +89,7 @@ void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en)
|
||||||
}
|
}
|
||||||
|
|
||||||
// only for prime N -- stupid but lazy, see if I care
|
// only for prime N -- stupid but lazy, see if I care
|
||||||
void bn_inv(u8* d, const u8* a, const u8* N, int n)
|
void bn_inv(u8* d, const u8* a, const u8* N, const size_t n)
|
||||||
{
|
{
|
||||||
u8 t[512], s[512];
|
u8 t[512], s[512];
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
// bignum arithmetic
|
// bignum arithmetic
|
||||||
|
|
||||||
int bn_compare(const u8* a, const u8* b, int n);
|
int bn_compare(const u8* a, const u8* b, size_t n);
|
||||||
void bn_sub_modulus(u8* a, const u8* N, int n);
|
void bn_sub_modulus(u8* a, const u8* N, size_t n);
|
||||||
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n);
|
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, size_t n);
|
||||||
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n);
|
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, size_t n);
|
||||||
void bn_inv(u8* d, const u8* a, const u8* N, int n); // only for prime N
|
void bn_inv(u8* d, const u8* a, const u8* N, size_t n); // only for prime N
|
||||||
void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en);
|
void bn_exp(u8* d, const u8* a, const u8* N, size_t n, const u8* e, size_t en);
|
||||||
|
|
|
@ -126,16 +126,18 @@ InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& ins
|
||||||
TraceOutput CodeTrace::SaveCurrentInstruction(const Core::CPUThreadGuard& guard) const
|
TraceOutput CodeTrace::SaveCurrentInstruction(const Core::CPUThreadGuard& guard) const
|
||||||
{
|
{
|
||||||
auto& system = guard.GetSystem();
|
auto& system = guard.GetSystem();
|
||||||
auto& ppc_state = system.GetPPCState();
|
auto& power_pc = system.GetPowerPC();
|
||||||
|
auto& ppc_state = power_pc.GetPPCState();
|
||||||
|
auto& debug_interface = power_pc.GetDebugInterface();
|
||||||
|
|
||||||
// Quickly save instruction and memory target for fast logging.
|
// Quickly save instruction and memory target for fast logging.
|
||||||
TraceOutput output;
|
TraceOutput output;
|
||||||
const std::string instr = PowerPC::debug_interface.Disassemble(&guard, ppc_state.pc);
|
const std::string instr = debug_interface.Disassemble(&guard, ppc_state.pc);
|
||||||
output.instruction = instr;
|
output.instruction = instr;
|
||||||
output.address = ppc_state.pc;
|
output.address = ppc_state.pc;
|
||||||
|
|
||||||
if (IsInstructionLoadStore(output.instruction))
|
if (IsInstructionLoadStore(output.instruction))
|
||||||
output.memory_target = PowerPC::debug_interface.GetMemoryAddressFromInstruction(instr);
|
output.memory_target = debug_interface.GetMemoryAddressFromInstruction(instr);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -189,16 +191,17 @@ AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool
|
||||||
else if (stop_on == AutoStop::Changed)
|
else if (stop_on == AutoStop::Changed)
|
||||||
stop_condition = HitType::ACTIVE;
|
stop_condition = HitType::ACTIVE;
|
||||||
|
|
||||||
PowerPC::breakpoints.ClearAllTemporary();
|
auto& power_pc = guard.GetSystem().GetPowerPC();
|
||||||
|
power_pc.GetBreakPoints().ClearAllTemporary();
|
||||||
using clock = std::chrono::steady_clock;
|
using clock = std::chrono::steady_clock;
|
||||||
clock::time_point timeout = clock::now() + std::chrono::seconds(4);
|
clock::time_point timeout = clock::now() + std::chrono::seconds(4);
|
||||||
|
|
||||||
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
PowerPC::CoreMode old_mode = power_pc.GetMode();
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
power_pc.SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
PowerPC::SingleStep();
|
power_pc.SingleStep();
|
||||||
|
|
||||||
pc_instr = SaveCurrentInstruction(guard);
|
pc_instr = SaveCurrentInstruction(guard);
|
||||||
hit = TraceLogic(pc_instr);
|
hit = TraceLogic(pc_instr);
|
||||||
|
@ -210,7 +213,7 @@ AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool
|
||||||
if (clock::now() >= timeout)
|
if (clock::now() >= timeout)
|
||||||
results.timed_out = true;
|
results.timed_out = true;
|
||||||
|
|
||||||
PowerPC::SetMode(old_mode);
|
power_pc.SetMode(old_mode);
|
||||||
m_recording = false;
|
m_recording = false;
|
||||||
|
|
||||||
results.reg_tracked = m_reg_autotrack;
|
results.reg_tracked = m_reg_autotrack;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright 2015 Dolphin Emulator Project
|
// Copyright 2015 Dolphin Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "Common/ENetUtil.h"
|
#include "Common/ENet.h"
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
namespace ENetUtil
|
namespace Common::ENet
|
||||||
{
|
{
|
||||||
void WakeupThread(ENetHost* host)
|
void WakeupThread(ENetHost* host)
|
||||||
{
|
{
|
||||||
|
@ -62,4 +62,4 @@ bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace ENetUtil
|
} // namespace Common::ENet
|
|
@ -3,15 +3,22 @@
|
||||||
//
|
//
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <enet/enet.h>
|
#include <memory>
|
||||||
|
|
||||||
#include <SFML/Network/Packet.hpp>
|
#include <SFML/Network/Packet.hpp>
|
||||||
|
#include <enet/enet.h>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
namespace ENetUtil
|
namespace Common::ENet
|
||||||
{
|
{
|
||||||
|
struct ENetHostDeleter
|
||||||
|
{
|
||||||
|
void operator()(ENetHost* host) const noexcept { enet_host_destroy(host); }
|
||||||
|
};
|
||||||
|
using ENetHostPtr = std::unique_ptr<ENetHost, ENetHostDeleter>;
|
||||||
|
|
||||||
void WakeupThread(ENetHost* host);
|
void WakeupThread(ENetHost* host);
|
||||||
int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event);
|
int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event);
|
||||||
bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id);
|
bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id);
|
||||||
} // namespace ENetUtil
|
} // namespace Common::ENet
|
|
@ -358,14 +358,14 @@ u64 GetSize(FILE* f)
|
||||||
const u64 pos = ftello(f);
|
const u64 pos = ftello(f);
|
||||||
if (fseeko(f, 0, SEEK_END) != 0)
|
if (fseeko(f, 0, SEEK_END) != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), LastStrerrorString());
|
ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), Common::LastStrerrorString());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 size = ftello(f);
|
const u64 size = ftello(f);
|
||||||
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0))
|
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), LastStrerrorString());
|
ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), Common::LastStrerrorString());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +379,7 @@ bool CreateEmptyFile(const std::string& filename)
|
||||||
|
|
||||||
if (!File::IOFile(filename, "wb"))
|
if (!File::IOFile(filename, "wb"))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(COMMON, "CreateEmptyFile: failed {}: {}", filename, LastStrerrorString());
|
ERROR_LOG_FMT(COMMON, "CreateEmptyFile: failed {}: {}", filename, Common::LastStrerrorString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +486,7 @@ FSTEntry ScanDirectoryTree(std::string directory, bool recursive)
|
||||||
}
|
}
|
||||||
else if (cur_depth < prev_depth)
|
else if (cur_depth < prev_depth)
|
||||||
{
|
{
|
||||||
while (dir_fsts.size() - 1 != cur_depth)
|
while (dir_fsts.size() != static_cast<size_t>(cur_depth) + 1u)
|
||||||
{
|
{
|
||||||
calc_dir_size(dir_fsts.top());
|
calc_dir_size(dir_fsts.top());
|
||||||
dir_fsts.pop();
|
dir_fsts.pop();
|
||||||
|
@ -726,7 +726,7 @@ std::string GetBundleDirectory()
|
||||||
std::string GetExePath()
|
std::string GetExePath()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
auto exe_path = GetModuleName(nullptr);
|
auto exe_path = Common::GetModuleName(nullptr);
|
||||||
if (!exe_path)
|
if (!exe_path)
|
||||||
return {};
|
return {};
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
|
|
|
@ -155,7 +155,8 @@ bool GLContextGLX::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor
|
||||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}};
|
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}};
|
||||||
|
|
||||||
s_glxError = false;
|
s_glxError = false;
|
||||||
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs[0]);
|
m_context =
|
||||||
|
glXCreateContextAttribs(m_display, m_fbconfig, nullptr, True, &context_attribs[0]);
|
||||||
XSync(m_display, False);
|
XSync(m_display, False);
|
||||||
if (!m_context || s_glxError)
|
if (!m_context || s_glxError)
|
||||||
continue;
|
continue;
|
||||||
|
@ -174,7 +175,8 @@ bool GLContextGLX::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor
|
||||||
std::array<int, 5> context_attribs_legacy = {
|
std::array<int, 5> context_attribs_legacy = {
|
||||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None}};
|
{GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None}};
|
||||||
s_glxError = false;
|
s_glxError = false;
|
||||||
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs_legacy[0]);
|
m_context =
|
||||||
|
glXCreateContextAttribs(m_display, m_fbconfig, nullptr, True, &context_attribs_legacy[0]);
|
||||||
XSync(m_display, False);
|
XSync(m_display, False);
|
||||||
m_attribs.clear();
|
m_attribs.clear();
|
||||||
m_attribs.insert(m_attribs.end(), context_attribs_legacy.begin(), context_attribs_legacy.end());
|
m_attribs.insert(m_attribs.end(), context_attribs_legacy.begin(), context_attribs_legacy.end());
|
||||||
|
|
|
@ -69,7 +69,7 @@ private:
|
||||||
|
|
||||||
struct Storage
|
struct Storage
|
||||||
{
|
{
|
||||||
std::mutex m_mutex;
|
std::recursive_mutex m_mutex;
|
||||||
std::vector<HookImpl*> m_listeners;
|
std::vector<HookImpl*> m_listeners;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,8 @@ public:
|
||||||
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
|
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
|
||||||
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
|
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
|
||||||
|
|
||||||
static int CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow,
|
static int CurlProgressCallback(Impl* impl, curl_off_t dltotal, curl_off_t dlnow,
|
||||||
double ultotal);
|
curl_off_t ultotal, curl_off_t ulnow);
|
||||||
std::string EscapeComponent(const std::string& string);
|
std::string EscapeComponent(const std::string& string);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -95,11 +95,12 @@ HttpRequest::Response HttpRequest::Post(const std::string& url, const std::strin
|
||||||
reinterpret_cast<const u8*>(payload.data()), payload.size(), codes);
|
reinterpret_cast<const u8*>(payload.data()), payload.size(), codes);
|
||||||
}
|
}
|
||||||
|
|
||||||
int HttpRequest::Impl::CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow,
|
int HttpRequest::Impl::CurlProgressCallback(Impl* impl, curl_off_t dltotal, curl_off_t dlnow,
|
||||||
double ultotal)
|
curl_off_t ultotal, curl_off_t ulnow)
|
||||||
{
|
{
|
||||||
// Abort if callback isn't true
|
// Abort if callback isn't true
|
||||||
return !impl->m_callback(dlnow, dltotal, ulnow, ultotal);
|
return !impl->m_callback(static_cast<s64>(dltotal), static_cast<s64>(dlnow),
|
||||||
|
static_cast<s64>(ultotal), static_cast<s64>(ulnow));
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback callback)
|
HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback callback)
|
||||||
|
@ -116,7 +117,7 @@ HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback c
|
||||||
if (m_callback)
|
if (m_callback)
|
||||||
{
|
{
|
||||||
curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSDATA, this);
|
curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSDATA, this);
|
||||||
curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSFUNCTION, CurlProgressCallback);
|
curl_easy_setopt(m_curl.get(), CURLOPT_XFERINFOFUNCTION, CurlProgressCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up error buffer
|
// Set up error buffer
|
||||||
|
|
|
@ -25,8 +25,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return false to abort the request
|
// Return false to abort the request
|
||||||
using ProgressCallback =
|
using ProgressCallback = std::function<bool(s64 dltotal, s64 dlnow, s64 ultotal, s64 ulnow)>;
|
||||||
std::function<bool(double dlnow, double dltotal, double ulnow, double ultotal)>;
|
|
||||||
|
|
||||||
explicit HttpRequest(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds{3000},
|
explicit HttpRequest(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds{3000},
|
||||||
ProgressCallback callback = nullptr);
|
ProgressCallback callback = nullptr);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
void IniFile::ParseLine(std::string_view line, std::string* keyOut, std::string* valueOut)
|
void IniFile::ParseLine(std::string_view line, std::string* keyOut, std::string* valueOut)
|
||||||
{
|
{
|
||||||
if (line.empty() || line.front() == '#')
|
if (line.empty() || line.front() == '#')
|
||||||
|
@ -369,3 +371,4 @@ bool IniFile::Save(const std::string& filename)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
} // namespace Common
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
struct CaseInsensitiveStringCompare
|
struct CaseInsensitiveStringCompare
|
||||||
{
|
{
|
||||||
// Allow heterogenous lookup.
|
// Allow heterogenous lookup.
|
||||||
|
@ -166,3 +168,4 @@ private:
|
||||||
|
|
||||||
static const std::string& NULL_STRING;
|
static const std::string& NULL_STRING;
|
||||||
};
|
};
|
||||||
|
} // namespace Common
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
// value_type[value_size] value;
|
// value_type[value_size] value;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
class LinearDiskCacheReader
|
class LinearDiskCacheReader
|
||||||
{
|
{
|
||||||
|
@ -163,3 +165,4 @@ private:
|
||||||
File::IOFile m_file;
|
File::IOFile m_file;
|
||||||
u32 m_num_entries = 0;
|
u32 m_num_entries = 0;
|
||||||
};
|
};
|
||||||
|
} // namespace Common
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2008 Dolphin Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "Common/MathUtil.h"
|
|
||||||
|
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
// Calculate sum of a float list
|
|
||||||
float MathFloatVectorSum(const std::vector<float>& Vec)
|
|
||||||
{
|
|
||||||
return std::accumulate(Vec.begin(), Vec.end(), 0.0f);
|
|
||||||
}
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
@ -186,12 +185,9 @@ private:
|
||||||
T m_variance{};
|
T m_variance{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace MathUtil
|
|
||||||
|
|
||||||
float MathFloatVectorSum(const std::vector<float>&);
|
|
||||||
|
|
||||||
// Rounds down. 0 -> undefined
|
// Rounds down. 0 -> undefined
|
||||||
constexpr int IntLog2(u64 val)
|
constexpr int IntLog2(u64 val)
|
||||||
{
|
{
|
||||||
return 63 - std::countl_zero(val);
|
return 63 - std::countl_zero(val);
|
||||||
}
|
}
|
||||||
|
} // namespace MathUtil
|
||||||
|
|
|
@ -250,7 +250,7 @@ size_t MemPhysical()
|
||||||
mib[1] = HW_PHYSMEM64;
|
mib[1] = HW_PHYSMEM64;
|
||||||
#endif
|
#endif
|
||||||
size_t length = sizeof(size_t);
|
size_t length = sizeof(size_t);
|
||||||
sysctl(mib, 2, &physical_memory, &length, NULL, 0);
|
sysctl(mib, 2, &physical_memory, &length, nullptr, 0);
|
||||||
return physical_memory;
|
return physical_memory;
|
||||||
#elif defined __HAIKU__
|
#elif defined __HAIKU__
|
||||||
system_info sysinfo;
|
system_info sysinfo;
|
||||||
|
|
|
@ -70,12 +70,10 @@ std::string SettingsHandler::GetValue(std::string_view key) const
|
||||||
|
|
||||||
void SettingsHandler::Decrypt()
|
void SettingsHandler::Decrypt()
|
||||||
{
|
{
|
||||||
const u8* str = m_buffer.data();
|
|
||||||
while (m_position < m_buffer.size())
|
while (m_position < m_buffer.size())
|
||||||
{
|
{
|
||||||
decoded.push_back((u8)(m_buffer[m_position] ^ m_key));
|
decoded.push_back((u8)(m_buffer[m_position] ^ m_key));
|
||||||
m_position++;
|
m_position++;
|
||||||
str++;
|
|
||||||
m_key = (m_key >> 31) | (m_key << 1);
|
m_key = (m_key >> 31) | (m_key << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,7 @@ int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent*
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<TraversalClient> g_TraversalClient;
|
std::unique_ptr<TraversalClient> g_TraversalClient;
|
||||||
std::unique_ptr<ENetHost> g_MainNetHost;
|
Common::ENet::ENetHostPtr g_MainNetHost;
|
||||||
|
|
||||||
// The settings at the previous TraversalClient reset - notably, we
|
// The settings at the previous TraversalClient reset - notably, we
|
||||||
// need to know not just what port it's on, but whether it was
|
// need to know not just what port it's on, but whether it was
|
||||||
|
@ -323,18 +323,18 @@ bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 liste
|
||||||
g_OldListenPort = listen_port;
|
g_OldListenPort = listen_port;
|
||||||
|
|
||||||
ENetAddress addr = {ENET_HOST_ANY, listen_port};
|
ENetAddress addr = {ENET_HOST_ANY, listen_port};
|
||||||
ENetHost* host = enet_host_create(&addr, // address
|
auto host = Common::ENet::ENetHostPtr{enet_host_create(&addr, // address
|
||||||
50, // peerCount
|
50, // peerCount
|
||||||
NetPlay::CHANNEL_COUNT, // channelLimit
|
NetPlay::CHANNEL_COUNT, // channelLimit
|
||||||
0, // incomingBandwidth
|
0, // incomingBandwidth
|
||||||
0); // outgoingBandwidth
|
0)}; // outgoingBandwidth
|
||||||
if (!host)
|
if (!host)
|
||||||
{
|
{
|
||||||
g_MainNetHost.reset();
|
g_MainNetHost.reset();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
host->mtu = std::min(host->mtu, NetPlay::MAX_ENET_MTU);
|
host->mtu = std::min(host->mtu, NetPlay::MAX_ENET_MTU);
|
||||||
g_MainNetHost.reset(host);
|
g_MainNetHost = std::move(host);
|
||||||
g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port));
|
g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <enet/enet.h>
|
#include <enet/enet.h>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/ENet.h"
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
#include "Common/TraversalProto.h"
|
#include "Common/TraversalProto.h"
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ private:
|
||||||
};
|
};
|
||||||
extern std::unique_ptr<TraversalClient> g_TraversalClient;
|
extern std::unique_ptr<TraversalClient> g_TraversalClient;
|
||||||
// the NetHost connected to the TraversalClient.
|
// the NetHost connected to the TraversalClient.
|
||||||
extern std::unique_ptr<ENetHost> g_MainNetHost;
|
extern Common::ENet::ENetHostPtr g_MainNetHost;
|
||||||
// Create g_TraversalClient and g_MainNetHost if necessary.
|
// Create g_TraversalClient and g_MainNetHost if necessary.
|
||||||
bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port = 0);
|
bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port = 0);
|
||||||
void ReleaseTraversalClient();
|
void ReleaseTraversalClient();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// Copyright 2021 Dolphin Emulator Project
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
|
@ -164,14 +164,14 @@ static void UnmapPortThread()
|
||||||
UnmapPort(s_mapped);
|
UnmapPort(s_mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPnP::TryPortmapping(u16 port)
|
void Common::UPnP::TryPortmapping(u16 port)
|
||||||
{
|
{
|
||||||
if (s_thread.joinable())
|
if (s_thread.joinable())
|
||||||
s_thread.join();
|
s_thread.join();
|
||||||
s_thread = std::thread(&MapPortThread, port);
|
s_thread = std::thread(&MapPortThread, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPnP::StopPortmapping()
|
void Common::UPnP::StopPortmapping()
|
||||||
{
|
{
|
||||||
if (s_thread.joinable())
|
if (s_thread.joinable())
|
||||||
s_thread.join();
|
s_thread.join();
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
namespace UPnP
|
namespace Common::UPnP
|
||||||
{
|
{
|
||||||
void TryPortmapping(u16 port);
|
void TryPortmapping(u16 port);
|
||||||
void StopPortmapping();
|
void StopPortmapping();
|
||||||
} // namespace UPnP
|
} // namespace Common::UPnP
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1106,6 +1106,7 @@ public:
|
||||||
template <typename FunctionPointer>
|
template <typename FunctionPointer>
|
||||||
void ABI_CallFunctionPR(FunctionPointer func, const void* ptr, X64Reg reg1)
|
void ABI_CallFunctionPR(FunctionPointer func, const void* ptr, X64Reg reg1)
|
||||||
{
|
{
|
||||||
|
if (reg1 != ABI_PARAM2)
|
||||||
MOV(64, R(ABI_PARAM2), R(reg1));
|
MOV(64, R(ABI_PARAM2), R(reg1));
|
||||||
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
|
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
|
||||||
ABI_CallFunction(func);
|
ABI_CallFunction(func);
|
||||||
|
|
|
@ -4,10 +4,17 @@
|
||||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
#include "Core/AchievementManager.h"
|
#include "Core/AchievementManager.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <rcheevos/include/rc_hash.h>
|
||||||
|
|
||||||
#include "Common/HttpRequest.h"
|
#include "Common/HttpRequest.h"
|
||||||
#include "Common/WorkQueueThread.h"
|
#include "Common/WorkQueueThread.h"
|
||||||
#include "Config/AchievementSettings.h"
|
#include "Config/AchievementSettings.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
|
static constexpr bool hardcore_mode_enabled = false;
|
||||||
|
|
||||||
AchievementManager* AchievementManager::GetInstance()
|
AchievementManager* AchievementManager::GetInstance()
|
||||||
{
|
{
|
||||||
|
@ -28,49 +35,337 @@ void AchievementManager::Init()
|
||||||
|
|
||||||
AchievementManager::ResponseType AchievementManager::Login(const std::string& password)
|
AchievementManager::ResponseType AchievementManager::Login(const std::string& password)
|
||||||
{
|
{
|
||||||
|
if (!m_is_runtime_initialized)
|
||||||
|
return AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED;
|
||||||
return VerifyCredentials(password);
|
return VerifyCredentials(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementManager::LoginAsync(const std::string& password, const LoginCallback& callback)
|
void AchievementManager::LoginAsync(const std::string& password, const ResponseCallback& callback)
|
||||||
{
|
{
|
||||||
|
if (!m_is_runtime_initialized)
|
||||||
|
{
|
||||||
|
callback(AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_queue.EmplaceItem([this, password, callback] { callback(VerifyCredentials(password)); });
|
m_queue.EmplaceItem([this, password, callback] { callback(VerifyCredentials(password)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AchievementManager::IsLoggedIn() const
|
bool AchievementManager::IsLoggedIn() const
|
||||||
{
|
{
|
||||||
return m_login_data.response.succeeded;
|
return !Config::Get(Config::RA_API_TOKEN).empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::LoadGameByFilenameAsync(const std::string& iso_path,
|
||||||
|
const ResponseCallback& callback)
|
||||||
|
{
|
||||||
|
if (!m_is_runtime_initialized)
|
||||||
|
{
|
||||||
|
callback(AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct FilereaderState
|
||||||
|
{
|
||||||
|
int64_t position = 0;
|
||||||
|
std::unique_ptr<DiscIO::Volume> volume;
|
||||||
|
};
|
||||||
|
rc_hash_filereader volume_reader{
|
||||||
|
.open = [](const char* path_utf8) -> void* {
|
||||||
|
auto state = std::make_unique<FilereaderState>();
|
||||||
|
state->volume = DiscIO::CreateVolume(path_utf8);
|
||||||
|
if (!state->volume)
|
||||||
|
return nullptr;
|
||||||
|
return state.release();
|
||||||
|
},
|
||||||
|
.seek =
|
||||||
|
[](void* file_handle, int64_t offset, int origin) {
|
||||||
|
switch (origin)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
reinterpret_cast<FilereaderState*>(file_handle)->position = offset;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
reinterpret_cast<FilereaderState*>(file_handle)->position += offset;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
// Unused
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.tell =
|
||||||
|
[](void* file_handle) {
|
||||||
|
return reinterpret_cast<FilereaderState*>(file_handle)->position;
|
||||||
|
},
|
||||||
|
.read =
|
||||||
|
[](void* file_handle, void* buffer, size_t requested_bytes) {
|
||||||
|
FilereaderState* filereader_state = reinterpret_cast<FilereaderState*>(file_handle);
|
||||||
|
bool success = (filereader_state->volume->Read(
|
||||||
|
filereader_state->position, requested_bytes, reinterpret_cast<u8*>(buffer),
|
||||||
|
DiscIO::PARTITION_NONE));
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
filereader_state->position += requested_bytes;
|
||||||
|
return requested_bytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return static_cast<size_t>(0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.close = [](void* file_handle) { delete reinterpret_cast<FilereaderState*>(file_handle); }};
|
||||||
|
rc_hash_init_custom_filereader(&volume_reader);
|
||||||
|
std::array<char, HASH_LENGTH> game_hash;
|
||||||
|
if (!rc_hash_generate_from_file(game_hash.data(), RC_CONSOLE_GAMECUBE, iso_path.c_str()))
|
||||||
|
return;
|
||||||
|
m_queue.EmplaceItem([this, callback, game_hash] {
|
||||||
|
const auto resolve_hash_response = ResolveHash(game_hash);
|
||||||
|
if (resolve_hash_response != ResponseType::SUCCESS || m_game_id == 0)
|
||||||
|
{
|
||||||
|
callback(resolve_hash_response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto start_session_response = StartRASession();
|
||||||
|
if (start_session_response != ResponseType::SUCCESS)
|
||||||
|
{
|
||||||
|
callback(start_session_response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fetch_game_data_response = FetchGameData();
|
||||||
|
m_is_game_loaded = fetch_game_data_response == ResponseType::SUCCESS;
|
||||||
|
|
||||||
|
// Claim the lock, then queue the fetch unlock data calls, then initialize the unlock map in
|
||||||
|
// ActivateDeactiveAchievements. This allows the calls to process while initializing the
|
||||||
|
// unlock map but then forces them to wait until it's initialized before making modifications to
|
||||||
|
// it.
|
||||||
|
{
|
||||||
|
std::lock_guard lg{m_lock};
|
||||||
|
LoadUnlockData([](ResponseType r_type) {});
|
||||||
|
ActivateDeactivateAchievements();
|
||||||
|
}
|
||||||
|
ActivateDeactivateLeaderboards();
|
||||||
|
ActivateDeactivateRichPresence();
|
||||||
|
|
||||||
|
callback(fetch_game_data_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::LoadUnlockData(const ResponseCallback& callback)
|
||||||
|
{
|
||||||
|
m_queue.EmplaceItem([this, callback] {
|
||||||
|
const auto hardcore_unlock_response = FetchUnlockData(true);
|
||||||
|
if (hardcore_unlock_response != ResponseType::SUCCESS)
|
||||||
|
{
|
||||||
|
callback(hardcore_unlock_response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(FetchUnlockData(false));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::ActivateDeactivateAchievements()
|
||||||
|
{
|
||||||
|
bool enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED);
|
||||||
|
bool unofficial = Config::Get(Config::RA_UNOFFICIAL_ENABLED);
|
||||||
|
bool encore = Config::Get(Config::RA_ENCORE_ENABLED);
|
||||||
|
for (u32 ix = 0; ix < m_game_data.num_achievements; ix++)
|
||||||
|
{
|
||||||
|
auto iter =
|
||||||
|
m_unlock_map.insert({m_game_data.achievements[ix].id, UnlockStatus{.game_data_index = ix}});
|
||||||
|
ActivateDeactivateAchievement(iter.first->first, enabled, unofficial, encore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::ActivateDeactivateLeaderboards()
|
||||||
|
{
|
||||||
|
bool leaderboards_enabled = Config::Get(Config::RA_LEADERBOARDS_ENABLED);
|
||||||
|
for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++)
|
||||||
|
{
|
||||||
|
auto leaderboard = m_game_data.leaderboards[ix];
|
||||||
|
if (m_is_game_loaded && leaderboards_enabled && hardcore_mode_enabled)
|
||||||
|
{
|
||||||
|
rc_runtime_activate_lboard(&m_runtime, leaderboard.id, leaderboard.definition, nullptr, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc_runtime_deactivate_lboard(&m_runtime, m_game_data.leaderboards[ix].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::ActivateDeactivateRichPresence()
|
||||||
|
{
|
||||||
|
rc_runtime_activate_richpresence(
|
||||||
|
&m_runtime,
|
||||||
|
(m_is_game_loaded && Config::Get(Config::RA_RICH_PRESENCE_ENABLED)) ?
|
||||||
|
m_game_data.rich_presence_script :
|
||||||
|
"",
|
||||||
|
nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::CloseGame()
|
||||||
|
{
|
||||||
|
m_is_game_loaded = false;
|
||||||
|
m_game_id = 0;
|
||||||
|
m_queue.Cancel();
|
||||||
|
m_unlock_map.clear();
|
||||||
|
ActivateDeactivateAchievements();
|
||||||
|
ActivateDeactivateLeaderboards();
|
||||||
|
ActivateDeactivateRichPresence();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementManager::Logout()
|
void AchievementManager::Logout()
|
||||||
{
|
{
|
||||||
|
CloseGame();
|
||||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
|
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
|
||||||
rc_api_destroy_login_response(&m_login_data);
|
|
||||||
m_login_data.response.succeeded = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementManager::Shutdown()
|
void AchievementManager::Shutdown()
|
||||||
{
|
{
|
||||||
|
CloseGame();
|
||||||
m_is_runtime_initialized = false;
|
m_is_runtime_initialized = false;
|
||||||
m_queue.Shutdown();
|
m_queue.Shutdown();
|
||||||
// DON'T log out - keep those credentials for next run.
|
// DON'T log out - keep those credentials for next run.
|
||||||
rc_api_destroy_login_response(&m_login_data);
|
|
||||||
m_login_data.response.succeeded = 0;
|
|
||||||
rc_runtime_destroy(&m_runtime);
|
rc_runtime_destroy(&m_runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
AchievementManager::ResponseType AchievementManager::VerifyCredentials(const std::string& password)
|
AchievementManager::ResponseType AchievementManager::VerifyCredentials(const std::string& password)
|
||||||
{
|
{
|
||||||
|
rc_api_login_response_t login_data{};
|
||||||
std::string username = Config::Get(Config::RA_USERNAME);
|
std::string username = Config::Get(Config::RA_USERNAME);
|
||||||
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
||||||
rc_api_login_request_t login_request = {
|
rc_api_login_request_t login_request = {
|
||||||
.username = username.c_str(), .api_token = api_token.c_str(), .password = password.c_str()};
|
.username = username.c_str(), .api_token = api_token.c_str(), .password = password.c_str()};
|
||||||
ResponseType r_type = Request<rc_api_login_request_t, rc_api_login_response_t>(
|
ResponseType r_type = Request<rc_api_login_request_t, rc_api_login_response_t>(
|
||||||
login_request, &m_login_data, rc_api_init_login_request, rc_api_process_login_response);
|
login_request, &login_data, rc_api_init_login_request, rc_api_process_login_response);
|
||||||
if (r_type == ResponseType::SUCCESS)
|
if (r_type == ResponseType::SUCCESS)
|
||||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, m_login_data.api_token);
|
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, login_data.api_token);
|
||||||
|
rc_api_destroy_login_response(&login_data);
|
||||||
return r_type;
|
return r_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AchievementManager::ResponseType
|
||||||
|
AchievementManager::ResolveHash(std::array<char, HASH_LENGTH> game_hash)
|
||||||
|
{
|
||||||
|
rc_api_resolve_hash_response_t hash_data{};
|
||||||
|
std::string username = Config::Get(Config::RA_USERNAME);
|
||||||
|
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
||||||
|
rc_api_resolve_hash_request_t resolve_hash_request = {
|
||||||
|
.username = username.c_str(), .api_token = api_token.c_str(), .game_hash = game_hash.data()};
|
||||||
|
ResponseType r_type = Request<rc_api_resolve_hash_request_t, rc_api_resolve_hash_response_t>(
|
||||||
|
resolve_hash_request, &hash_data, rc_api_init_resolve_hash_request,
|
||||||
|
rc_api_process_resolve_hash_response);
|
||||||
|
if (r_type == ResponseType::SUCCESS)
|
||||||
|
m_game_id = hash_data.game_id;
|
||||||
|
rc_api_destroy_resolve_hash_response(&hash_data);
|
||||||
|
return r_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
AchievementManager::ResponseType AchievementManager::StartRASession()
|
||||||
|
{
|
||||||
|
rc_api_start_session_response_t session_data{};
|
||||||
|
std::string username = Config::Get(Config::RA_USERNAME);
|
||||||
|
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
||||||
|
rc_api_start_session_request_t start_session_request = {
|
||||||
|
.username = username.c_str(), .api_token = api_token.c_str(), .game_id = m_game_id};
|
||||||
|
ResponseType r_type = Request<rc_api_start_session_request_t, rc_api_start_session_response_t>(
|
||||||
|
start_session_request, &session_data, rc_api_init_start_session_request,
|
||||||
|
rc_api_process_start_session_response);
|
||||||
|
rc_api_destroy_start_session_response(&session_data);
|
||||||
|
return r_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
AchievementManager::ResponseType AchievementManager::FetchGameData()
|
||||||
|
{
|
||||||
|
std::string username = Config::Get(Config::RA_USERNAME);
|
||||||
|
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
||||||
|
rc_api_fetch_game_data_request_t fetch_data_request = {
|
||||||
|
.username = username.c_str(), .api_token = api_token.c_str(), .game_id = m_game_id};
|
||||||
|
return Request<rc_api_fetch_game_data_request_t, rc_api_fetch_game_data_response_t>(
|
||||||
|
fetch_data_request, &m_game_data, rc_api_init_fetch_game_data_request,
|
||||||
|
rc_api_process_fetch_game_data_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
AchievementManager::ResponseType AchievementManager::FetchUnlockData(bool hardcore)
|
||||||
|
{
|
||||||
|
rc_api_fetch_user_unlocks_response_t unlock_data{};
|
||||||
|
std::string username = Config::Get(Config::RA_USERNAME);
|
||||||
|
std::string api_token = Config::Get(Config::RA_API_TOKEN);
|
||||||
|
rc_api_fetch_user_unlocks_request_t fetch_unlocks_request = {.username = username.c_str(),
|
||||||
|
.api_token = api_token.c_str(),
|
||||||
|
.game_id = m_game_id,
|
||||||
|
.hardcore = hardcore};
|
||||||
|
ResponseType r_type =
|
||||||
|
Request<rc_api_fetch_user_unlocks_request_t, rc_api_fetch_user_unlocks_response_t>(
|
||||||
|
fetch_unlocks_request, &unlock_data, rc_api_init_fetch_user_unlocks_request,
|
||||||
|
rc_api_process_fetch_user_unlocks_response);
|
||||||
|
if (r_type == ResponseType::SUCCESS)
|
||||||
|
{
|
||||||
|
std::lock_guard lg{m_lock};
|
||||||
|
bool enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED);
|
||||||
|
bool unofficial = Config::Get(Config::RA_UNOFFICIAL_ENABLED);
|
||||||
|
bool encore = Config::Get(Config::RA_ENCORE_ENABLED);
|
||||||
|
for (AchievementId ix = 0; ix < unlock_data.num_achievement_ids; ix++)
|
||||||
|
{
|
||||||
|
auto it = m_unlock_map.find(unlock_data.achievement_ids[ix]);
|
||||||
|
if (it == m_unlock_map.end())
|
||||||
|
continue;
|
||||||
|
it->second.remote_unlock_status =
|
||||||
|
hardcore ? UnlockStatus::UnlockType::HARDCORE : UnlockStatus::UnlockType::SOFTCORE;
|
||||||
|
ActivateDeactivateAchievement(unlock_data.achievement_ids[ix], enabled, unofficial, encore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rc_api_destroy_fetch_user_unlocks_response(&unlock_data);
|
||||||
|
return r_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementManager::ActivateDeactivateAchievement(AchievementId id, bool enabled,
|
||||||
|
bool unofficial, bool encore)
|
||||||
|
{
|
||||||
|
auto it = m_unlock_map.find(id);
|
||||||
|
if (it == m_unlock_map.end())
|
||||||
|
return;
|
||||||
|
const UnlockStatus& status = it->second;
|
||||||
|
u32 index = status.game_data_index;
|
||||||
|
bool active = (rc_runtime_get_achievement(&m_runtime, id) != nullptr);
|
||||||
|
|
||||||
|
// Deactivate achievements if game is not loaded
|
||||||
|
bool activate = m_is_game_loaded;
|
||||||
|
// Activate achievements only if achievements are enabled
|
||||||
|
if (activate && !enabled)
|
||||||
|
activate = false;
|
||||||
|
// Deactivate if achievement is unofficial, unless unofficial achievements are enabled
|
||||||
|
if (activate && !unofficial &&
|
||||||
|
m_game_data.achievements[index].category == RC_ACHIEVEMENT_CATEGORY_UNOFFICIAL)
|
||||||
|
{
|
||||||
|
activate = false;
|
||||||
|
}
|
||||||
|
// If encore mode is on, activate/deactivate regardless of current unlock status
|
||||||
|
if (activate && !encore)
|
||||||
|
{
|
||||||
|
// Encore is off, achievement has been unlocked in this session, deactivate
|
||||||
|
activate = (status.session_unlock_count == 0);
|
||||||
|
// Encore is off, achievement has been hardcore unlocked on site, deactivate
|
||||||
|
if (activate && status.remote_unlock_status == UnlockStatus::UnlockType::HARDCORE)
|
||||||
|
activate = false;
|
||||||
|
// Encore is off, hardcore is off, achievement has been softcore unlocked on site, deactivate
|
||||||
|
if (activate && !hardcore_mode_enabled &&
|
||||||
|
status.remote_unlock_status == UnlockStatus::UnlockType::SOFTCORE)
|
||||||
|
{
|
||||||
|
activate = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!active && activate)
|
||||||
|
{
|
||||||
|
rc_runtime_activate_achievement(&m_runtime, id, m_game_data.achievements[index].definition,
|
||||||
|
nullptr, 0);
|
||||||
|
}
|
||||||
|
if (active && !activate)
|
||||||
|
rc_runtime_deactivate_achievement(&m_runtime, id);
|
||||||
|
}
|
||||||
|
|
||||||
// Every RetroAchievements API call, with only a partial exception for fetch_image, follows
|
// Every RetroAchievements API call, with only a partial exception for fetch_image, follows
|
||||||
// the same design pattern (here, X is the name of the call):
|
// the same design pattern (here, X is the name of the call):
|
||||||
// Create a specific rc_api_X_request_t struct and populate with the necessary values
|
// Create a specific rc_api_X_request_t struct and populate with the necessary values
|
||||||
|
|
|
@ -8,37 +8,58 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <rcheevos/include/rc_api_runtime.h>
|
||||||
#include <rcheevos/include/rc_api_user.h>
|
#include <rcheevos/include/rc_api_user.h>
|
||||||
#include <rcheevos/include/rc_runtime.h>
|
#include <rcheevos/include/rc_runtime.h>
|
||||||
|
|
||||||
#include "Common/Event.h"
|
#include "Common/Event.h"
|
||||||
#include "Common/WorkQueueThread.h"
|
#include "Common/WorkQueueThread.h"
|
||||||
|
|
||||||
|
using AchievementId = u32;
|
||||||
|
|
||||||
class AchievementManager
|
class AchievementManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class ResponseType
|
enum class ResponseType
|
||||||
{
|
{
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
|
MANAGER_NOT_INITIALIZED,
|
||||||
INVALID_CREDENTIALS,
|
INVALID_CREDENTIALS,
|
||||||
CONNECTION_FAILED,
|
CONNECTION_FAILED,
|
||||||
UNKNOWN_FAILURE
|
UNKNOWN_FAILURE
|
||||||
};
|
};
|
||||||
using LoginCallback = std::function<void(ResponseType)>;
|
using ResponseCallback = std::function<void(ResponseType)>;
|
||||||
|
|
||||||
static AchievementManager* GetInstance();
|
static AchievementManager* GetInstance();
|
||||||
void Init();
|
void Init();
|
||||||
ResponseType Login(const std::string& password);
|
ResponseType Login(const std::string& password);
|
||||||
void LoginAsync(const std::string& password, const LoginCallback& callback);
|
void LoginAsync(const std::string& password, const ResponseCallback& callback);
|
||||||
bool IsLoggedIn() const;
|
bool IsLoggedIn() const;
|
||||||
|
void LoadGameByFilenameAsync(const std::string& iso_path, const ResponseCallback& callback);
|
||||||
|
|
||||||
|
void LoadUnlockData(const ResponseCallback& callback);
|
||||||
|
void ActivateDeactivateAchievements();
|
||||||
|
void ActivateDeactivateLeaderboards();
|
||||||
|
void ActivateDeactivateRichPresence();
|
||||||
|
|
||||||
|
void CloseGame();
|
||||||
void Logout();
|
void Logout();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AchievementManager() = default;
|
AchievementManager() = default;
|
||||||
|
|
||||||
|
static constexpr int HASH_LENGTH = 33;
|
||||||
|
|
||||||
ResponseType VerifyCredentials(const std::string& password);
|
ResponseType VerifyCredentials(const std::string& password);
|
||||||
|
ResponseType ResolveHash(std::array<char, HASH_LENGTH> game_hash);
|
||||||
|
ResponseType StartRASession();
|
||||||
|
ResponseType FetchGameData();
|
||||||
|
ResponseType FetchUnlockData(bool hardcore);
|
||||||
|
|
||||||
|
void ActivateDeactivateAchievement(AchievementId id, bool enabled, bool unofficial, bool encore);
|
||||||
|
|
||||||
template <typename RcRequest, typename RcResponse>
|
template <typename RcRequest, typename RcResponse>
|
||||||
ResponseType Request(RcRequest rc_request, RcResponse* rc_response,
|
ResponseType Request(RcRequest rc_request, RcResponse* rc_response,
|
||||||
|
@ -47,8 +68,25 @@ private:
|
||||||
|
|
||||||
rc_runtime_t m_runtime{};
|
rc_runtime_t m_runtime{};
|
||||||
bool m_is_runtime_initialized = false;
|
bool m_is_runtime_initialized = false;
|
||||||
rc_api_login_response_t m_login_data{};
|
unsigned int m_game_id = 0;
|
||||||
|
rc_api_fetch_game_data_response_t m_game_data{};
|
||||||
|
bool m_is_game_loaded = false;
|
||||||
|
|
||||||
|
struct UnlockStatus
|
||||||
|
{
|
||||||
|
AchievementId game_data_index = 0;
|
||||||
|
enum class UnlockType
|
||||||
|
{
|
||||||
|
LOCKED,
|
||||||
|
SOFTCORE,
|
||||||
|
HARDCORE
|
||||||
|
} remote_unlock_status = UnlockType::LOCKED;
|
||||||
|
int session_unlock_count = 0;
|
||||||
|
};
|
||||||
|
std::unordered_map<AchievementId, UnlockStatus> m_unlock_map;
|
||||||
|
|
||||||
Common::WorkQueueThread<std::function<void()>> m_queue;
|
Common::WorkQueueThread<std::function<void()>> m_queue;
|
||||||
|
std::recursive_mutex m_lock;
|
||||||
}; // class AchievementManager
|
}; // class AchievementManager
|
||||||
|
|
||||||
#endif // USE_RETRO_ACHIEVEMENTS
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
|
@ -169,18 +169,17 @@ void AddCode(ARCode code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini)
|
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini)
|
||||||
{
|
{
|
||||||
ApplyCodes(LoadCodes(global_ini, local_ini));
|
ApplyCodes(LoadCodes(global_ini, local_ini));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses the Action Replay section of a game ini file.
|
// Parses the Action Replay section of a game ini file.
|
||||||
std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_ini)
|
std::vector<ARCode> LoadCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini)
|
||||||
{
|
{
|
||||||
std::vector<ARCode> codes;
|
std::vector<ARCode> codes;
|
||||||
|
|
||||||
const IniFile* inis[2] = {&global_ini, &local_ini};
|
for (const auto* ini : {&global_ini, &local_ini})
|
||||||
for (const IniFile* ini : inis)
|
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::vector<std::string> encrypted_lines;
|
std::vector<std::string> encrypted_lines;
|
||||||
|
@ -250,7 +249,7 @@ std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_in
|
||||||
return codes;
|
return codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveCodes(IniFile* local_ini, std::span<const ARCode> codes)
|
void SaveCodes(Common::IniFile* local_ini, std::span<const ARCode> codes)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::vector<std::string> enabled_lines;
|
std::vector<std::string> enabled_lines;
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
class IniFile;
|
class IniFile;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
|
@ -47,10 +50,10 @@ void SetSyncedCodesAsActive();
|
||||||
void UpdateSyncedCodes(std::span<const ARCode> codes);
|
void UpdateSyncedCodes(std::span<const ARCode> codes);
|
||||||
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
|
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
|
||||||
void AddCode(ARCode new_code);
|
void AddCode(ARCode new_code);
|
||||||
void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini);
|
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini);
|
||||||
|
|
||||||
std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_ini);
|
std::vector<ARCode> LoadCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini);
|
||||||
void SaveCodes(IniFile* local_ini, std::span<const ARCode> codes);
|
void SaveCodes(Common::IniFile* local_ini, std::span<const ARCode> codes);
|
||||||
|
|
||||||
using EncryptedLine = std::string;
|
using EncryptedLine = std::string;
|
||||||
std::variant<std::monostate, AREntry, EncryptedLine> DeserializeLine(const std::string& line);
|
std::variant<std::monostate, AREntry, EncryptedLine> DeserializeLine(const std::string& line);
|
||||||
|
|
|
@ -57,13 +57,14 @@ void PresetTimeBaseTicks(Core::System& system, const Core::CPUThreadGuard& guard
|
||||||
|
|
||||||
void CBoot::RunFunction(Core::System& system, u32 address)
|
void CBoot::RunFunction(Core::System& system, u32 address)
|
||||||
{
|
{
|
||||||
auto& ppc_state = system.GetPPCState();
|
auto& power_pc = system.GetPowerPC();
|
||||||
|
auto& ppc_state = power_pc.GetPPCState();
|
||||||
|
|
||||||
ppc_state.pc = address;
|
ppc_state.pc = address;
|
||||||
LR(ppc_state) = 0x00;
|
LR(ppc_state) = 0x00;
|
||||||
|
|
||||||
while (ppc_state.pc != 0x00)
|
while (ppc_state.pc != 0x00)
|
||||||
PowerPC::SingleStep();
|
power_pc.SingleStep();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state)
|
void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
|
#include "Core/AchievementManager.h"
|
||||||
#include "Core/Boot/Boot.h"
|
#include "Core/Boot/Boot.h"
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
#include "Core/Config/SYSCONFSettings.h"
|
#include "Core/Config/SYSCONFSettings.h"
|
||||||
|
@ -163,6 +164,16 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
std::string path = "";
|
||||||
|
if (std::holds_alternative<BootParameters::Disc>(boot->parameters))
|
||||||
|
{
|
||||||
|
path = std::get<BootParameters::Disc>(boot->parameters).path;
|
||||||
|
}
|
||||||
|
AchievementManager::GetInstance()->LoadGameByFilenameAsync(
|
||||||
|
path, [](AchievementManager::ResponseType r_type) {});
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
const bool load_ipl = !StartUp.bWii && !Config::Get(Config::MAIN_SKIP_IPL) &&
|
const bool load_ipl = !StartUp.bWii && !Config::Get(Config::MAIN_SKIP_IPL) &&
|
||||||
std::holds_alternative<BootParameters::Disc>(boot->parameters);
|
std::holds_alternative<BootParameters::Disc>(boot->parameters);
|
||||||
if (load_ipl)
|
if (load_ipl)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ReadEnabledOrDisabled(const IniFile& ini, const std::string& section, bool enabled,
|
void ReadEnabledOrDisabled(const Common::IniFile& ini, const std::string& section, bool enabled,
|
||||||
std::vector<T>* codes)
|
std::vector<T>* codes)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
|
@ -30,7 +30,8 @@ void ReadEnabledOrDisabled(const IniFile& ini, const std::string& section, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ReadEnabledAndDisabled(const IniFile& ini, const std::string& section, std::vector<T>* codes)
|
void ReadEnabledAndDisabled(const Common::IniFile& ini, const std::string& section,
|
||||||
|
std::vector<T>* codes)
|
||||||
{
|
{
|
||||||
ReadEnabledOrDisabled(ini, section + "_Enabled", true, codes);
|
ReadEnabledOrDisabled(ini, section + "_Enabled", true, codes);
|
||||||
ReadEnabledOrDisabled(ini, section + "_Disabled", false, codes);
|
ReadEnabledOrDisabled(ini, section + "_Disabled", false, codes);
|
||||||
|
|
|
@ -13,4 +13,13 @@ namespace Config
|
||||||
const Info<bool> RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false};
|
const Info<bool> RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false};
|
||||||
const Info<std::string> RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""};
|
const Info<std::string> RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""};
|
||||||
const Info<std::string> RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""};
|
const Info<std::string> RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""};
|
||||||
|
const Info<bool> RA_ACHIEVEMENTS_ENABLED{
|
||||||
|
{System::Achievements, "Achievements", "AchievementsEnabled"}, false};
|
||||||
|
const Info<bool> RA_LEADERBOARDS_ENABLED{
|
||||||
|
{System::Achievements, "Achievements", "LeaderboardsEnabled"}, false};
|
||||||
|
const Info<bool> RA_RICH_PRESENCE_ENABLED{
|
||||||
|
{System::Achievements, "Achievements", "RichPresenceEnabled"}, false};
|
||||||
|
const Info<bool> RA_UNOFFICIAL_ENABLED{{System::Achievements, "Achievements", "UnofficialEnabled"},
|
||||||
|
false};
|
||||||
|
const Info<bool> RA_ENCORE_ENABLED{{System::Achievements, "Achievements", "EncoreEnabled"}, false};
|
||||||
} // namespace Config
|
} // namespace Config
|
||||||
|
|
|
@ -11,4 +11,9 @@ namespace Config
|
||||||
extern const Info<bool> RA_ENABLED;
|
extern const Info<bool> RA_ENABLED;
|
||||||
extern const Info<std::string> RA_USERNAME;
|
extern const Info<std::string> RA_USERNAME;
|
||||||
extern const Info<std::string> RA_API_TOKEN;
|
extern const Info<std::string> RA_API_TOKEN;
|
||||||
|
extern const Info<bool> RA_ACHIEVEMENTS_ENABLED;
|
||||||
|
extern const Info<bool> RA_LEADERBOARDS_ENABLED;
|
||||||
|
extern const Info<bool> RA_RICH_PRESENCE_ENABLED;
|
||||||
|
extern const Info<bool> RA_UNOFFICIAL_ENABLED;
|
||||||
|
extern const Info<bool> RA_ENCORE_ENABLED;
|
||||||
} // namespace Config
|
} // namespace Config
|
||||||
|
|
|
@ -113,14 +113,14 @@ public:
|
||||||
LoadFromSYSCONF(layer);
|
LoadFromSYSCONF(layer);
|
||||||
for (const auto& system : system_to_ini)
|
for (const auto& system : system_to_ini)
|
||||||
{
|
{
|
||||||
IniFile ini;
|
Common::IniFile ini;
|
||||||
ini.Load(File::GetUserPath(system.second));
|
ini.Load(File::GetUserPath(system.second));
|
||||||
const std::list<IniFile::Section>& system_sections = ini.GetSections();
|
const auto& system_sections = ini.GetSections();
|
||||||
|
|
||||||
for (const auto& section : system_sections)
|
for (const auto& section : system_sections)
|
||||||
{
|
{
|
||||||
const std::string section_name = section.GetName();
|
const std::string section_name = section.GetName();
|
||||||
const IniFile::Section::SectionMap& section_map = section.GetValues();
|
const auto& section_map = section.GetValues();
|
||||||
|
|
||||||
for (const auto& value : section_map)
|
for (const auto& value : section_map)
|
||||||
{
|
{
|
||||||
|
@ -141,7 +141,7 @@ public:
|
||||||
{
|
{
|
||||||
SaveToSYSCONF(layer->GetLayer());
|
SaveToSYSCONF(layer->GetLayer());
|
||||||
|
|
||||||
std::map<Config::System, IniFile> inis;
|
std::map<Config::System, Common::IniFile> inis;
|
||||||
|
|
||||||
for (const auto& system : system_to_ini)
|
for (const auto& system : system_to_ini)
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ public:
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
IniFile::Section* ini_section = ini->second.GetOrCreateSection(location.section);
|
auto* ini_section = ini->second.GetOrCreateSection(location.section);
|
||||||
ini_section->Set(location.key, *value);
|
ini_section->Set(location.key, *value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -175,7 +175,7 @@ public:
|
||||||
|
|
||||||
void Load(Config::Layer* layer) override
|
void Load(Config::Layer* layer) override
|
||||||
{
|
{
|
||||||
IniFile ini;
|
Common::IniFile ini;
|
||||||
if (layer->GetLayer() == Config::LayerType::GlobalGame)
|
if (layer->GetLayer() == Config::LayerType::GlobalGame)
|
||||||
{
|
{
|
||||||
for (const std::string& filename : GetGameIniFilenames(m_id, m_revision))
|
for (const std::string& filename : GetGameIniFilenames(m_id, m_revision))
|
||||||
|
@ -187,7 +187,7 @@ public:
|
||||||
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::list<IniFile::Section>& system_sections = ini.GetSections();
|
const auto& system_sections = ini.GetSections();
|
||||||
|
|
||||||
for (const auto& section : system_sections)
|
for (const auto& section : system_sections)
|
||||||
{
|
{
|
||||||
|
@ -234,11 +234,11 @@ private:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile profile_ini;
|
Common::IniFile profile_ini;
|
||||||
profile_ini.Load(ini_path);
|
profile_ini.Load(ini_path);
|
||||||
|
|
||||||
const IniFile::Section* ini_section = profile_ini.GetOrCreateSection("Profile");
|
const auto* ini_section = profile_ini.GetOrCreateSection("Profile");
|
||||||
const IniFile::Section::SectionMap& section_map = ini_section->GetValues();
|
const auto& section_map = ini_section->GetValues();
|
||||||
for (const auto& value : section_map)
|
for (const auto& value : section_map)
|
||||||
{
|
{
|
||||||
Config::Location location{std::get<2>(use_data), std::get<1>(use_data) + num,
|
Config::Location location{std::get<2>(use_data), std::get<1>(use_data) + num,
|
||||||
|
@ -250,12 +250,12 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadFromSystemSection(Config::Layer* layer, const IniFile::Section& section) const
|
void LoadFromSystemSection(Config::Layer* layer, const Common::IniFile::Section& section) const
|
||||||
{
|
{
|
||||||
const std::string section_name = section.GetName();
|
const std::string section_name = section.GetName();
|
||||||
|
|
||||||
// Regular key,value pairs
|
// Regular key,value pairs
|
||||||
const IniFile::Section::SectionMap& section_map = section.GetValues();
|
const auto& section_map = section.GetValues();
|
||||||
|
|
||||||
for (const auto& value : section_map)
|
for (const auto& value : section_map)
|
||||||
{
|
{
|
||||||
|
@ -280,7 +280,7 @@ void INIGameConfigLayerLoader::Save(Config::Layer* layer)
|
||||||
if (layer->GetLayer() != Config::LayerType::LocalGame)
|
if (layer->GetLayer() != Config::LayerType::LocalGame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IniFile ini;
|
Common::IniFile ini;
|
||||||
for (const std::string& file_name : GetGameIniFilenames(m_id, m_revision))
|
for (const std::string& file_name : GetGameIniFilenames(m_id, m_revision))
|
||||||
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + file_name, true);
|
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + file_name, true);
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ void INIGameConfigLayerLoader::Save(Config::Layer* layer)
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
IniFile::Section* ini_section = ini.GetOrCreateSection(ini_location.first);
|
auto* ini_section = ini.GetOrCreateSection(ini_location.first);
|
||||||
ini_section->Set(ini_location.second, *value);
|
ini_section->Set(ini_location.second, *value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -393,40 +393,40 @@ DiscIO::Language SConfig::GetLanguageAdjustedForRegion(bool wii, DiscIO::Region
|
||||||
return language;
|
return language;
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile SConfig::LoadDefaultGameIni() const
|
Common::IniFile SConfig::LoadDefaultGameIni() const
|
||||||
{
|
{
|
||||||
return LoadDefaultGameIni(GetGameID(), m_revision);
|
return LoadDefaultGameIni(GetGameID(), m_revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile SConfig::LoadLocalGameIni() const
|
Common::IniFile SConfig::LoadLocalGameIni() const
|
||||||
{
|
{
|
||||||
return LoadLocalGameIni(GetGameID(), m_revision);
|
return LoadLocalGameIni(GetGameID(), m_revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile SConfig::LoadGameIni() const
|
Common::IniFile SConfig::LoadGameIni() const
|
||||||
{
|
{
|
||||||
return LoadGameIni(GetGameID(), m_revision);
|
return LoadGameIni(GetGameID(), m_revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile SConfig::LoadDefaultGameIni(const std::string& id, std::optional<u16> revision)
|
Common::IniFile SConfig::LoadDefaultGameIni(const std::string& id, std::optional<u16> revision)
|
||||||
{
|
{
|
||||||
IniFile game_ini;
|
Common::IniFile game_ini;
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
||||||
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
||||||
return game_ini;
|
return game_ini;
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile SConfig::LoadLocalGameIni(const std::string& id, std::optional<u16> revision)
|
Common::IniFile SConfig::LoadLocalGameIni(const std::string& id, std::optional<u16> revision)
|
||||||
{
|
{
|
||||||
IniFile game_ini;
|
Common::IniFile game_ini;
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
||||||
game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
||||||
return game_ini;
|
return game_ini;
|
||||||
}
|
}
|
||||||
|
|
||||||
IniFile SConfig::LoadGameIni(const std::string& id, std::optional<u16> revision)
|
Common::IniFile SConfig::LoadGameIni(const std::string& id, std::optional<u16> revision)
|
||||||
{
|
{
|
||||||
IniFile game_ini;
|
Common::IniFile game_ini;
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
||||||
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
|
||||||
|
|
|
@ -14,7 +14,10 @@
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
class IniFile;
|
class IniFile;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
|
@ -81,13 +84,13 @@ struct SConfig
|
||||||
DiscIO::Language GetCurrentLanguage(bool wii) const;
|
DiscIO::Language GetCurrentLanguage(bool wii) const;
|
||||||
DiscIO::Language GetLanguageAdjustedForRegion(bool wii, DiscIO::Region region) const;
|
DiscIO::Language GetLanguageAdjustedForRegion(bool wii, DiscIO::Region region) const;
|
||||||
|
|
||||||
IniFile LoadDefaultGameIni() const;
|
Common::IniFile LoadDefaultGameIni() const;
|
||||||
IniFile LoadLocalGameIni() const;
|
Common::IniFile LoadLocalGameIni() const;
|
||||||
IniFile LoadGameIni() const;
|
Common::IniFile LoadGameIni() const;
|
||||||
|
|
||||||
static IniFile LoadDefaultGameIni(const std::string& id, std::optional<u16> revision);
|
static Common::IniFile LoadDefaultGameIni(const std::string& id, std::optional<u16> revision);
|
||||||
static IniFile LoadLocalGameIni(const std::string& id, std::optional<u16> revision);
|
static Common::IniFile LoadLocalGameIni(const std::string& id, std::optional<u16> revision);
|
||||||
static IniFile LoadGameIni(const std::string& id, std::optional<u16> revision);
|
static Common::IniFile LoadGameIni(const std::string& id, std::optional<u16> revision);
|
||||||
|
|
||||||
SConfig(const SConfig&) = delete;
|
SConfig(const SConfig&) = delete;
|
||||||
SConfig& operator=(const SConfig&) = delete;
|
SConfig& operator=(const SConfig&) = delete;
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "Common/Timer.h"
|
#include "Common/Timer.h"
|
||||||
#include "Common/Version.h"
|
#include "Common/Version.h"
|
||||||
|
|
||||||
|
#include "Core/AchievementManager.h"
|
||||||
#include "Core/Boot/Boot.h"
|
#include "Core/Boot/Boot.h"
|
||||||
#include "Core/BootManager.h"
|
#include "Core/BootManager.h"
|
||||||
#include "Core/Config/MainSettings.h"
|
#include "Core/Config/MainSettings.h"
|
||||||
|
@ -283,6 +284,10 @@ void Stop() // - Hammertime!
|
||||||
if (GetState() == State::Stopping || GetState() == State::Uninitialized)
|
if (GetState() == State::Stopping || GetState() == State::Uninitialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
AchievementManager::GetInstance()->CloseGame();
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
s_is_stopping = true;
|
s_is_stopping = true;
|
||||||
|
|
||||||
CallOnStateChangedCallbacks(State::Stopping);
|
CallOnStateChangedCallbacks(State::Stopping);
|
||||||
|
@ -435,7 +440,8 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
|
||||||
{
|
{
|
||||||
DeclareAsCPUThread();
|
DeclareAsCPUThread();
|
||||||
|
|
||||||
if (Core::System::GetInstance().IsDualCoreMode())
|
auto& system = Core::System::GetInstance();
|
||||||
|
if (system.IsDualCoreMode())
|
||||||
Common::SetCurrentThreadName("FIFO player thread");
|
Common::SetCurrentThreadName("FIFO player thread");
|
||||||
else
|
else
|
||||||
Common::SetCurrentThreadName("FIFO-GPU thread");
|
Common::SetCurrentThreadName("FIFO-GPU thread");
|
||||||
|
@ -443,15 +449,14 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
|
||||||
// Enter CPU run loop. When we leave it - we are done.
|
// Enter CPU run loop. When we leave it - we are done.
|
||||||
if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore())
|
if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore())
|
||||||
{
|
{
|
||||||
PowerPC::InjectExternalCPUCore(cpu_core.get());
|
system.GetPowerPC().InjectExternalCPUCore(cpu_core.get());
|
||||||
s_is_started = true;
|
s_is_started = true;
|
||||||
|
|
||||||
CPUSetInitialExecutionState();
|
CPUSetInitialExecutionState();
|
||||||
auto& system = Core::System::GetInstance();
|
|
||||||
system.GetCPU().Run();
|
system.GetCPU().Run();
|
||||||
|
|
||||||
s_is_started = false;
|
s_is_started = false;
|
||||||
PowerPC::InjectExternalCPUCore(nullptr);
|
system.GetPowerPC().InjectExternalCPUCore(nullptr);
|
||||||
FifoPlayer::GetInstance().Close();
|
FifoPlayer::GetInstance().Close();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -552,7 +557,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
|
||||||
HLE::Clear();
|
HLE::Clear();
|
||||||
|
|
||||||
CPUThreadGuard guard(system);
|
CPUThreadGuard guard(system);
|
||||||
PowerPC::debug_interface.Clear(guard);
|
system.GetPowerPC().GetDebugInterface().Clear(guard);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
VideoBackendBase::PopulateBackendInfo();
|
VideoBackendBase::PopulateBackendInfo();
|
||||||
|
@ -590,7 +595,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
|
||||||
system.GetCPU().Break();
|
system.GetCPU().Break();
|
||||||
|
|
||||||
// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
|
// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
|
|
||||||
// Determine the CPU thread function
|
// Determine the CPU thread function
|
||||||
void (*cpuThreadFunc)(const std::optional<std::string>& savestate_path, bool delete_savestate);
|
void (*cpuThreadFunc)(const std::optional<std::string>& savestate_path, bool delete_savestate);
|
||||||
|
@ -628,11 +633,11 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
|
||||||
// Setup our core
|
// Setup our core
|
||||||
if (Config::Get(Config::MAIN_CPU_CORE) != PowerPC::CPUCore::Interpreter)
|
if (Config::Get(Config::MAIN_CPU_CORE) != PowerPC::CPUCore::Interpreter)
|
||||||
{
|
{
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::JIT);
|
system.GetPowerPC().SetMode(PowerPC::CoreMode::JIT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
|
@ -901,7 +906,7 @@ void UpdateTitle()
|
||||||
{
|
{
|
||||||
// Settings are shown the same for both extended and summary info
|
// Settings are shown the same for both extended and summary info
|
||||||
const std::string SSettings = fmt::format(
|
const std::string SSettings = fmt::format(
|
||||||
"{} {} | {} | {}", PowerPC::GetCPUName(),
|
"{} {} | {} | {}", Core::System::GetInstance().GetPowerPC().GetCPUName(),
|
||||||
Core::System::GetInstance().IsDualCoreMode() ? "DC" : "SC", g_video_backend->GetDisplayName(),
|
Core::System::GetInstance().IsDualCoreMode() ? "DC" : "SC", g_video_backend->GetDisplayName(),
|
||||||
Config::Get(Config::MAIN_DSP_HLE) ? "HLE" : "LLE");
|
Config::Get(Config::MAIN_DSP_HLE) ? "HLE" : "LLE");
|
||||||
|
|
||||||
|
|
|
@ -303,8 +303,8 @@ void CoreTimingManager::MoveEvents()
|
||||||
|
|
||||||
void CoreTimingManager::Advance()
|
void CoreTimingManager::Advance()
|
||||||
{
|
{
|
||||||
auto& system = m_system;
|
auto& power_pc = m_system.GetPowerPC();
|
||||||
auto& ppc_state = m_system.GetPPCState();
|
auto& ppc_state = power_pc.GetPPCState();
|
||||||
|
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ void CoreTimingManager::Advance()
|
||||||
m_event_queue.pop_back();
|
m_event_queue.pop_back();
|
||||||
|
|
||||||
Throttle(evt.time);
|
Throttle(evt.time);
|
||||||
evt.type->callback(system, evt.userdata, m_globals.global_timer - evt.time);
|
evt.type->callback(m_system, evt.userdata, m_globals.global_timer - evt.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_is_global_timer_sane = false;
|
m_is_global_timer_sane = false;
|
||||||
|
@ -341,7 +341,7 @@ void CoreTimingManager::Advance()
|
||||||
// It's important to do this after processing events otherwise any exceptions will be delayed
|
// It's important to do this after processing events otherwise any exceptions will be delayed
|
||||||
// until the next slice:
|
// until the next slice:
|
||||||
// Pokemon Box refuses to boot if the first exception from the audio DMA is received late
|
// Pokemon Box refuses to boot if the first exception from the audio DMA is received late
|
||||||
PowerPC::CheckExternalExceptions();
|
power_pc.CheckExternalExceptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTimingManager::Throttle(const s64 target_cycle)
|
void CoreTimingManager::Throttle(const s64 target_cycle)
|
||||||
|
|
|
@ -32,7 +32,7 @@ void AddAutoBreakpoints()
|
||||||
{
|
{
|
||||||
Common::Symbol* symbol = g_symbolDB.GetSymbolFromName(bp);
|
Common::Symbol* symbol = g_symbolDB.GetSymbolFromName(bp);
|
||||||
if (symbol)
|
if (symbol)
|
||||||
PowerPC::breakpoints.Add(symbol->address, false);
|
Core::System::GetInstance().GetPowerPC().GetBreakPoints().Add(symbol->address, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,6 +36,7 @@ void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPa
|
||||||
if (!PowerPC::MMU::HostIsRAMAddress(guard, address))
|
if (!PowerPC::MMU::HostIsRAMAddress(guard, address))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto& power_pc = guard.GetSystem().GetPowerPC();
|
||||||
for (u32 offset = 0; offset < size; ++offset)
|
for (u32 offset = 0; offset < size; ++offset)
|
||||||
{
|
{
|
||||||
if (store_existing_value)
|
if (store_existing_value)
|
||||||
|
@ -50,11 +51,11 @@ void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPa
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((address + offset) % 4) == 3)
|
if (((address + offset) % 4) == 3)
|
||||||
PowerPC::ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4));
|
power_pc.ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4));
|
||||||
}
|
}
|
||||||
if (((address + size) % 4) != 0)
|
if (((address + size) % 4) != 0)
|
||||||
{
|
{
|
||||||
PowerPC::ScheduleInvalidateCacheThreadSafe(
|
power_pc.ScheduleInvalidateCacheThreadSafe(
|
||||||
Common::AlignDown(address + static_cast<u32>(size), 4));
|
Common::AlignDown(address + static_cast<u32>(size), 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,40 +348,41 @@ bool PPCDebugInterface::IsAlive() const
|
||||||
|
|
||||||
bool PPCDebugInterface::IsBreakpoint(u32 address) const
|
bool PPCDebugInterface::IsBreakpoint(u32 address) const
|
||||||
{
|
{
|
||||||
return PowerPC::breakpoints.IsAddressBreakPoint(address);
|
return m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::SetBreakpoint(u32 address)
|
void PPCDebugInterface::SetBreakpoint(u32 address)
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.Add(address);
|
m_system.GetPowerPC().GetBreakPoints().Add(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::ClearBreakpoint(u32 address)
|
void PPCDebugInterface::ClearBreakpoint(u32 address)
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.Remove(address);
|
m_system.GetPowerPC().GetBreakPoints().Remove(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::ClearAllBreakpoints()
|
void PPCDebugInterface::ClearAllBreakpoints()
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.Clear();
|
m_system.GetPowerPC().GetBreakPoints().Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::ToggleBreakpoint(u32 address)
|
void PPCDebugInterface::ToggleBreakpoint(u32 address)
|
||||||
{
|
{
|
||||||
if (PowerPC::breakpoints.IsAddressBreakPoint(address))
|
auto& breakpoints = m_system.GetPowerPC().GetBreakPoints();
|
||||||
PowerPC::breakpoints.Remove(address);
|
if (breakpoints.IsAddressBreakPoint(address))
|
||||||
|
breakpoints.Remove(address);
|
||||||
else
|
else
|
||||||
PowerPC::breakpoints.Add(address);
|
breakpoints.Add(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::ClearAllMemChecks()
|
void PPCDebugInterface::ClearAllMemChecks()
|
||||||
{
|
{
|
||||||
PowerPC::memchecks.Clear();
|
m_system.GetPowerPC().GetMemChecks().Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PPCDebugInterface::IsMemCheck(u32 address, size_t size) const
|
bool PPCDebugInterface::IsMemCheck(u32 address, size_t size) const
|
||||||
{
|
{
|
||||||
return PowerPC::memchecks.GetMemCheck(address, size) != nullptr;
|
return m_system.GetPowerPC().GetMemChecks().GetMemCheck(address, size) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool log)
|
void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool log)
|
||||||
|
@ -397,11 +399,11 @@ void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool
|
||||||
MemCheck.log_on_hit = log;
|
MemCheck.log_on_hit = log;
|
||||||
MemCheck.break_on_hit = true;
|
MemCheck.break_on_hit = true;
|
||||||
|
|
||||||
PowerPC::memchecks.Add(std::move(MemCheck));
|
m_system.GetPowerPC().GetMemChecks().Add(std::move(MemCheck));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::memchecks.Remove(address);
|
m_system.GetPowerPC().GetMemChecks().Remove(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
@ -101,14 +102,9 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file,
|
||||||
part_start = offset;
|
part_start = offset;
|
||||||
// Copy cpmem now, because end_of_primitives isn't triggered until the first opcode after
|
// Copy cpmem now, because end_of_primitives isn't triggered until the first opcode after
|
||||||
// primitive data, and the first opcode might update cpmem
|
// primitive data, and the first opcode might update cpmem
|
||||||
#ifdef __GNUC__
|
static_assert(std::is_trivially_copyable_v<CPState>);
|
||||||
#pragma GCC diagnostic push
|
std::memcpy(static_cast<void*>(&cpmem), static_cast<const void*>(&analyzer.m_cpmem),
|
||||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
sizeof(CPState));
|
||||||
#endif
|
|
||||||
std::memcpy(&cpmem, &analyzer.m_cpmem, sizeof(CPState));
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (analyzer.m_end_of_primitives)
|
if (analyzer.m_end_of_primitives)
|
||||||
{
|
{
|
||||||
|
|
|
@ -268,9 +268,7 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
|
||||||
RecordInitialVideoMemory();
|
RecordInitialVideoMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
const auto& fifo = Core::System::GetInstance().GetCommandProcessor().GetFifo();
|
||||||
auto& command_processor = system.GetCommandProcessor();
|
|
||||||
const auto& fifo = command_processor.GetFifo();
|
|
||||||
EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
|
EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
|
||||||
fifo.CPEnd.load(std::memory_order_relaxed));
|
fifo.CPEnd.load(std::memory_order_relaxed));
|
||||||
},
|
},
|
||||||
|
|
|
@ -127,11 +127,11 @@ std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded, bo
|
||||||
return gcodes;
|
return gcodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<GeckoCode> LoadCodes(const IniFile& globalIni, const IniFile& localIni)
|
std::vector<GeckoCode> LoadCodes(const Common::IniFile& globalIni, const Common::IniFile& localIni)
|
||||||
{
|
{
|
||||||
std::vector<GeckoCode> gcodes;
|
std::vector<GeckoCode> gcodes;
|
||||||
|
|
||||||
for (const IniFile* ini : {&globalIni, &localIni})
|
for (const auto* ini : {&globalIni, &localIni})
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
ini->GetLines("Gecko", &lines, false);
|
ini->GetLines("Gecko", &lines, false);
|
||||||
|
@ -239,7 +239,7 @@ static void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcod
|
||||||
lines.push_back('*' + note);
|
lines.push_back('*' + note);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes)
|
void SaveCodes(Common::IniFile& inifile, const std::vector<GeckoCode>& gcodes)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::vector<std::string> enabled_lines;
|
std::vector<std::string> enabled_lines;
|
||||||
|
|
|
@ -9,14 +9,17 @@
|
||||||
|
|
||||||
#include "Core/GeckoCode.h"
|
#include "Core/GeckoCode.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
class IniFile;
|
class IniFile;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Gecko
|
namespace Gecko
|
||||||
{
|
{
|
||||||
std::vector<GeckoCode> LoadCodes(const IniFile& globalIni, const IniFile& localIni);
|
std::vector<GeckoCode> LoadCodes(const Common::IniFile& globalIni, const Common::IniFile& localIni);
|
||||||
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded,
|
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded,
|
||||||
bool use_https = true);
|
bool use_https = true);
|
||||||
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes);
|
void SaveCodes(Common::IniFile& inifile, const std::vector<GeckoCode>& gcodes);
|
||||||
|
|
||||||
std::optional<GeckoCode::Code> DeserializeLine(const std::string& line);
|
std::optional<GeckoCode::Code> DeserializeLine(const std::string& line);
|
||||||
} // namespace Gecko
|
} // namespace Gecko
|
||||||
|
|
|
@ -203,7 +203,7 @@ HookFlag GetHookFlagsByIndex(u32 index)
|
||||||
bool IsEnabled(HookFlag flag)
|
bool IsEnabled(HookFlag flag)
|
||||||
{
|
{
|
||||||
return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) ||
|
return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) ||
|
||||||
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter;
|
Core::System::GetInstance().GetPowerPC().GetMode() == PowerPC::CoreMode::Interpreter;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 UnPatch(Core::System& system, std::string_view patch_name)
|
u32 UnPatch(Core::System& system, std::string_view patch_name)
|
||||||
|
|
|
@ -19,19 +19,21 @@
|
||||||
|
|
||||||
namespace CPU
|
namespace CPU
|
||||||
{
|
{
|
||||||
CPUManager::CPUManager() = default;
|
CPUManager::CPUManager(Core::System& system) : m_system(system)
|
||||||
|
{
|
||||||
|
}
|
||||||
CPUManager::~CPUManager() = default;
|
CPUManager::~CPUManager() = default;
|
||||||
|
|
||||||
void CPUManager::Init(PowerPC::CPUCore cpu_core)
|
void CPUManager::Init(PowerPC::CPUCore cpu_core)
|
||||||
{
|
{
|
||||||
PowerPC::Init(cpu_core);
|
m_system.GetPowerPC().Init(cpu_core);
|
||||||
m_state = State::Stepping;
|
m_state = State::Stepping;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPUManager::Shutdown()
|
void CPUManager::Shutdown()
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
PowerPC::Shutdown();
|
m_system.GetPowerPC().Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires holding m_state_change_lock
|
// Requires holding m_state_change_lock
|
||||||
|
@ -62,11 +64,11 @@ void CPUManager::ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
|
||||||
|
|
||||||
void CPUManager::Run()
|
void CPUManager::Run()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& power_pc = m_system.GetPowerPC();
|
||||||
|
|
||||||
// Updating the host CPU's rounding mode must be done on the CPU thread.
|
// Updating the host CPU's rounding mode must be done on the CPU thread.
|
||||||
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
|
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
|
||||||
PowerPC::RoundingModeUpdated();
|
PowerPC::RoundingModeUpdated(power_pc.GetPPCState());
|
||||||
|
|
||||||
std::unique_lock state_lock(m_state_change_lock);
|
std::unique_lock state_lock(m_state_change_lock);
|
||||||
while (m_state != State::PowerDown)
|
while (m_state != State::PowerDown)
|
||||||
|
@ -85,22 +87,22 @@ void CPUManager::Run()
|
||||||
// SingleStep so that the "continue", "step over" and "step out" debugger functions
|
// SingleStep so that the "continue", "step over" and "step out" debugger functions
|
||||||
// work when the PC is at a breakpoint at the beginning of the block
|
// work when the PC is at a breakpoint at the beginning of the block
|
||||||
// If watchpoints are enabled, any instruction could be a breakpoint.
|
// If watchpoints are enabled, any instruction could be a breakpoint.
|
||||||
if (PowerPC::GetMode() != PowerPC::CoreMode::Interpreter)
|
if (power_pc.GetMode() != PowerPC::CoreMode::Interpreter)
|
||||||
{
|
{
|
||||||
if (PowerPC::breakpoints.IsAddressBreakPoint(system.GetPPCState().pc) ||
|
if (power_pc.GetBreakPoints().IsAddressBreakPoint(power_pc.GetPPCState().pc) ||
|
||||||
PowerPC::memchecks.HasAny())
|
power_pc.GetMemChecks().HasAny())
|
||||||
{
|
{
|
||||||
m_state = State::Stepping;
|
m_state = State::Stepping;
|
||||||
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
PowerPC::CoreMode old_mode = power_pc.GetMode();
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
power_pc.SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
PowerPC::SingleStep();
|
power_pc.SingleStep();
|
||||||
PowerPC::SetMode(old_mode);
|
power_pc.SetMode(old_mode);
|
||||||
m_state = State::Running;
|
m_state = State::Running;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter a fast runloop
|
// Enter a fast runloop
|
||||||
PowerPC::RunLoop();
|
power_pc.RunLoop();
|
||||||
|
|
||||||
state_lock.lock();
|
state_lock.lock();
|
||||||
m_state_cpu_thread_active = false;
|
m_state_cpu_thread_active = false;
|
||||||
|
@ -147,7 +149,7 @@ void CPUManager::Run()
|
||||||
m_state_cpu_thread_active = true;
|
m_state_cpu_thread_active = true;
|
||||||
state_lock.unlock();
|
state_lock.unlock();
|
||||||
|
|
||||||
PowerPC::SingleStep();
|
power_pc.SingleStep();
|
||||||
|
|
||||||
state_lock.lock();
|
state_lock.lock();
|
||||||
m_state_cpu_thread_active = false;
|
m_state_cpu_thread_active = false;
|
||||||
|
|
|
@ -12,7 +12,10 @@ namespace Common
|
||||||
{
|
{
|
||||||
class Event;
|
class Event;
|
||||||
}
|
}
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
namespace PowerPC
|
namespace PowerPC
|
||||||
{
|
{
|
||||||
enum class CPUCore;
|
enum class CPUCore;
|
||||||
|
@ -30,7 +33,7 @@ enum class State
|
||||||
class CPUManager
|
class CPUManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CPUManager();
|
explicit CPUManager(Core::System& system);
|
||||||
CPUManager(const CPUManager& other) = delete;
|
CPUManager(const CPUManager& other) = delete;
|
||||||
CPUManager(CPUManager&& other) = delete;
|
CPUManager(CPUManager&& other) = delete;
|
||||||
CPUManager& operator=(const CPUManager& other) = delete;
|
CPUManager& operator=(const CPUManager& other) = delete;
|
||||||
|
@ -130,5 +133,7 @@ private:
|
||||||
bool m_state_cpu_step_instruction = false;
|
bool m_state_cpu_step_instruction = false;
|
||||||
Common::Event* m_state_cpu_step_instruction_sync = nullptr;
|
Common::Event* m_state_cpu_step_instruction_sync = nullptr;
|
||||||
std::queue<std::function<void()>> m_pending_jobs;
|
std::queue<std::function<void()>> m_pending_jobs;
|
||||||
|
|
||||||
|
Core::System& m_system;
|
||||||
};
|
};
|
||||||
} // namespace CPU
|
} // namespace CPU
|
||||||
|
|
|
@ -44,21 +44,21 @@ constexpr u32 VOICE_16_BIT_FLAG = 2;
|
||||||
|
|
||||||
// These are used in the pre-2020 versions version
|
// These are used in the pre-2020 versions version
|
||||||
constexpr u32 VOICE_PAUSE_OLD = 0x00000004;
|
constexpr u32 VOICE_PAUSE_OLD = 0x00000004;
|
||||||
constexpr u32 VOICE_LOOP_OLD = 0x00000008; // not used by the DSP
|
constexpr u32 VOICE_LOOP_OLD [[maybe_unused]] = 0x00000008; // not used by the DSP
|
||||||
constexpr u32 VOICE_ONCE_OLD = 0x00000010; // not used by the DSP
|
constexpr u32 VOICE_ONCE_OLD [[maybe_unused]] = 0x00000010; // not used by the DSP
|
||||||
constexpr u32 VOICE_STREAM_OLD = 0x00000020; // not used by the DSP
|
constexpr u32 VOICE_STREAM_OLD [[maybe_unused]] = 0x00000020; // not used by the DSP
|
||||||
|
|
||||||
// These were changed in the 2020 version to account for the different flags
|
// These were changed in the 2020 version to account for the different flags
|
||||||
constexpr u32 VOICE_PAUSE_NEW = 0x00000008;
|
constexpr u32 VOICE_PAUSE_NEW = 0x00000008;
|
||||||
constexpr u32 VOICE_LOOP_NEW = 0x00000010; // not used by the DSP
|
constexpr u32 VOICE_LOOP_NEW [[maybe_unused]] = 0x00000010; // not used by the DSP
|
||||||
constexpr u32 VOICE_ONCE_NEW = 0x00000020; // not used by the DSP
|
constexpr u32 VOICE_ONCE_NEW [[maybe_unused]] = 0x00000020; // not used by the DSP
|
||||||
constexpr u32 VOICE_STREAM_NEW = 0x00000040; // not used by the DSP
|
constexpr u32 VOICE_STREAM_NEW [[maybe_unused]] = 0x00000040; // not used by the DSP
|
||||||
|
|
||||||
// These did not change between versions
|
// These did not change between versions
|
||||||
constexpr u32 VOICE_FINISHED = 0x00100000;
|
constexpr u32 VOICE_FINISHED = 0x00100000;
|
||||||
constexpr u32 VOICE_STOPPED = 0x00200000; // not used by the DSP
|
constexpr u32 VOICE_STOPPED [[maybe_unused]] = 0x00200000; // not used by the DSP
|
||||||
constexpr u32 VOICE_RUNNING = 0x40000000;
|
constexpr u32 VOICE_RUNNING = 0x40000000;
|
||||||
constexpr u32 VOICE_USED = 0x80000000; // not used by the DSP
|
constexpr u32 VOICE_USED [[maybe_unused]] = 0x80000000; // not used by the DSP
|
||||||
|
|
||||||
// 1<<4 = scale gain by 1/1, 2<<2 = PCM decoding from ARAM, 1<<0 = 8-bit reads
|
// 1<<4 = scale gain by 1/1, 2<<2 = PCM decoding from ARAM, 1<<0 = 8-bit reads
|
||||||
constexpr u32 ACCELERATOR_FORMAT_8_BIT = 0x0019;
|
constexpr u32 ACCELERATOR_FORMAT_8_BIT = 0x0019;
|
||||||
|
|
|
@ -384,7 +384,8 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
// only if contain data
|
// only if contain data
|
||||||
if (static_cast<int>(this_seq - ref->ack_num) >= 0 && data.size() >= size)
|
if (static_cast<int>(this_seq - ref->ack_num) >= 0 &&
|
||||||
|
data.size() >= static_cast<size_t>(size))
|
||||||
{
|
{
|
||||||
ref->tcp_socket.send(data.data(), size);
|
ref->tcp_socket.send(data.data(), size);
|
||||||
ref->ack_num += size;
|
ref->ack_num += size;
|
||||||
|
|
|
@ -45,7 +45,8 @@ bool CEXIETHERNET::TAPServerNetworkInterface::Activate()
|
||||||
|
|
||||||
if (connect(fd, reinterpret_cast<sockaddr*>(&sun), sizeof(sun)) == -1)
|
if (connect(fd, reinterpret_cast<sockaddr*>(&sun), sizeof(sun)) == -1)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SP1, "Couldn't connect socket ({}), unable to init BBA", LastStrerrorString());
|
ERROR_LOG_FMT(SP1, "Couldn't connect socket ({}), unable to init BBA",
|
||||||
|
Common::LastStrerrorString());
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
return false;
|
return false;
|
||||||
|
@ -99,14 +100,14 @@ void CEXIETHERNET::TAPServerNetworkInterface::ReadThreadHandler()
|
||||||
u16 size;
|
u16 size;
|
||||||
if (read(fd, &size, 2) != 2)
|
if (read(fd, &size, 2) != 2)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SP1, "Failed to read size field from BBA: {}", LastStrerrorString());
|
ERROR_LOG_FMT(SP1, "Failed to read size field from BBA: {}", Common::LastStrerrorString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int read_bytes = read(fd, m_eth_ref->mRecvBuffer.get(), size);
|
int read_bytes = read(fd, m_eth_ref->mRecvBuffer.get(), size);
|
||||||
if (read_bytes < 0)
|
if (read_bytes < 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SP1, "Failed to read packet data from BBA: {}", LastStrerrorString());
|
ERROR_LOG_FMT(SP1, "Failed to read packet data from BBA: {}", Common::LastStrerrorString());
|
||||||
}
|
}
|
||||||
else if (readEnabled.IsSet())
|
else if (readEnabled.IsSet())
|
||||||
{
|
{
|
||||||
|
|
|
@ -448,7 +448,7 @@ void CEXIETHERNET::SendFromDirectFIFO()
|
||||||
const u8* frame = tx_fifo.get();
|
const u8* frame = tx_fifo.get();
|
||||||
const u16 size = Common::BitCastPtr<u16>(&mBbaMem[BBA_TXFIFOCNT]);
|
const u16 size = Common::BitCastPtr<u16>(&mBbaMem[BBA_TXFIFOCNT]);
|
||||||
if (m_network_interface->SendFrame(frame, size))
|
if (m_network_interface->SendFrame(frame, size))
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogBBA(frame, size);
|
m_system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogBBA(frame, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEXIETHERNET::SendFromPacketBuffer()
|
void CEXIETHERNET::SendFromPacketBuffer()
|
||||||
|
@ -561,7 +561,8 @@ bool CEXIETHERNET::RecvHandlePacket()
|
||||||
INFO_LOG_FMT(SP1, "{:x} {:x} {:x} {:x}", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP),
|
INFO_LOG_FMT(SP1, "{:x} {:x} {:x} {:x}", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP),
|
||||||
page_ptr(BBA_RHBP));
|
page_ptr(BBA_RHBP));
|
||||||
#endif
|
#endif
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogBBA(mRecvBuffer.get(), mRecvBufferLength);
|
m_system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogBBA(mRecvBuffer.get(),
|
||||||
|
mRecvBufferLength);
|
||||||
write_ptr = &mBbaMem[page_ptr(BBA_RWP) << 8];
|
write_ptr = &mBbaMem[page_ptr(BBA_RWP) << 8];
|
||||||
|
|
||||||
descriptor = (Descriptor*)write_ptr;
|
descriptor = (Descriptor*)write_ptr;
|
||||||
|
|
|
@ -61,14 +61,7 @@ MemoryInterfaceManager::~MemoryInterfaceManager() = default;
|
||||||
void MemoryInterfaceManager::Init()
|
void MemoryInterfaceManager::Init()
|
||||||
{
|
{
|
||||||
static_assert(std::is_trivially_copyable_v<MIMemStruct>);
|
static_assert(std::is_trivially_copyable_v<MIMemStruct>);
|
||||||
#ifdef __GNUC__
|
std::memset(static_cast<void*>(&m_mi_mem), 0, sizeof(MIMemStruct));
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
|
||||||
#endif
|
|
||||||
std::memset(&m_mi_mem, 0, sizeof(MIMemStruct));
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryInterfaceManager::Shutdown()
|
void MemoryInterfaceManager::Shutdown()
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
namespace ProcessorInterface
|
namespace ProcessorInterface
|
||||||
{
|
{
|
||||||
constexpr u32 FLIPPER_REV_A = 0x046500B0;
|
constexpr u32 FLIPPER_REV_A [[maybe_unused]] = 0x046500B0;
|
||||||
constexpr u32 FLIPPER_REV_B = 0x146500B1;
|
constexpr u32 FLIPPER_REV_B [[maybe_unused]] = 0x146500B1;
|
||||||
constexpr u32 FLIPPER_REV_C = 0x246500B1;
|
constexpr u32 FLIPPER_REV_C = 0x246500B1;
|
||||||
|
|
||||||
ProcessorInterfaceManager::ProcessorInterfaceManager(Core::System& system) : m_system(system)
|
ProcessorInterfaceManager::ProcessorInterfaceManager(Core::System& system) : m_system(system)
|
||||||
|
|
|
@ -223,7 +223,7 @@ void TimeBaseSet()
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& core_timing = system.GetCoreTiming();
|
||||||
core_timing.SetFakeTBStartTicks(core_timing.GetTicks());
|
core_timing.SetFakeTBStartTicks(core_timing.GetTicks());
|
||||||
core_timing.SetFakeTBStartValue(PowerPC::ReadFullTimeBaseValue());
|
core_timing.SetFakeTBStartValue(system.GetPowerPC().ReadFullTimeBaseValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetFakeTimeBase()
|
u64 GetFakeTimeBase()
|
||||||
|
|
|
@ -136,14 +136,8 @@ static bool DeserializeExtensionState(DesiredWiimoteState* state,
|
||||||
return false;
|
return false;
|
||||||
auto& e = state->extension.data.emplace<T>();
|
auto& e = state->extension.data.emplace<T>();
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
#ifdef __GNUC__
|
std::memcpy(static_cast<void*>(&e), static_cast<const void*>(&serialized.data[offset]),
|
||||||
#pragma GCC diagnostic push
|
sizeof(T));
|
||||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
|
||||||
#endif
|
|
||||||
std::memcpy(&e, &serialized.data[offset], sizeof(T));
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ bool IsPressed(int id, bool held)
|
||||||
// TODO: Remove this at a future date when we're confident most configs are migrated.
|
// TODO: Remove this at a future date when we're confident most configs are migrated.
|
||||||
static void LoadLegacyConfig(ControllerEmu::EmulatedController* controller)
|
static void LoadLegacyConfig(ControllerEmu::EmulatedController* controller)
|
||||||
{
|
{
|
||||||
IniFile inifile;
|
Common::IniFile inifile;
|
||||||
if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Hotkeys.ini"))
|
if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Hotkeys.ini"))
|
||||||
{
|
{
|
||||||
if (!inifile.Exists("Hotkeys") && inifile.Exists("Hotkeys1"))
|
if (!inifile.Exists("Hotkeys") && inifile.Exists("Hotkeys1"))
|
||||||
|
|
|
@ -24,35 +24,18 @@
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
#include "DiscIO/Volume.h"
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
template <u32 addr>
|
constexpr u32 ADDRESS_DISR = 0x0D806000;
|
||||||
class RegisterWrapper
|
constexpr u32 ADDRESS_DICVR = 0x0D806004;
|
||||||
{
|
constexpr u32 ADDRESS_DICMDBUF0 = 0x0D806008;
|
||||||
public:
|
constexpr u32 ADDRESS_DICMDBUF1 = 0x0D80600C;
|
||||||
operator u32() const
|
constexpr u32 ADDRESS_DICMDBUF2 = 0x0D806010;
|
||||||
{
|
constexpr u32 ADDRESS_DIMAR = 0x0D806014;
|
||||||
auto& system = Core::System::GetInstance();
|
constexpr u32 ADDRESS_DILENGTH = 0x0D806018;
|
||||||
auto& memory = system.GetMemory();
|
constexpr u32 ADDRESS_DICR = 0x0D80601C;
|
||||||
return memory.GetMMIOMapping()->Read<u32>(addr);
|
constexpr u32 ADDRESS_DIIMMBUF = 0x0D806020;
|
||||||
}
|
|
||||||
void operator=(u32 rhs)
|
|
||||||
{
|
|
||||||
auto& system = Core::System::GetInstance();
|
|
||||||
auto& memory = system.GetMemory();
|
|
||||||
memory.GetMMIOMapping()->Write(addr, rhs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static RegisterWrapper<0x0D806000> DISR;
|
|
||||||
static RegisterWrapper<0x0D806004> DICVR;
|
|
||||||
static RegisterWrapper<0x0D806008> DICMDBUF0;
|
|
||||||
static RegisterWrapper<0x0D80600C> DICMDBUF1;
|
|
||||||
static RegisterWrapper<0x0D806010> DICMDBUF2;
|
|
||||||
static RegisterWrapper<0x0D806014> DIMAR;
|
|
||||||
static RegisterWrapper<0x0D806018> DILENGTH;
|
|
||||||
static RegisterWrapper<0x0D80601C> DICR;
|
|
||||||
static RegisterWrapper<0x0D806020> DIIMMBUF;
|
|
||||||
|
|
||||||
static RegisterWrapper<0x0D8000E0> HW_GPIO_OUT;
|
constexpr u32 ADDRESS_HW_GPIO_OUT = 0x0D8000E0;
|
||||||
static RegisterWrapper<0x0D800194> HW_RESETS;
|
constexpr u32 ADDRESS_HW_RESETS = 0x0D800194;
|
||||||
|
|
||||||
namespace IOS::HLE
|
namespace IOS::HLE
|
||||||
{
|
{
|
||||||
|
@ -169,6 +152,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& memory = system.GetMemory();
|
auto& memory = system.GetMemory();
|
||||||
|
auto* mmio = memory.GetMMIOMapping();
|
||||||
|
|
||||||
// DVDInterface's ExecuteCommand handles most of the work for most of these.
|
// DVDInterface's ExecuteCommand handles most of the work for most of these.
|
||||||
// The IOCtl callback is used to generate a reply afterwards.
|
// The IOCtl callback is used to generate a reply afterwards.
|
||||||
|
@ -176,14 +160,14 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
{
|
{
|
||||||
case DIIoctl::DVDLowInquiry:
|
case DIIoctl::DVDLowInquiry:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowInquiry");
|
INFO_LOG_FMT(IOS_DI, "DVDLowInquiry");
|
||||||
DICMDBUF0 = 0x12000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0x12000000);
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
return StartDMATransfer(0x20, request);
|
return StartDMATransfer(0x20, request);
|
||||||
case DIIoctl::DVDLowReadDiskID:
|
case DIIoctl::DVDLowReadDiskID:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskID");
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskID");
|
||||||
DICMDBUF0 = 0xA8000040;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xA8000040);
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
DICMDBUF2 = 0x20;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, 0x20);
|
||||||
return StartDMATransfer(0x20, request);
|
return StartDMATransfer(0x20, request);
|
||||||
// TODO: Include an additional read that happens on Wii discs, or at least
|
// TODO: Include an additional read that happens on Wii discs, or at least
|
||||||
// emulate its side effect of disabling DTK configuration
|
// emulate its side effect of disabling DTK configuration
|
||||||
|
@ -225,7 +209,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
return DIResult::CoverClosed;
|
return DIResult::CoverClosed;
|
||||||
case DIIoctl::DVDLowGetCoverRegister:
|
case DIIoctl::DVDLowGetCoverRegister:
|
||||||
{
|
{
|
||||||
const u32 dicvr = DICVR;
|
const u32 dicvr = mmio->Read<u32>(ADDRESS_DICVR);
|
||||||
DEBUG_LOG_FMT(IOS_DI, "DVDLowGetCoverRegister {:#010x}", dicvr);
|
DEBUG_LOG_FMT(IOS_DI, "DVDLowGetCoverRegister {:#010x}", dicvr);
|
||||||
return WriteIfFits(request, dicvr);
|
return WriteIfFits(request, dicvr);
|
||||||
}
|
}
|
||||||
|
@ -240,27 +224,27 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
{
|
{
|
||||||
const u8 position = memory.Read_U8(request.buffer_in + 7);
|
const u8 position = memory.Read_U8(request.buffer_in + 7);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdPhysical: position {:#04x}", position);
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdPhysical: position {:#04x}", position);
|
||||||
DICMDBUF0 = 0xAD000000 | (position << 8);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAD000000 | (position << 8));
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
DICMDBUF2 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
|
||||||
return StartDMATransfer(0x800, request);
|
return StartDMATransfer(0x800, request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowReadDvdCopyright:
|
case DIIoctl::DVDLowReadDvdCopyright:
|
||||||
{
|
{
|
||||||
const u8 position = memory.Read_U8(request.buffer_in + 7);
|
const u8 position = memory.Read_U8(request.buffer_in + 7);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdCopyright: position {:#04x}", position);
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdCopyright: position {:#04x}", position);
|
||||||
DICMDBUF0 = 0xAD010000 | (position << 8);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAD010000 | (position << 8));
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
DICMDBUF2 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowReadDvdDiscKey:
|
case DIIoctl::DVDLowReadDvdDiscKey:
|
||||||
{
|
{
|
||||||
const u8 position = memory.Read_U8(request.buffer_in + 7);
|
const u8 position = memory.Read_U8(request.buffer_in + 7);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdDiscKey: position {:#04x}", position);
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdDiscKey: position {:#04x}", position);
|
||||||
DICMDBUF0 = 0xAD020000 | (position << 8);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAD020000 | (position << 8));
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
DICMDBUF2 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
|
||||||
return StartDMATransfer(0x800, request);
|
return StartDMATransfer(0x800, request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowGetLength:
|
case DIIoctl::DVDLowGetLength:
|
||||||
|
@ -268,7 +252,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
return WriteIfFits(request, m_last_length);
|
return WriteIfFits(request, m_last_length);
|
||||||
case DIIoctl::DVDLowGetImmBuf:
|
case DIIoctl::DVDLowGetImmBuf:
|
||||||
{
|
{
|
||||||
const u32 diimmbuf = DIIMMBUF;
|
const u32 diimmbuf = mmio->Read<u32>(ADDRESS_DIIMMBUF);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowGetImmBuf {:#010x}", diimmbuf);
|
INFO_LOG_FMT(IOS_DI, "DVDLowGetImmBuf {:#010x}", diimmbuf);
|
||||||
return WriteIfFits(request, diimmbuf);
|
return WriteIfFits(request, diimmbuf);
|
||||||
}
|
}
|
||||||
|
@ -303,27 +287,27 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const bool spinup = memory.Read_U32(request.buffer_in + 4);
|
const bool spinup = memory.Read_U32(request.buffer_in + 4);
|
||||||
|
|
||||||
// The GPIO *disables* spinning up the drive. Normally handled via syscall 0x4e.
|
// The GPIO *disables* spinning up the drive. Normally handled via syscall 0x4e.
|
||||||
const u32 old_gpio = HW_GPIO_OUT;
|
const u32 old_gpio = mmio->Read<u32>(ADDRESS_HW_GPIO_OUT);
|
||||||
if (spinup)
|
if (spinup)
|
||||||
HW_GPIO_OUT = old_gpio & ~static_cast<u32>(GPIO::DI_SPIN);
|
mmio->Write<u32>(ADDRESS_HW_GPIO_OUT, old_gpio & ~static_cast<u32>(GPIO::DI_SPIN));
|
||||||
else
|
else
|
||||||
HW_GPIO_OUT = old_gpio | static_cast<u32>(GPIO::DI_SPIN);
|
mmio->Write<u32>(ADDRESS_HW_GPIO_OUT, old_gpio | static_cast<u32>(GPIO::DI_SPIN));
|
||||||
|
|
||||||
// Syscall 0x46 check_di_reset
|
// Syscall 0x46 check_di_reset
|
||||||
const bool was_resetting = (HW_RESETS & (1 << 10)) == 0;
|
const bool was_resetting = (mmio->Read<u32>(ADDRESS_HW_RESETS) & (1 << 10)) == 0;
|
||||||
if (was_resetting)
|
if (was_resetting)
|
||||||
{
|
{
|
||||||
// This route will not generally be taken in Dolphin but is included for completeness
|
// This route will not generally be taken in Dolphin but is included for completeness
|
||||||
// Syscall 0x45 deassert_di_reset
|
// Syscall 0x45 deassert_di_reset
|
||||||
HW_RESETS = HW_RESETS | (1 << 10);
|
mmio->Write<u32>(ADDRESS_HW_RESETS, mmio->Read<u32>(ADDRESS_HW_RESETS) | (1 << 10));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Syscall 0x44 assert_di_reset
|
// Syscall 0x44 assert_di_reset
|
||||||
HW_RESETS = HW_RESETS & ~(1 << 10);
|
mmio->Write<u32>(ADDRESS_HW_RESETS, mmio->Read<u32>(ADDRESS_HW_RESETS) & ~(1 << 10));
|
||||||
// Normally IOS sleeps for 12 microseconds here, but we can't easily emulate that
|
// Normally IOS sleeps for 12 microseconds here, but we can't easily emulate that
|
||||||
// Syscall 0x45 deassert_di_reset
|
// Syscall 0x45 deassert_di_reset
|
||||||
HW_RESETS = HW_RESETS | (1 << 10);
|
mmio->Write<u32>(ADDRESS_HW_RESETS, mmio->Read<u32>(ADDRESS_HW_RESETS) | (1 << 10));
|
||||||
}
|
}
|
||||||
ResetDIRegisters();
|
ResetDIRegisters();
|
||||||
return DIResult::Success;
|
return DIResult::Success;
|
||||||
|
@ -356,14 +340,14 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
if (range.start <= position && position <= range.end && range.start <= end &&
|
if (range.start <= position && position <= range.end && range.start <= end &&
|
||||||
end <= range.end)
|
end <= range.end)
|
||||||
{
|
{
|
||||||
DICMDBUF0 = 0xA8000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xA8000000);
|
||||||
DICMDBUF1 = position;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, position);
|
||||||
DICMDBUF2 = length;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, length);
|
||||||
if (range.is_error_001_range && Config::Get(Config::SESSION_SHOULD_FAKE_ERROR_001))
|
if (range.is_error_001_range && Config::Get(Config::SESSION_SHOULD_FAKE_ERROR_001))
|
||||||
{
|
{
|
||||||
DIMAR = request.buffer_out;
|
mmio->Write<u32>(ADDRESS_DIMAR, request.buffer_out);
|
||||||
m_last_length = length;
|
m_last_length = length;
|
||||||
DILENGTH = length;
|
mmio->Write<u32>(ADDRESS_DILENGTH, length);
|
||||||
system.GetDVDInterface().ForceOutOfBoundsRead(DVD::ReplyType::IOS);
|
system.GetDVDInterface().ForceOutOfBoundsRead(DVD::ReplyType::IOS);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -403,13 +387,13 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
return DIResult::SecurityError;
|
return DIResult::SecurityError;
|
||||||
case DIIoctl::DVDLowGetStatusRegister:
|
case DIIoctl::DVDLowGetStatusRegister:
|
||||||
{
|
{
|
||||||
const u32 disr = DISR;
|
const u32 disr = mmio->Read<u32>(ADDRESS_DISR);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowGetStatusRegister: {:#010x}", disr);
|
INFO_LOG_FMT(IOS_DI, "DVDLowGetStatusRegister: {:#010x}", disr);
|
||||||
return WriteIfFits(request, disr);
|
return WriteIfFits(request, disr);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowGetControlRegister:
|
case DIIoctl::DVDLowGetControlRegister:
|
||||||
{
|
{
|
||||||
const u32 dicr = DICR;
|
const u32 dicr = mmio->Read<u32>(ADDRESS_DICR);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowGetControlRegister: {:#010x}", dicr);
|
INFO_LOG_FMT(IOS_DI, "DVDLowGetControlRegister: {:#010x}", dicr);
|
||||||
return WriteIfFits(request, dicr);
|
return WriteIfFits(request, dicr);
|
||||||
}
|
}
|
||||||
|
@ -418,9 +402,9 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u8 param1 = memory.Read_U8(request.buffer_in + 7);
|
const u8 param1 = memory.Read_U8(request.buffer_in + 7);
|
||||||
const u32 param2 = memory.Read_U32(request.buffer_in + 8);
|
const u32 param2 = memory.Read_U32(request.buffer_in + 8);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReportKey: param1 {:#04x}, param2 {:#08x}", param1, param2);
|
INFO_LOG_FMT(IOS_DI, "DVDLowReportKey: param1 {:#04x}, param2 {:#08x}", param1, param2);
|
||||||
DICMDBUF0 = 0xA4000000 | (param1 << 16);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xA4000000 | (param1 << 16));
|
||||||
DICMDBUF1 = param2 & 0xFFFFFF;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, param2 & 0xFFFFFF);
|
||||||
DICMDBUF2 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
|
||||||
return StartDMATransfer(0x20, request);
|
return StartDMATransfer(0x20, request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowSeek:
|
case DIIoctl::DVDLowSeek:
|
||||||
|
@ -428,8 +412,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u32 position = memory.Read_U32(request.buffer_in + 4); // 32-bit offset
|
const u32 position = memory.Read_U32(request.buffer_in + 4); // 32-bit offset
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowSeek: position {:#010x}, translated to {:#010x}", position,
|
INFO_LOG_FMT(IOS_DI, "DVDLowSeek: position {:#010x}, translated to {:#010x}", position,
|
||||||
position); // TODO: do partition translation!
|
position); // TODO: do partition translation!
|
||||||
DICMDBUF0 = 0xAB000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAB000000);
|
||||||
DICMDBUF1 = position;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, position);
|
||||||
return StartImmediateTransfer(request, false);
|
return StartImmediateTransfer(request, false);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowReadDvd:
|
case DIIoctl::DVDLowReadDvd:
|
||||||
|
@ -440,9 +424,9 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u32 position = memory.Read_U32(request.buffer_in + 16);
|
const u32 position = memory.Read_U32(request.buffer_in + 16);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvd({}, {}): position {:#08x}, length {:#08x}", flag1, flag2,
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvd({}, {}): position {:#08x}, length {:#08x}", flag1, flag2,
|
||||||
position, length);
|
position, length);
|
||||||
DICMDBUF0 = 0xD0000000 | ((flag1 & 1) << 7) | ((flag2 & 1) << 6);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD0000000 | ((flag1 & 1) << 7) | ((flag2 & 1) << 6));
|
||||||
DICMDBUF1 = position & 0xFFFFFF;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, position & 0xFFFFFF);
|
||||||
DICMDBUF2 = length & 0xFFFFFF;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, length & 0xFFFFFF);
|
||||||
return StartDMATransfer(0x800 * length, request);
|
return StartDMATransfer(0x800 * length, request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowReadDvdConfig:
|
case DIIoctl::DVDLowReadDvdConfig:
|
||||||
|
@ -451,41 +435,41 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u8 param2 = memory.Read_U8(request.buffer_in + 11);
|
const u8 param2 = memory.Read_U8(request.buffer_in + 11);
|
||||||
const u32 position = memory.Read_U32(request.buffer_in + 12);
|
const u32 position = memory.Read_U32(request.buffer_in + 12);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdConfig({}, {}): position {:#08x}", flag1, param2, position);
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdConfig({}, {}): position {:#08x}", flag1, param2, position);
|
||||||
DICMDBUF0 = 0xD1000000 | ((flag1 & 1) << 16) | param2;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD1000000 | ((flag1 & 1) << 16) | param2);
|
||||||
DICMDBUF1 = position & 0xFFFFFF;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, position & 0xFFFFFF);
|
||||||
DICMDBUF2 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowStopLaser:
|
case DIIoctl::DVDLowStopLaser:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowStopLaser");
|
INFO_LOG_FMT(IOS_DI, "DVDLowStopLaser");
|
||||||
DICMDBUF0 = 0xD2000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD2000000);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
case DIIoctl::DVDLowOffset:
|
case DIIoctl::DVDLowOffset:
|
||||||
{
|
{
|
||||||
const u8 flag = memory.Read_U8(request.buffer_in + 7);
|
const u8 flag = memory.Read_U8(request.buffer_in + 7);
|
||||||
const u32 offset = memory.Read_U32(request.buffer_in + 8);
|
const u32 offset = memory.Read_U32(request.buffer_in + 8);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowOffset({}): offset {:#010x}", flag, offset);
|
INFO_LOG_FMT(IOS_DI, "DVDLowOffset({}): offset {:#010x}", flag, offset);
|
||||||
DICMDBUF0 = 0xD9000000 | ((flag & 1) << 16);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD9000000 | ((flag & 1) << 16));
|
||||||
DICMDBUF1 = offset;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, offset);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowReadDiskBca:
|
case DIIoctl::DVDLowReadDiskBca:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskBca");
|
INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskBca");
|
||||||
DICMDBUF0 = 0xDA000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDA000000);
|
||||||
return StartDMATransfer(0x40, request);
|
return StartDMATransfer(0x40, request);
|
||||||
case DIIoctl::DVDLowRequestDiscStatus:
|
case DIIoctl::DVDLowRequestDiscStatus:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowRequestDiscStatus");
|
INFO_LOG_FMT(IOS_DI, "DVDLowRequestDiscStatus");
|
||||||
DICMDBUF0 = 0xDB000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDB000000);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
case DIIoctl::DVDLowRequestRetryNumber:
|
case DIIoctl::DVDLowRequestRetryNumber:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowRequestRetryNumber");
|
INFO_LOG_FMT(IOS_DI, "DVDLowRequestRetryNumber");
|
||||||
DICMDBUF0 = 0xDC000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDC000000);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
case DIIoctl::DVDLowSetMaximumRotation:
|
case DIIoctl::DVDLowSetMaximumRotation:
|
||||||
{
|
{
|
||||||
const u8 speed = memory.Read_U8(request.buffer_in + 7);
|
const u8 speed = memory.Read_U8(request.buffer_in + 7);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowSetMaximumRotation: speed {}", speed);
|
INFO_LOG_FMT(IOS_DI, "DVDLowSetMaximumRotation: speed {}", speed);
|
||||||
DICMDBUF0 = 0xDD000000 | ((speed & 3) << 16);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDD000000 | ((speed & 3) << 16));
|
||||||
return StartImmediateTransfer(request, false);
|
return StartImmediateTransfer(request, false);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowSerMeasControl:
|
case DIIoctl::DVDLowSerMeasControl:
|
||||||
|
@ -493,12 +477,12 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u8 flag1 = memory.Read_U8(request.buffer_in + 7);
|
const u8 flag1 = memory.Read_U8(request.buffer_in + 7);
|
||||||
const u8 flag2 = memory.Read_U8(request.buffer_in + 11);
|
const u8 flag2 = memory.Read_U8(request.buffer_in + 11);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowSerMeasControl({}, {})", flag1, flag2);
|
INFO_LOG_FMT(IOS_DI, "DVDLowSerMeasControl({}, {})", flag1, flag2);
|
||||||
DICMDBUF0 = 0xDF000000 | ((flag1 & 1) << 17) | ((flag2 & 1) << 16);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDF000000 | ((flag1 & 1) << 17) | ((flag2 & 1) << 16));
|
||||||
return StartDMATransfer(0x20, request);
|
return StartDMATransfer(0x20, request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowRequestError:
|
case DIIoctl::DVDLowRequestError:
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowRequestError");
|
INFO_LOG_FMT(IOS_DI, "DVDLowRequestError");
|
||||||
DICMDBUF0 = 0xE0000000;
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE0000000);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
case DIIoctl::DVDLowAudioStream:
|
case DIIoctl::DVDLowAudioStream:
|
||||||
{
|
{
|
||||||
|
@ -507,17 +491,17 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u32 position = memory.Read_U32(request.buffer_in + 12);
|
const u32 position = memory.Read_U32(request.buffer_in + 12);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowAudioStream({}): offset {:#010x} (byte {:#011x}), length {:#x}",
|
INFO_LOG_FMT(IOS_DI, "DVDLowAudioStream({}): offset {:#010x} (byte {:#011x}), length {:#x}",
|
||||||
mode, position, static_cast<u64>(position) << 2, length);
|
mode, position, static_cast<u64>(position) << 2, length);
|
||||||
DICMDBUF0 = 0xE1000000 | ((mode & 3) << 16);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE1000000 | ((mode & 3) << 16));
|
||||||
DICMDBUF1 = position;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, position);
|
||||||
DICMDBUF2 = length;
|
mmio->Write<u32>(ADDRESS_DICMDBUF2, length);
|
||||||
return StartImmediateTransfer(request, false);
|
return StartImmediateTransfer(request, false);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowRequestAudioStatus:
|
case DIIoctl::DVDLowRequestAudioStatus:
|
||||||
{
|
{
|
||||||
const u8 mode = memory.Read_U8(request.buffer_in + 7);
|
const u8 mode = memory.Read_U8(request.buffer_in + 7);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowRequestAudioStatus({})", mode);
|
INFO_LOG_FMT(IOS_DI, "DVDLowRequestAudioStatus({})", mode);
|
||||||
DICMDBUF0 = 0xE2000000 | ((mode & 3) << 16);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE2000000 | ((mode & 3) << 16));
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
// Note that this command does not copy the value written to DIIMMBUF, which makes it rather
|
// Note that this command does not copy the value written to DIIMMBUF, which makes it rather
|
||||||
// useless (to actually use it, DVDLowGetImmBuf would need to be used afterwards)
|
// useless (to actually use it, DVDLowGetImmBuf would need to be used afterwards)
|
||||||
return StartImmediateTransfer(request, false);
|
return StartImmediateTransfer(request, false);
|
||||||
|
@ -527,8 +511,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u8 eject = memory.Read_U8(request.buffer_in + 7);
|
const u8 eject = memory.Read_U8(request.buffer_in + 7);
|
||||||
const u8 kill = memory.Read_U8(request.buffer_in + 11);
|
const u8 kill = memory.Read_U8(request.buffer_in + 11);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowStopMotor({}, {})", eject, kill);
|
INFO_LOG_FMT(IOS_DI, "DVDLowStopMotor({}, {})", eject, kill);
|
||||||
DICMDBUF0 = 0xE3000000 | ((eject & 1) << 17) | ((kill & 1) << 20);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE3000000 | ((eject & 1) << 17) | ((kill & 1) << 20));
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
}
|
}
|
||||||
case DIIoctl::DVDLowAudioBufferConfig:
|
case DIIoctl::DVDLowAudioBufferConfig:
|
||||||
|
@ -537,8 +521,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
|
||||||
const u8 buffer_size = memory.Read_U8(request.buffer_in + 11);
|
const u8 buffer_size = memory.Read_U8(request.buffer_in + 11);
|
||||||
INFO_LOG_FMT(IOS_DI, "DVDLowAudioBufferConfig: {}, buffer size {}",
|
INFO_LOG_FMT(IOS_DI, "DVDLowAudioBufferConfig: {}, buffer size {}",
|
||||||
enable ? "enabled" : "disabled", buffer_size);
|
enable ? "enabled" : "disabled", buffer_size);
|
||||||
DICMDBUF0 = 0xE4000000 | ((enable & 1) << 16) | (buffer_size & 0xf);
|
mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE4000000 | ((enable & 1) << 16) | (buffer_size & 0xf));
|
||||||
DICMDBUF1 = 0;
|
mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
|
||||||
// On the other hand, this command *does* copy DIIMMBUF, but the actual code in the drive never
|
// On the other hand, this command *does* copy DIIMMBUF, but the actual code in the drive never
|
||||||
// writes anything to it, so it just copies over a stale value (e.g. from DVDLowRequestError).
|
// writes anything to it, so it just copies over a stale value (e.g. from DVDLowRequestError).
|
||||||
return StartImmediateTransfer(request);
|
return StartImmediateTransfer(request);
|
||||||
|
@ -577,11 +561,13 @@ std::optional<DIDevice::DIResult> DIDevice::StartDMATransfer(u32 command_length,
|
||||||
return DIResult::BadArgument;
|
return DIResult::BadArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIMAR = request.buffer_out;
|
auto& system = Core::System::GetInstance();
|
||||||
|
auto* mmio = system.GetMemory().GetMMIOMapping();
|
||||||
|
mmio->Write<u32>(ADDRESS_DIMAR, request.buffer_out);
|
||||||
m_last_length = command_length;
|
m_last_length = command_length;
|
||||||
DILENGTH = command_length;
|
mmio->Write<u32>(ADDRESS_DILENGTH, command_length);
|
||||||
|
|
||||||
Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
|
system.GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
|
||||||
// Reply will be posted when done by FinishIOCtl.
|
// Reply will be posted when done by FinishIOCtl.
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -665,10 +651,11 @@ void DIDevice::FinishDICommand(DIResult result)
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& memory = system.GetMemory();
|
auto& memory = system.GetMemory();
|
||||||
|
auto* mmio = memory.GetMMIOMapping();
|
||||||
|
|
||||||
IOCtlRequest request{m_executing_command->m_request_address};
|
IOCtlRequest request{m_executing_command->m_request_address};
|
||||||
if (m_executing_command->m_copy_diimmbuf)
|
if (m_executing_command->m_copy_diimmbuf)
|
||||||
memory.Write_U32(DIIMMBUF, request.buffer_out);
|
memory.Write_U32(mmio->Read<u32>(ADDRESS_DIIMMBUF), request.buffer_out);
|
||||||
|
|
||||||
m_ios.EnqueueIPCReply(request, static_cast<s32>(result));
|
m_ios.EnqueueIPCReply(request, static_cast<s32>(result));
|
||||||
|
|
||||||
|
|
|
@ -134,10 +134,13 @@ struct FileStatus
|
||||||
constexpr size_t MaxPathDepth = 8;
|
constexpr size_t MaxPathDepth = 8;
|
||||||
/// The maximum number of characters a path can have.
|
/// The maximum number of characters a path can have.
|
||||||
constexpr size_t MaxPathLength = 64;
|
constexpr size_t MaxPathLength = 64;
|
||||||
|
/// The maximum number of characters a filename can have.
|
||||||
|
constexpr size_t MaxFilenameLength = 12;
|
||||||
|
|
||||||
/// Returns whether a Wii path is valid.
|
/// Returns whether a Wii path is valid.
|
||||||
bool IsValidPath(std::string_view path);
|
bool IsValidPath(std::string_view path);
|
||||||
bool IsValidNonRootPath(std::string_view path);
|
bool IsValidNonRootPath(std::string_view path);
|
||||||
|
bool IsValidFilename(std::string_view filename);
|
||||||
|
|
||||||
struct SplitPathResult
|
struct SplitPathResult
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "Core/IOS/FS/FileSystem.h"
|
#include "Core/IOS/FS/FileSystem.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Core/IOS/Device.h"
|
#include "Core/IOS/Device.h"
|
||||||
|
@ -21,6 +23,12 @@ bool IsValidNonRootPath(std::string_view path)
|
||||||
path.back() != '/';
|
path.back() != '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsValidFilename(std::string_view filename)
|
||||||
|
{
|
||||||
|
return filename.length() <= MaxFilenameLength &&
|
||||||
|
!std::any_of(filename.begin(), filename.end(), [](char c) { return c == '/'; });
|
||||||
|
}
|
||||||
|
|
||||||
SplitPathResult SplitPathAndBasename(std::string_view path)
|
SplitPathResult SplitPathAndBasename(std::string_view path)
|
||||||
{
|
{
|
||||||
const auto last_separator = path.rfind('/');
|
const auto last_separator = path.rfind('/');
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Core/IOS/FS/HostBackend/FS.h"
|
#include "Core/IOS/FS/HostBackend/FS.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "Common/Align.h"
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
|
@ -27,6 +29,21 @@ namespace IOS::HLE::FS
|
||||||
{
|
{
|
||||||
constexpr u32 BUFFER_CHUNK_SIZE = 65536;
|
constexpr u32 BUFFER_CHUNK_SIZE = 65536;
|
||||||
|
|
||||||
|
// size of a single cluster in the NAND
|
||||||
|
constexpr u16 CLUSTER_SIZE = 16384;
|
||||||
|
|
||||||
|
// total number of clusters available in the NAND
|
||||||
|
constexpr u16 TOTAL_CLUSTERS = 0x7ec0;
|
||||||
|
|
||||||
|
// number of clusters reserved for bad blocks and similar, not accessible to normal writes
|
||||||
|
constexpr u16 RESERVED_CLUSTERS = 0x0300;
|
||||||
|
|
||||||
|
// number of clusters actually usable by the file system
|
||||||
|
constexpr u16 USABLE_CLUSTERS = TOTAL_CLUSTERS - RESERVED_CLUSTERS;
|
||||||
|
|
||||||
|
// total number of inodes available in the NAND
|
||||||
|
constexpr u16 TOTAL_INODES = 0x17ff;
|
||||||
|
|
||||||
HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const
|
HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const
|
||||||
{
|
{
|
||||||
for (const auto& redirect : m_nand_redirects)
|
for (const auto& redirect : m_nand_redirects)
|
||||||
|
@ -47,21 +64,6 @@ HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wi
|
||||||
return HostFilename{m_root_path, false};
|
return HostFilename{m_root_path, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total filesize of contents of a directory (recursive)
|
|
||||||
// Only used for ES_GetUsage atm, could be useful elsewhere?
|
|
||||||
static u64 ComputeTotalFileSize(const File::FSTEntry& parent_entry)
|
|
||||||
{
|
|
||||||
u64 sizeOfFiles = 0;
|
|
||||||
for (const File::FSTEntry& entry : parent_entry.children)
|
|
||||||
{
|
|
||||||
if (entry.isDirectory)
|
|
||||||
sizeOfFiles += ComputeTotalFileSize(entry);
|
|
||||||
else
|
|
||||||
sizeOfFiles += entry.size;
|
|
||||||
}
|
|
||||||
return sizeOfFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
struct SerializedFstEntry
|
struct SerializedFstEntry
|
||||||
|
@ -102,6 +104,45 @@ auto GetNamePredicate(const std::string& name)
|
||||||
{
|
{
|
||||||
return [&name](const auto& entry) { return entry.name == name; };
|
return [&name](const auto& entry) { return entry.name == name; };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the host directory entries into ones that can be exposed to the emulated system.
|
||||||
|
static u64 FixupDirectoryEntries(File::FSTEntry* dir, bool is_root)
|
||||||
|
{
|
||||||
|
u64 removed_entries = 0;
|
||||||
|
for (auto it = dir->children.begin(); it != dir->children.end();)
|
||||||
|
{
|
||||||
|
// Drop files in the root of the Wii NAND folder, since we store extra files there that the
|
||||||
|
// emulated system shouldn't know about.
|
||||||
|
if (is_root && !it->isDirectory)
|
||||||
|
{
|
||||||
|
++removed_entries;
|
||||||
|
it = dir->children.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode escaped invalid file system characters so that games (such as Harry Potter and the
|
||||||
|
// Half-Blood Prince) can find what they expect.
|
||||||
|
if (it->virtualName.find("__") != std::string::npos)
|
||||||
|
it->virtualName = Common::UnescapeFileName(it->virtualName);
|
||||||
|
|
||||||
|
// Drop files that have too long filenames.
|
||||||
|
if (!IsValidFilename(it->virtualName))
|
||||||
|
{
|
||||||
|
if (it->isDirectory)
|
||||||
|
removed_entries += it->size;
|
||||||
|
++removed_entries;
|
||||||
|
it = dir->children.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir->isDirectory)
|
||||||
|
removed_entries += FixupDirectoryEntries(&*it, false);
|
||||||
|
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
dir->size -= removed_entries;
|
||||||
|
return removed_entries;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool HostFileSystem::FstEntry::CheckPermission(Uid caller_uid, Gid caller_gid,
|
bool HostFileSystem::FstEntry::CheckPermission(Uid caller_uid, Gid caller_gid,
|
||||||
|
@ -645,12 +686,7 @@ Result<std::vector<std::string>> HostFileSystem::ReadDirectory(Uid uid, Gid gid,
|
||||||
|
|
||||||
const std::string host_path = BuildFilename(path).host_path;
|
const std::string host_path = BuildFilename(path).host_path;
|
||||||
File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false);
|
File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false);
|
||||||
for (File::FSTEntry& child : host_entry.children)
|
FixupDirectoryEntries(&host_entry, path == "/");
|
||||||
{
|
|
||||||
// Decode escaped invalid file system characters so that games (such as
|
|
||||||
// Harry Potter and the Half-Blood Prince) can find what they expect.
|
|
||||||
child.virtualName = Common::UnescapeFileName(child.virtualName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort files according to their order in the FST tree (issue 10234).
|
// Sort files according to their order in the FST tree (issue 10234).
|
||||||
// The result should look like this:
|
// The result should look like this:
|
||||||
|
@ -747,19 +783,33 @@ ResultCode HostFileSystem::SetMetadata(Uid caller_uid, const std::string& path,
|
||||||
return ResultCode::Success;
|
return ResultCode::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 ComputeUsedClusters(const File::FSTEntry& parent_entry)
|
||||||
|
{
|
||||||
|
u64 clusters = 0;
|
||||||
|
for (const File::FSTEntry& entry : parent_entry.children)
|
||||||
|
{
|
||||||
|
if (entry.isDirectory)
|
||||||
|
clusters += ComputeUsedClusters(entry);
|
||||||
|
else
|
||||||
|
clusters += Common::AlignUp(entry.size, CLUSTER_SIZE) / CLUSTER_SIZE;
|
||||||
|
}
|
||||||
|
return clusters;
|
||||||
|
}
|
||||||
|
|
||||||
Result<NandStats> HostFileSystem::GetNandStats()
|
Result<NandStats> HostFileSystem::GetNandStats()
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS_FS, "GET STATS - returning static values for now");
|
const auto root_stats = GetDirectoryStats("/");
|
||||||
|
if (!root_stats)
|
||||||
|
return root_stats.Error(); // TODO: is this right? can this fail on hardware?
|
||||||
|
|
||||||
// TODO: scrape the real amounts from somewhere...
|
|
||||||
NandStats stats{};
|
NandStats stats{};
|
||||||
stats.cluster_size = 0x4000;
|
stats.cluster_size = CLUSTER_SIZE;
|
||||||
stats.free_clusters = 0x5DEC;
|
stats.free_clusters = USABLE_CLUSTERS - root_stats->used_clusters;
|
||||||
stats.used_clusters = 0x1DD4;
|
stats.used_clusters = root_stats->used_clusters;
|
||||||
stats.bad_clusters = 0x10;
|
stats.bad_clusters = 0;
|
||||||
stats.reserved_clusters = 0x02F0;
|
stats.reserved_clusters = RESERVED_CLUSTERS;
|
||||||
stats.free_inodes = 0x146B;
|
stats.free_inodes = TOTAL_INODES - root_stats->used_inodes;
|
||||||
stats.used_inodes = 0x0394;
|
stats.used_inodes = root_stats->used_inodes;
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
@ -771,19 +821,25 @@ Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_
|
||||||
|
|
||||||
DirectoryStats stats{};
|
DirectoryStats stats{};
|
||||||
std::string path(BuildFilename(wii_path).host_path);
|
std::string path(BuildFilename(wii_path).host_path);
|
||||||
if (File::IsDirectory(path))
|
File::FileInfo info(path);
|
||||||
|
if (!info.Exists())
|
||||||
|
{
|
||||||
|
return ResultCode::NotFound;
|
||||||
|
}
|
||||||
|
if (info.IsDirectory())
|
||||||
{
|
{
|
||||||
File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true);
|
File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true);
|
||||||
|
FixupDirectoryEntries(&parent_dir, wii_path == "/");
|
||||||
|
|
||||||
// add one for the folder itself
|
// add one for the folder itself
|
||||||
stats.used_inodes = 1 + (u32)parent_dir.size;
|
stats.used_inodes = static_cast<u32>(std::min<u64>(1 + parent_dir.size, TOTAL_INODES));
|
||||||
|
|
||||||
u64 total_size = ComputeTotalFileSize(parent_dir); // "Real" size to convert to nand blocks
|
const u64 clusters = ComputeUsedClusters(parent_dir);
|
||||||
|
stats.used_clusters = static_cast<u32>(std::min<u64>(clusters, USABLE_CLUSTERS));
|
||||||
stats.used_clusters = (u32)(total_size / (16 * 1024)); // one block is 16kb
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WARN_LOG_FMT(IOS_FS, "fsBlock failed, cannot find directory: {}", path);
|
return ResultCode::Invalid;
|
||||||
}
|
}
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,8 +200,9 @@ static void ResetAndPausePPC()
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& memory = system.GetMemory();
|
auto& memory = system.GetMemory();
|
||||||
memory.Write_U32(0x48000000, 0x00000000); // b 0x0
|
memory.Write_U32(0x48000000, 0x00000000); // b 0x0
|
||||||
PowerPC::Reset();
|
auto& power_pc = system.GetPowerPC();
|
||||||
system.GetPPCState().pc = 0;
|
power_pc.Reset();
|
||||||
|
power_pc.GetPPCState().pc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReleasePPC()
|
static void ReleasePPC()
|
||||||
|
|
|
@ -43,7 +43,7 @@ static void ReinitHardware()
|
||||||
// (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually
|
// (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually
|
||||||
// reset DI fully, in such a way that the DTK config isn't cleared?
|
// reset DI fully, in such a way that the DTK config isn't cleared?
|
||||||
// system.GetDVDInterface().ResetDrive(true);
|
// system.GetDVDInterface().ResetDrive(true);
|
||||||
PowerPC::Reset();
|
system.GetPowerPC().Reset();
|
||||||
Wiimote::ResetAllWiimotes();
|
Wiimote::ResetAllWiimotes();
|
||||||
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
|
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
|
||||||
auto& dsp = system.GetDSP();
|
auto& dsp = system.GetDSP();
|
||||||
|
@ -83,18 +83,18 @@ bool Load()
|
||||||
Host_NotifyMapLoaded();
|
Host_NotifyMapLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& ppc_state = system.GetPPCState();
|
auto& power_pc = system.GetPowerPC();
|
||||||
const PowerPC::CoreMode core_mode = PowerPC::GetMode();
|
const PowerPC::CoreMode core_mode = power_pc.GetMode();
|
||||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
power_pc.SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
ppc_state.msr.Hex = 0;
|
power_pc.GetPPCState().msr.Hex = 0;
|
||||||
ppc_state.pc = 0x3400;
|
power_pc.GetPPCState().pc = 0x3400;
|
||||||
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");
|
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");
|
||||||
|
|
||||||
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
|
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
|
||||||
// 0xdeadbeef there, then waits for it to be cleared by IOS before continuing.
|
// 0xdeadbeef there, then waits for it to be cleared by IOS before continuing.
|
||||||
while (memory.Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef)
|
while (memory.Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef)
|
||||||
PowerPC::SingleStep();
|
power_pc.SingleStep();
|
||||||
PowerPC::SetMode(core_mode);
|
power_pc.SetMode(core_mode);
|
||||||
|
|
||||||
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
||||||
NOTICE_LOG_FMT(IOS, "IPL ready.");
|
NOTICE_LOG_FMT(IOS, "IPL ready.");
|
||||||
|
|
|
@ -233,6 +233,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
|
||||||
|
|
||||||
IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request)
|
IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
|
m_dl_list.ReadDlList();
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& memory = system.GetMemory();
|
auto& memory = system.GetMemory();
|
||||||
const u32 flags = memory.Read_U32(request.buffer_in);
|
const u32 flags = memory.Read_U32(request.buffer_in);
|
||||||
|
|
|
@ -63,7 +63,10 @@ int SSLSendWithoutSNI(void* ctx, const unsigned char* buf, size_t len)
|
||||||
|
|
||||||
// Log raw SSL packets if we don't dump unencrypted SSL writes
|
// Log raw SSL packets if we don't dump unencrypted SSL writes
|
||||||
if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_WRITE) && ret > 0)
|
if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_WRITE) && ret > 0)
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogWrite(buf, ret, *fd, nullptr);
|
{
|
||||||
|
Core::System::GetInstance().GetPowerPC().GetDebugInterface().NetworkLogger()->LogWrite(
|
||||||
|
buf, ret, *fd, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +79,10 @@ int SSLRecv(void* ctx, unsigned char* buf, size_t len)
|
||||||
|
|
||||||
// Log raw SSL packets if we don't dump unencrypted SSL reads
|
// Log raw SSL packets if we don't dump unencrypted SSL reads
|
||||||
if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_READ) && ret > 0)
|
if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_READ) && ret > 0)
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogRead(buf, ret, *fd, nullptr);
|
{
|
||||||
|
Core::System::GetInstance().GetPowerPC().GetDebugInterface().NetworkLogger()->LogRead(
|
||||||
|
buf, ret, *fd, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,8 +487,8 @@ void WiiSocket::Update(bool read, bool write, bool except)
|
||||||
|
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
{
|
{
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogSSLWrite(memory.GetPointer(BufferOut2),
|
system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogSSLWrite(
|
||||||
ret, ssl->hostfd);
|
memory.GetPointer(BufferOut2), ret, ssl->hostfd);
|
||||||
// Return bytes written or SSL_ERR_ZERO if none
|
// Return bytes written or SSL_ERR_ZERO if none
|
||||||
WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
|
WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
|
||||||
}
|
}
|
||||||
|
@ -521,8 +521,8 @@ void WiiSocket::Update(bool read, bool write, bool except)
|
||||||
|
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
{
|
{
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogSSLRead(memory.GetPointer(BufferIn2),
|
system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogSSLRead(
|
||||||
ret, ssl->hostfd);
|
memory.GetPointer(BufferIn2), ret, ssl->hostfd);
|
||||||
// Return bytes read or SSL_ERR_ZERO if none
|
// Return bytes read or SSL_ERR_ZERO if none
|
||||||
WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
|
WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
|
||||||
}
|
}
|
||||||
|
@ -595,7 +595,7 @@ void WiiSocket::Update(bool read, bool write, bool except)
|
||||||
const int ret = sendto(fd, data, BufferInSize, flags, to, tolen);
|
const int ret = sendto(fd, data, BufferInSize, flags, to, tolen);
|
||||||
ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true);
|
ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogWrite(data, ret, fd, to);
|
system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogWrite(data, ret, fd, to);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET,
|
INFO_LOG_FMT(IOS_NET,
|
||||||
"{} = {} Socket: {:08x}, BufferIn: ({:08x}, {}), BufferIn2: ({:08x}, {}), "
|
"{} = {} Socket: {:08x}, BufferIn: ({:08x}, {}), BufferIn2: ({:08x}, {}), "
|
||||||
|
@ -654,7 +654,7 @@ void WiiSocket::Update(bool read, bool write, bool except)
|
||||||
ReturnValue =
|
ReturnValue =
|
||||||
WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true);
|
WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
PowerPC::debug_interface.NetworkLogger()->LogRead(data, ret, fd, from);
|
system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogRead(data, ret, fd, from);
|
||||||
|
|
||||||
INFO_LOG_FMT(IOS_NET,
|
INFO_LOG_FMT(IOS_NET,
|
||||||
"{}({}, {}) Socket: {:08X}, Flags: {:08X}, "
|
"{}({}, {}) Socket: {:08X}, Flags: {:08X}, "
|
||||||
|
@ -865,7 +865,7 @@ s32 WiiSockMan::AddSocket(s32 fd, bool is_rw)
|
||||||
WiiSocket& sock = WiiSockets[wii_fd];
|
WiiSocket& sock = WiiSockets[wii_fd];
|
||||||
sock.SetFd(fd);
|
sock.SetFd(fd);
|
||||||
sock.SetWiiFd(wii_fd);
|
sock.SetWiiFd(wii_fd);
|
||||||
PowerPC::debug_interface.NetworkLogger()->OnNewSocket(fd);
|
Core::System::GetInstance().GetPowerPC().GetDebugInterface().NetworkLogger()->OnNewSocket(fd);
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
int opt_no_sigpipe = 1;
|
int opt_no_sigpipe = 1;
|
||||||
|
|
|
@ -103,7 +103,7 @@ std::optional<IPCReply> USB_HIDv4::GetDeviceChange(const IOCtlRequest& request)
|
||||||
IPCReply USB_HIDv4::Shutdown(const IOCtlRequest& request)
|
IPCReply USB_HIDv4::Shutdown(const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
std::lock_guard lk{m_devicechange_hook_address_mutex};
|
||||||
if (m_devicechange_hook_request != 0)
|
if (m_devicechange_hook_request != nullptr)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
auto& memory = system.GetMemory();
|
auto& memory = system.GetMemory();
|
||||||
|
|
|
@ -191,7 +191,7 @@ USB_KBD::USB_KBD(Kernel& ios, const std::string& device_name) : Device(ios, devi
|
||||||
std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request)
|
std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(IOS, "USB_KBD: Open");
|
INFO_LOG_FMT(IOS, "USB_KBD: Open");
|
||||||
IniFile ini;
|
Common::IniFile ini;
|
||||||
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||||
ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_keyboard_layout, KBD_LAYOUT_QWERTY);
|
ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_keyboard_layout, KBD_LAYOUT_QWERTY);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Crypto/SHA1.h"
|
#include "Common/Crypto/SHA1.h"
|
||||||
#include "Common/ENetUtil.h"
|
#include "Common/ENet.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
|
@ -168,7 +168,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
|
||||||
{
|
{
|
||||||
if (Connect())
|
if (Connect())
|
||||||
{
|
{
|
||||||
m_client->intercept = ENetUtil::InterceptCallback;
|
m_client->intercept = Common::ENet::InterceptCallback;
|
||||||
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,8 @@ bool NetPlayClient::Connect()
|
||||||
// TODO: make this not hang
|
// TODO: make this not hang
|
||||||
ENetEvent netEvent;
|
ENetEvent netEvent;
|
||||||
int net;
|
int net;
|
||||||
while ((net = enet_host_service(m_client, &netEvent, 5000)) > 0 && netEvent.type == 42)
|
while ((net = enet_host_service(m_client, &netEvent, 5000)) > 0 &&
|
||||||
|
netEvent.type == ENetEventType(42)) // See PR #11381 and ENetUtil::InterceptCallback
|
||||||
{
|
{
|
||||||
// ignore packets from traversal server
|
// ignore packets from traversal server
|
||||||
}
|
}
|
||||||
|
@ -1522,7 +1523,7 @@ void NetPlayClient::OnGameDigestAbort()
|
||||||
|
|
||||||
void NetPlayClient::Send(const sf::Packet& packet, const u8 channel_id)
|
void NetPlayClient::Send(const sf::Packet& packet, const u8 channel_id)
|
||||||
{
|
{
|
||||||
ENetUtil::SendPacket(m_server, packet, channel_id);
|
Common::ENet::SendPacket(m_server, packet, channel_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetPlayClient::DisplayPlayersPing()
|
void NetPlayClient::DisplayPlayersPing()
|
||||||
|
@ -1577,7 +1578,7 @@ void NetPlayClient::SendAsync(sf::Packet&& packet, const u8 channel_id)
|
||||||
std::lock_guard lkq(m_crit.async_queue_write);
|
std::lock_guard lkq(m_crit.async_queue_write);
|
||||||
m_async_queue.Push(AsyncQueueEntry{std::move(packet), channel_id});
|
m_async_queue.Push(AsyncQueueEntry{std::move(packet), channel_id});
|
||||||
}
|
}
|
||||||
ENetUtil::WakeupThread(m_client);
|
Common::ENet::WakeupThread(m_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from ---NETPLAY--- thread
|
// called from ---NETPLAY--- thread
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "Common/CommonPaths.h"
|
#include "Common/CommonPaths.h"
|
||||||
#include "Common/ENetUtil.h"
|
#include "Common/ENet.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/HttpRequest.h"
|
#include "Common/HttpRequest.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
@ -111,7 +111,7 @@ NetPlayServer::~NetPlayServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
UPnP::StopPortmapping();
|
Common::UPnP::StopPortmapping();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI*
|
||||||
if (m_server != nullptr)
|
if (m_server != nullptr)
|
||||||
{
|
{
|
||||||
m_server->mtu = std::min(m_server->mtu, NetPlay::MAX_ENET_MTU);
|
m_server->mtu = std::min(m_server->mtu, NetPlay::MAX_ENET_MTU);
|
||||||
m_server->intercept = ENetUtil::InterceptCallback;
|
m_server->intercept = Common::ENet::InterceptCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupIndex();
|
SetupIndex();
|
||||||
|
@ -168,7 +168,7 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI*
|
||||||
|
|
||||||
#ifdef USE_UPNP
|
#ifdef USE_UPNP
|
||||||
if (forward_port)
|
if (forward_port)
|
||||||
UPnP::TryPortmapping(port);
|
Common::UPnP::TryPortmapping(port);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -701,7 +701,7 @@ void NetPlayServer::SendAsync(sf::Packet&& packet, const PlayerId pid, const u8
|
||||||
std::lock_guard lkq(m_crit.async_queue_write);
|
std::lock_guard lkq(m_crit.async_queue_write);
|
||||||
m_async_queue.Push(AsyncQueueEntry{std::move(packet), pid, TargetMode::Only, channel_id});
|
m_async_queue.Push(AsyncQueueEntry{std::move(packet), pid, TargetMode::Only, channel_id});
|
||||||
}
|
}
|
||||||
ENetUtil::WakeupThread(m_server);
|
Common::ENet::WakeupThread(m_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_pid,
|
void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_pid,
|
||||||
|
@ -712,7 +712,7 @@ void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_
|
||||||
m_async_queue.Push(
|
m_async_queue.Push(
|
||||||
AsyncQueueEntry{std::move(packet), skip_pid, TargetMode::AllExcept, channel_id});
|
AsyncQueueEntry{std::move(packet), skip_pid, TargetMode::AllExcept, channel_id});
|
||||||
}
|
}
|
||||||
ENetUtil::WakeupThread(m_server);
|
Common::ENet::WakeupThread(m_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetPlayServer::SendChunked(sf::Packet&& packet, const PlayerId pid, const std::string& title)
|
void NetPlayServer::SendChunked(sf::Packet&& packet, const PlayerId pid, const std::string& title)
|
||||||
|
@ -2027,10 +2027,10 @@ bool NetPlayServer::SyncCodes()
|
||||||
// Find all INI files
|
// Find all INI files
|
||||||
const auto game_id = game->GetGameID();
|
const auto game_id = game->GetGameID();
|
||||||
const auto revision = game->GetRevision();
|
const auto revision = game->GetRevision();
|
||||||
IniFile globalIni;
|
Common::IniFile globalIni;
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
||||||
globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
||||||
IniFile localIni;
|
Common::IniFile localIni;
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
||||||
localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
||||||
|
|
||||||
|
@ -2183,7 +2183,7 @@ void NetPlayServer::SendToClients(const sf::Packet& packet, const PlayerId skip_
|
||||||
|
|
||||||
void NetPlayServer::Send(ENetPeer* socket, const sf::Packet& packet, const u8 channel_id)
|
void NetPlayServer::Send(ENetPeer* socket, const sf::Packet& packet, const u8 channel_id)
|
||||||
{
|
{
|
||||||
ENetUtil::SendPacket(socket, packet, channel_id);
|
Common::ENet::SendPacket(socket, packet, channel_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetPlayServer::KickPlayer(PlayerId player)
|
void NetPlayServer::KickPlayer(PlayerId player)
|
||||||
|
@ -2266,8 +2266,7 @@ u16 NetPlayServer::GetPort() const
|
||||||
std::unordered_set<std::string> NetPlayServer::GetInterfaceSet() const
|
std::unordered_set<std::string> NetPlayServer::GetInterfaceSet() const
|
||||||
{
|
{
|
||||||
std::unordered_set<std::string> result;
|
std::unordered_set<std::string> result;
|
||||||
auto lst = GetInterfaceListInternal();
|
for (const auto& list_entry : GetInterfaceListInternal())
|
||||||
for (auto list_entry : lst)
|
|
||||||
result.emplace(list_entry.first);
|
result.emplace(list_entry.first);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,11 +102,9 @@ std::string SerializeLine(const PatchEntry& entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
|
void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
|
||||||
const IniFile& globalIni, const IniFile& localIni)
|
const Common::IniFile& globalIni, const Common::IniFile& localIni)
|
||||||
{
|
{
|
||||||
const IniFile* inis[2] = {&globalIni, &localIni};
|
for (const auto* ini : {&globalIni, &localIni})
|
||||||
|
|
||||||
for (const IniFile* ini : inis)
|
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
Patch currentPatch;
|
Patch currentPatch;
|
||||||
|
@ -152,7 +150,7 @@ void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavePatchSection(IniFile* local_ini, const std::vector<Patch>& patches)
|
void SavePatchSection(Common::IniFile* local_ini, const std::vector<Patch>& patches)
|
||||||
{
|
{
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::vector<std::string> lines_enabled;
|
std::vector<std::string> lines_enabled;
|
||||||
|
@ -177,7 +175,7 @@ void SavePatchSection(IniFile* local_ini, const std::vector<Patch>& patches)
|
||||||
local_ini->SetLines("OnFrame", lines);
|
local_ini->SetLines("OnFrame", lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadSpeedhacks(const std::string& section, IniFile& ini)
|
static void LoadSpeedhacks(const std::string& section, Common::IniFile& ini)
|
||||||
{
|
{
|
||||||
std::vector<std::string> keys;
|
std::vector<std::string> keys;
|
||||||
ini.GetKeys(section, &keys);
|
ini.GetKeys(section, &keys);
|
||||||
|
@ -211,9 +209,10 @@ int GetSpeedhackCycles(const u32 addr)
|
||||||
|
|
||||||
void LoadPatches()
|
void LoadPatches()
|
||||||
{
|
{
|
||||||
IniFile merged = SConfig::GetInstance().LoadGameIni();
|
const auto& sconfig = SConfig::GetInstance();
|
||||||
IniFile globalIni = SConfig::GetInstance().LoadDefaultGameIni();
|
Common::IniFile merged = sconfig.LoadGameIni();
|
||||||
IniFile localIni = SConfig::GetInstance().LoadLocalGameIni();
|
Common::IniFile globalIni = sconfig.LoadDefaultGameIni();
|
||||||
|
Common::IniFile localIni = sconfig.LoadLocalGameIni();
|
||||||
|
|
||||||
LoadPatchSection("OnFrame", &s_on_frame, globalIni, localIni);
|
LoadPatchSection("OnFrame", &s_on_frame, globalIni, localIni);
|
||||||
|
|
||||||
|
@ -278,7 +277,7 @@ static void ApplyMemoryPatches(const Core::CPUThreadGuard& guard,
|
||||||
std::lock_guard lock(s_on_frame_memory_mutex);
|
std::lock_guard lock(s_on_frame_memory_mutex);
|
||||||
for (std::size_t index : memory_patch_indices)
|
for (std::size_t index : memory_patch_indices)
|
||||||
{
|
{
|
||||||
PowerPC::debug_interface.ApplyExistingPatch(guard, index);
|
guard.GetSystem().GetPowerPC().GetDebugInterface().ApplyExistingPatch(guard, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,10 @@
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace Common
|
||||||
|
{
|
||||||
class IniFile;
|
class IniFile;
|
||||||
|
}
|
||||||
|
|
||||||
namespace PatchEngine
|
namespace PatchEngine
|
||||||
{
|
{
|
||||||
|
@ -47,8 +50,8 @@ int GetSpeedhackCycles(const u32 addr);
|
||||||
std::optional<PatchEntry> DeserializeLine(std::string line);
|
std::optional<PatchEntry> DeserializeLine(std::string line);
|
||||||
std::string SerializeLine(const PatchEntry& entry);
|
std::string SerializeLine(const PatchEntry& entry);
|
||||||
void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
|
void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
|
||||||
const IniFile& globalIni, const IniFile& localIni);
|
const Common::IniFile& globalIni, const Common::IniFile& localIni);
|
||||||
void SavePatchSection(IniFile* local_ini, const std::vector<Patch>& patches);
|
void SavePatchSection(Common::IniFile* local_ini, const std::vector<Patch>& patches);
|
||||||
void LoadPatches();
|
void LoadPatches();
|
||||||
|
|
||||||
void AddMemoryPatch(std::size_t index);
|
void AddMemoryPatch(std::size_t index);
|
||||||
|
|
|
@ -16,8 +16,15 @@
|
||||||
#include "Core/PowerPC/Expression.h"
|
#include "Core/PowerPC/Expression.h"
|
||||||
#include "Core/PowerPC/JitInterface.h"
|
#include "Core/PowerPC/JitInterface.h"
|
||||||
#include "Core/PowerPC/MMU.h"
|
#include "Core/PowerPC/MMU.h"
|
||||||
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
|
BreakPoints::BreakPoints(Core::System& system) : m_system(system)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BreakPoints::~BreakPoints() = default;
|
||||||
|
|
||||||
bool BreakPoints::IsAddressBreakPoint(u32 address) const
|
bool BreakPoints::IsAddressBreakPoint(u32 address) const
|
||||||
{
|
{
|
||||||
return std::any_of(m_breakpoints.begin(), m_breakpoints.end(),
|
return std::any_of(m_breakpoints.begin(), m_breakpoints.end(),
|
||||||
|
@ -106,7 +113,7 @@ void BreakPoints::Add(TBreakPoint bp)
|
||||||
if (IsAddressBreakPoint(bp.address))
|
if (IsAddressBreakPoint(bp.address))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true);
|
m_system.GetJitInterface().InvalidateICache(bp.address, 4, true);
|
||||||
|
|
||||||
m_breakpoints.emplace_back(std::move(bp));
|
m_breakpoints.emplace_back(std::move(bp));
|
||||||
}
|
}
|
||||||
|
@ -142,7 +149,7 @@ void BreakPoints::Add(u32 address, bool temp, bool break_on_hit, bool log_on_hit
|
||||||
m_breakpoints.emplace_back(std::move(bp));
|
m_breakpoints.emplace_back(std::move(bp));
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true);
|
m_system.GetJitInterface().InvalidateICache(address, 4, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BreakPoints::ToggleBreakPoint(u32 address)
|
bool BreakPoints::ToggleBreakPoint(u32 address)
|
||||||
|
@ -166,14 +173,14 @@ void BreakPoints::Remove(u32 address)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_breakpoints.erase(iter);
|
m_breakpoints.erase(iter);
|
||||||
Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true);
|
m_system.GetJitInterface().InvalidateICache(address, 4, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BreakPoints::Clear()
|
void BreakPoints::Clear()
|
||||||
{
|
{
|
||||||
for (const TBreakPoint& bp : m_breakpoints)
|
for (const TBreakPoint& bp : m_breakpoints)
|
||||||
{
|
{
|
||||||
Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true);
|
m_system.GetJitInterface().InvalidateICache(bp.address, 4, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_breakpoints.clear();
|
m_breakpoints.clear();
|
||||||
|
@ -186,7 +193,7 @@ void BreakPoints::ClearAllTemporary()
|
||||||
{
|
{
|
||||||
if (bp->is_temporary)
|
if (bp->is_temporary)
|
||||||
{
|
{
|
||||||
Core::System::GetInstance().GetJitInterface().InvalidateICache(bp->address, 4, true);
|
m_system.GetJitInterface().InvalidateICache(bp->address, 4, true);
|
||||||
bp = m_breakpoints.erase(bp);
|
bp = m_breakpoints.erase(bp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -196,6 +203,12 @@ void BreakPoints::ClearAllTemporary()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemChecks::MemChecks(Core::System& system) : m_system(system)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemChecks::~MemChecks() = default;
|
||||||
|
|
||||||
MemChecks::TMemChecksStr MemChecks::GetStrings() const
|
MemChecks::TMemChecksStr MemChecks::GetStrings() const
|
||||||
{
|
{
|
||||||
TMemChecksStr mc_strings;
|
TMemChecksStr mc_strings;
|
||||||
|
@ -279,8 +292,8 @@ void MemChecks::Add(TMemCheck memory_check)
|
||||||
// If this is the first one, clear the JIT cache so it can switch to
|
// If this is the first one, clear the JIT cache so it can switch to
|
||||||
// watchpoint-compatible code.
|
// watchpoint-compatible code.
|
||||||
if (!had_any)
|
if (!had_any)
|
||||||
Core::System::GetInstance().GetJitInterface().ClearCache();
|
m_system.GetJitInterface().ClearCache();
|
||||||
Core::System::GetInstance().GetMMU().DBATUpdated();
|
m_system.GetMMU().DBATUpdated();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,8 +321,8 @@ void MemChecks::Remove(u32 address)
|
||||||
Core::RunAsCPUThread([&] {
|
Core::RunAsCPUThread([&] {
|
||||||
m_mem_checks.erase(iter);
|
m_mem_checks.erase(iter);
|
||||||
if (!HasAny())
|
if (!HasAny())
|
||||||
Core::System::GetInstance().GetJitInterface().ClearCache();
|
m_system.GetJitInterface().ClearCache();
|
||||||
Core::System::GetInstance().GetMMU().DBATUpdated();
|
m_system.GetMMU().DBATUpdated();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,8 +330,8 @@ void MemChecks::Clear()
|
||||||
{
|
{
|
||||||
Core::RunAsCPUThread([&] {
|
Core::RunAsCPUThread([&] {
|
||||||
m_mem_checks.clear();
|
m_mem_checks.clear();
|
||||||
Core::System::GetInstance().GetJitInterface().ClearCache();
|
m_system.GetJitInterface().ClearCache();
|
||||||
Core::System::GetInstance().GetMMU().DBATUpdated();
|
m_system.GetMMU().DBATUpdated();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,14 +365,14 @@ bool MemChecks::OverlapsMemcheck(u32 address, u32 length) const
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TMemCheck::Action(Common::DebugInterface* debug_interface, u64 value, u32 addr, bool write,
|
bool TMemCheck::Action(Core::System& system, Common::DebugInterface* debug_interface, u64 value,
|
||||||
size_t size, u32 pc)
|
u32 addr, bool write, size_t size, u32 pc)
|
||||||
{
|
{
|
||||||
if (!is_enabled)
|
if (!is_enabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (((write && is_break_on_write) || (!write && is_break_on_read)) &&
|
if (((write && is_break_on_write) || (!write && is_break_on_read)) &&
|
||||||
EvaluateCondition(this->condition))
|
EvaluateCondition(system, this->condition))
|
||||||
{
|
{
|
||||||
if (log_on_hit)
|
if (log_on_hit)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,10 @@ namespace Common
|
||||||
{
|
{
|
||||||
class DebugInterface;
|
class DebugInterface;
|
||||||
}
|
}
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
struct TBreakPoint
|
struct TBreakPoint
|
||||||
{
|
{
|
||||||
|
@ -45,14 +49,21 @@ struct TMemCheck
|
||||||
std::optional<Expression> condition;
|
std::optional<Expression> condition;
|
||||||
|
|
||||||
// returns whether to break
|
// returns whether to break
|
||||||
bool Action(Common::DebugInterface* debug_interface, u64 value, u32 addr, bool write, size_t size,
|
bool Action(Core::System& system, Common::DebugInterface* debug_interface, u64 value, u32 addr,
|
||||||
u32 pc);
|
bool write, size_t size, u32 pc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Code breakpoints.
|
// Code breakpoints.
|
||||||
class BreakPoints
|
class BreakPoints
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit BreakPoints(Core::System& system);
|
||||||
|
BreakPoints(const BreakPoints& other) = delete;
|
||||||
|
BreakPoints(BreakPoints&& other) = delete;
|
||||||
|
BreakPoints& operator=(const BreakPoints& other) = delete;
|
||||||
|
BreakPoints& operator=(BreakPoints&& other) = delete;
|
||||||
|
~BreakPoints();
|
||||||
|
|
||||||
using TBreakPoints = std::vector<TBreakPoint>;
|
using TBreakPoints = std::vector<TBreakPoint>;
|
||||||
using TBreakPointsStr = std::vector<std::string>;
|
using TBreakPointsStr = std::vector<std::string>;
|
||||||
|
|
||||||
|
@ -82,12 +93,20 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TBreakPoints m_breakpoints;
|
TBreakPoints m_breakpoints;
|
||||||
|
Core::System& m_system;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Memory breakpoints
|
// Memory breakpoints
|
||||||
class MemChecks
|
class MemChecks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit MemChecks(Core::System& system);
|
||||||
|
MemChecks(const MemChecks& other) = delete;
|
||||||
|
MemChecks(MemChecks&& other) = delete;
|
||||||
|
MemChecks& operator=(const MemChecks& other) = delete;
|
||||||
|
MemChecks& operator=(MemChecks&& other) = delete;
|
||||||
|
~MemChecks();
|
||||||
|
|
||||||
using TMemChecks = std::vector<TMemCheck>;
|
using TMemChecks = std::vector<TMemCheck>;
|
||||||
using TMemChecksStr = std::vector<std::string>;
|
using TMemChecksStr = std::vector<std::string>;
|
||||||
|
|
||||||
|
@ -109,4 +128,5 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TMemChecks m_mem_checks;
|
TMemChecks m_mem_checks;
|
||||||
|
Core::System& m_system;
|
||||||
};
|
};
|
||||||
|
|
|
@ -214,7 +214,7 @@ bool CachedInterpreter::CheckFPU(CachedInterpreter& cached_interpreter, u32 data
|
||||||
if (!ppc_state.msr.FP)
|
if (!ppc_state.msr.FP)
|
||||||
{
|
{
|
||||||
ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
||||||
PowerPC::CheckExceptions();
|
cached_interpreter.m_system.GetPowerPC().CheckExceptions();
|
||||||
ppc_state.downcount -= data;
|
ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ bool CachedInterpreter::CheckDSI(CachedInterpreter& cached_interpreter, u32 data
|
||||||
auto& ppc_state = cached_interpreter.m_ppc_state;
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
if (ppc_state.Exceptions & EXCEPTION_DSI)
|
if (ppc_state.Exceptions & EXCEPTION_DSI)
|
||||||
{
|
{
|
||||||
PowerPC::CheckExceptions();
|
cached_interpreter.m_system.GetPowerPC().CheckExceptions();
|
||||||
ppc_state.downcount -= data;
|
ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,7 @@ bool CachedInterpreter::CheckProgramException(CachedInterpreter& cached_interpre
|
||||||
auto& ppc_state = cached_interpreter.m_ppc_state;
|
auto& ppc_state = cached_interpreter.m_ppc_state;
|
||||||
if (ppc_state.Exceptions & EXCEPTION_PROGRAM)
|
if (ppc_state.Exceptions & EXCEPTION_PROGRAM)
|
||||||
{
|
{
|
||||||
PowerPC::CheckExceptions();
|
cached_interpreter.m_system.GetPowerPC().CheckExceptions();
|
||||||
ppc_state.downcount -= data;
|
ppc_state.downcount -= data;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ bool CachedInterpreter::CheckProgramException(CachedInterpreter& cached_interpre
|
||||||
|
|
||||||
bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data)
|
bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data)
|
||||||
{
|
{
|
||||||
PowerPC::CheckBreakPoints();
|
cached_interpreter.m_system.GetPowerPC().CheckBreakPoints();
|
||||||
if (cached_interpreter.m_system.GetCPU().GetState() != CPU::State::Running)
|
if (cached_interpreter.m_system.GetCPU().GetState() != CPU::State::Running)
|
||||||
{
|
{
|
||||||
cached_interpreter.m_ppc_state.downcount -= data;
|
cached_interpreter.m_ppc_state.downcount -= data;
|
||||||
|
@ -295,7 +295,7 @@ void CachedInterpreter::Jit(u32 address)
|
||||||
// Address of instruction could not be translated
|
// Address of instruction could not be translated
|
||||||
m_ppc_state.npc = nextPC;
|
m_ppc_state.npc = nextPC;
|
||||||
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
m_ppc_state.Exceptions |= EXCEPTION_ISI;
|
||||||
PowerPC::CheckExceptions();
|
m_system.GetPowerPC().CheckExceptions();
|
||||||
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,8 @@ void CachedInterpreter::Jit(u32 address)
|
||||||
if (!op.skip)
|
if (!op.skip)
|
||||||
{
|
{
|
||||||
const bool breakpoint =
|
const bool breakpoint =
|
||||||
m_enable_debugging && PowerPC::breakpoints.IsAddressBreakPoint(op.address);
|
m_enable_debugging &&
|
||||||
|
m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(op.address);
|
||||||
const bool check_fpu = (op.opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound;
|
const bool check_fpu = (op.opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound;
|
||||||
const bool endblock = (op.opinfo->flags & FL_ENDBLOCK) != 0;
|
const bool endblock = (op.opinfo->flags & FL_ENDBLOCK) != 0;
|
||||||
const bool memcheck = (op.opinfo->flags & FL_LOADSTORE) && jo.memcheck;
|
const bool memcheck = (op.opinfo->flags & FL_LOADSTORE) && jo.memcheck;
|
||||||
|
|
|
@ -267,21 +267,22 @@ std::optional<Expression> Expression::TryParse(std::string_view text)
|
||||||
return Expression{text, std::move(ex), std::move(vars)};
|
return Expression{text, std::move(ex), std::move(vars)};
|
||||||
}
|
}
|
||||||
|
|
||||||
double Expression::Evaluate() const
|
double Expression::Evaluate(Core::System& system) const
|
||||||
{
|
{
|
||||||
SynchronizeBindings(SynchronizeDirection::From);
|
SynchronizeBindings(system, SynchronizeDirection::From);
|
||||||
|
|
||||||
double result = expr_eval(m_expr.get());
|
double result = expr_eval(m_expr.get());
|
||||||
|
|
||||||
SynchronizeBindings(SynchronizeDirection::To);
|
SynchronizeBindings(system, SynchronizeDirection::To);
|
||||||
|
|
||||||
Reporting(result);
|
Reporting(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Expression::SynchronizeBindings(SynchronizeDirection dir) const
|
void Expression::SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const
|
||||||
{
|
{
|
||||||
|
auto& ppc_state = system.GetPPCState();
|
||||||
auto bind = m_binds.begin();
|
auto bind = m_binds.begin();
|
||||||
for (auto* v = m_vars->head; v != nullptr; v = v->next, ++bind)
|
for (auto* v = m_vars->head; v != nullptr; v = v->next, ++bind)
|
||||||
{
|
{
|
||||||
|
@ -293,25 +294,25 @@ void Expression::SynchronizeBindings(SynchronizeDirection dir) const
|
||||||
break;
|
break;
|
||||||
case VarBindingType::GPR:
|
case VarBindingType::GPR:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = static_cast<double>(PowerPC::ppcState.gpr[bind->index]);
|
v->value = static_cast<double>(ppc_state.gpr[bind->index]);
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
ppc_state.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
||||||
break;
|
break;
|
||||||
case VarBindingType::FPR:
|
case VarBindingType::FPR:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = PowerPC::ppcState.ps[bind->index].PS0AsDouble();
|
v->value = ppc_state.ps[bind->index].PS0AsDouble();
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.ps[bind->index].SetPS0(v->value);
|
ppc_state.ps[bind->index].SetPS0(v->value);
|
||||||
break;
|
break;
|
||||||
case VarBindingType::SPR:
|
case VarBindingType::SPR:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = static_cast<double>(PowerPC::ppcState.spr[bind->index]);
|
v->value = static_cast<double>(ppc_state.spr[bind->index]);
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
ppc_state.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
|
||||||
break;
|
break;
|
||||||
case VarBindingType::PCtr:
|
case VarBindingType::PCtr:
|
||||||
if (dir == SynchronizeDirection::From)
|
if (dir == SynchronizeDirection::From)
|
||||||
v->value = static_cast<double>(PowerPC::ppcState.pc);
|
v->value = static_cast<double>(ppc_state.pc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ struct expr_var_list;
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
class CPUThreadGuard;
|
class CPUThreadGuard;
|
||||||
}
|
class System;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
struct ExprDeleter
|
struct ExprDeleter
|
||||||
{
|
{
|
||||||
|
@ -36,7 +37,7 @@ class Expression
|
||||||
public:
|
public:
|
||||||
static std::optional<Expression> TryParse(std::string_view text);
|
static std::optional<Expression> TryParse(std::string_view text);
|
||||||
|
|
||||||
double Evaluate() const;
|
double Evaluate(Core::System& system) const;
|
||||||
|
|
||||||
std::string GetText() const;
|
std::string GetText() const;
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ private:
|
||||||
|
|
||||||
Expression(std::string_view text, ExprPointer ex, ExprVarListPointer vars);
|
Expression(std::string_view text, ExprPointer ex, ExprVarListPointer vars);
|
||||||
|
|
||||||
void SynchronizeBindings(SynchronizeDirection dir) const;
|
void SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const;
|
||||||
void Reporting(const double result) const;
|
void Reporting(const double result) const;
|
||||||
|
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
|
@ -73,7 +74,7 @@ private:
|
||||||
std::vector<VarBinding> m_binds;
|
std::vector<VarBinding> m_binds;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool EvaluateCondition(const std::optional<Expression>& condition)
|
inline bool EvaluateCondition(Core::System& system, const std::optional<Expression>& condition)
|
||||||
{
|
{
|
||||||
return !condition || condition->Evaluate() != 0.0;
|
return !condition || condition->Evaluate(system) != 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,17 +163,19 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len)
|
||||||
{
|
{
|
||||||
if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft)
|
if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft)
|
||||||
{
|
{
|
||||||
while (PowerPC::breakpoints.IsAddressBreakPoint(addr))
|
auto& breakpoints = Core::System::GetInstance().GetPowerPC().GetBreakPoints();
|
||||||
|
while (breakpoints.IsAddressBreakPoint(addr))
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.Remove(addr);
|
breakpoints.Remove(addr);
|
||||||
INFO_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr);
|
INFO_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (PowerPC::memchecks.GetMemCheck(addr, len) != nullptr)
|
auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
|
||||||
|
while (memchecks.GetMemCheck(addr, len) != nullptr)
|
||||||
{
|
{
|
||||||
PowerPC::memchecks.Remove(addr);
|
memchecks.Remove(addr);
|
||||||
INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr);
|
INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -869,7 +871,8 @@ static bool AddBreakpoint(BreakpointType type, u32 addr, u32 len)
|
||||||
{
|
{
|
||||||
if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft)
|
if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft)
|
||||||
{
|
{
|
||||||
PowerPC::breakpoints.Add(addr);
|
auto& breakpoints = Core::System::GetInstance().GetPowerPC().GetBreakPoints();
|
||||||
|
breakpoints.Add(addr);
|
||||||
INFO_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}",
|
INFO_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}",
|
||||||
static_cast<int>(type), len, addr);
|
static_cast<int>(type), len, addr);
|
||||||
}
|
}
|
||||||
|
@ -886,7 +889,8 @@ static bool AddBreakpoint(BreakpointType type, u32 addr, u32 len)
|
||||||
new_memcheck.break_on_hit = true;
|
new_memcheck.break_on_hit = true;
|
||||||
new_memcheck.log_on_hit = false;
|
new_memcheck.log_on_hit = false;
|
||||||
new_memcheck.is_enabled = true;
|
new_memcheck.is_enabled = true;
|
||||||
PowerPC::memchecks.Add(std::move(new_memcheck));
|
auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
|
||||||
|
memchecks.Add(std::move(new_memcheck));
|
||||||
INFO_LOG_FMT(GDB_STUB, "gdb: added {} memcheck: {:08x} bytes at {:08x}", static_cast<int>(type),
|
INFO_LOG_FMT(GDB_STUB, "gdb: added {} memcheck: {:08x} bytes at {:08x}", static_cast<int>(type),
|
||||||
len, addr);
|
len, addr);
|
||||||
}
|
}
|
||||||
|
@ -1048,7 +1052,7 @@ void InitLocal(const char* socket)
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
strcpy(addr.sun_path, socket);
|
strcpy(addr.sun_path, socket);
|
||||||
|
|
||||||
InitGeneric(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), NULL, NULL);
|
InitGeneric(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), nullptr, nullptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue