diff --git a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj index f0485b609..b4c4648c6 100644 --- a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj +++ b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj @@ -788,6 +788,9 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = z; GENERATE_INFOPLIST_FILE = YES; @@ -1039,6 +1042,10 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = "$(VERSION)"; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; @@ -1197,6 +1204,9 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); GCC_OPTIMIZATION_LEVEL = z; GENERATE_INFOPLIST_FILE = YES; @@ -1448,6 +1458,10 @@ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", + "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries", ); MARKETING_VERSION = "$(VERSION)"; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index f809145ae..c39223b5a 100644 Binary files a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate and b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme b/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme index ae7c58c0b..f79f4ed54 100644 --- a/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme +++ b/src/MeloNX/MeloNX.xcodeproj/xcshareddata/xcschemes/MeloNX.xcscheme @@ -58,6 +58,7 @@ buildConfiguration = "Release" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + disableMainThreadChecker = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -68,7 +69,8 @@ allowLocationSimulation = "YES" queueDebuggingEnabled = "No" consoleMode = "0" - structuredConsoleMode = "2"> + structuredConsoleMode = "2" + disablePerformanceAntipatternChecker = "YES"> #include + #ifdef __cplusplus extern "C" { #endif + struct GameInfo { long FileSize; char TitleName[512]; @@ -41,6 +43,10 @@ struct DlcNcaList { struct DlcNcaListItem* items; }; +typedef void (^SwiftCallback)(NSString *result); + +void RegisterCallback(NSString *identifier, SwiftCallback callback); + extern struct GameInfo get_game_info(int, char*); extern struct DlcNcaList get_dlc_nca_list(const char* titleIdPtr, const char* pathPtr); diff --git a/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift b/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift index c25a148ef..3c09d1905 100644 --- a/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift +++ b/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift @@ -535,9 +535,9 @@ class Ryujinx : ObservableObject { args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode]) - // args.append(contentsOf: ["--exclusive-fullscreen", String(true)]) - // args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"]) - // args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"]) + args.append(contentsOf: ["--exclusive-fullscreen", String(true)]) + args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"]) + args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"]) // We don't need this. Ryujinx should handle it fine :3 // this also causes crashes in some games :3 diff --git a/src/MeloNX/MeloNX/App/Views/Main/Emulation/EmulationView/EmulationView.swift b/src/MeloNX/MeloNX/App/Views/Main/Emulation/EmulationView/EmulationView.swift index 43043a43c..58a2b6d49 100644 --- a/src/MeloNX/MeloNX/App/Views/Main/Emulation/EmulationView/EmulationView.swift +++ b/src/MeloNX/MeloNX/App/Views/Main/Emulation/EmulationView/EmulationView.swift @@ -142,6 +142,15 @@ struct EmulationView: View { // print(cool) } } + + RegisterCallback("exit-emulation") { cool in + DispatchQueue.main.async { + print(cool) + startgame = nil + stop_emulation() + try? Ryujinx.shared.stop() + } + } } .onChange(of: scenePhase) { newPhase in // Detect when the app enters the background diff --git a/src/MeloNX/MeloNX/App/Views/Main/Emulation/MetalView/MeloMTKView.swift b/src/MeloNX/MeloNX/App/Views/Main/Emulation/MetalView/MeloMTKView.swift index 442065c85..25d296012 100644 --- a/src/MeloNX/MeloNX/App/Views/Main/Emulation/MetalView/MeloMTKView.swift +++ b/src/MeloNX/MeloNX/App/Views/Main/Emulation/MetalView/MeloMTKView.swift @@ -9,10 +9,10 @@ import MetalKit import UIKit class MeloMTKView: MTKView { - private var activeTouches: [UITouch] = [] private var ignoredTouches: Set = [] - + private var touchIndexMap: [UITouch: Int] = [:] + private let baseWidth: CGFloat = 1280 private let baseHeight: CGFloat = 720 private var aspectRatio: AspectRatio = .fixed16x9 @@ -84,83 +84,112 @@ class MeloMTKView: MTKView { return CGPoint(x: scaledX, y: scaledY) } + private func getNextAvailableIndex() -> Int { + for i in 0.., with event: UIEvent?) { super.touchesBegan(touches, with: event) - + let disabled = UserDefaults.standard.bool(forKey: "disableTouch") + guard !disabled else { return } setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9) - - if !disabled { - for touch in touches { - let location = touch.location(in: self) - if scaleToTargetResolution(location) == nil { - ignoredTouches.insert(touch) - continue - } - - activeTouches.append(touch) - let index = activeTouches.firstIndex(of: touch)! - - let scaledLocation = scaleToTargetResolution(location)! - // // print("Touch began at: \(scaledLocation) and \(self.aspectRatio)") - touch_began(Float(scaledLocation.x), Float(scaledLocation.y), Int32(index)) + + for touch in touches { + let location = touch.location(in: self) + guard let scaledLocation = scaleToTargetResolution(location) else { + ignoredTouches.insert(touch) + continue } + + let index = getNextAvailableIndex() + touchIndexMap[touch] = index + activeTouches.append(touch) + + touch_began(Float(scaledLocation.x), Float(scaledLocation.y), Int32(index)) } } override func touchesEnded(_ touches: Set, with event: UIEvent?) { super.touchesEnded(touches, with: event) - + let disabled = UserDefaults.standard.bool(forKey: "disableTouch") - - setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9) - - if !disabled { + guard !disabled else { for touch in touches { - if ignoredTouches.contains(touch) { - ignoredTouches.remove(touch) - continue - } - + ignoredTouches.remove(touch) if let index = activeTouches.firstIndex(of: touch) { activeTouches.remove(at: index) - - // // print("Touch ended for index \(index)") - touch_ended(Int32(index)) } + touchIndexMap.removeValue(forKey: touch) + } + return + } + + for touch in touches { + if ignoredTouches.remove(touch) != nil { + continue + } + + if let touchIndex = touchIndexMap[touch] { + touch_ended(Int32(touchIndex)) + + if let arrayIndex = activeTouches.firstIndex(of: touch) { + activeTouches.remove(at: arrayIndex) + } + touchIndexMap.removeValue(forKey: touch) } } } override func touchesMoved(_ touches: Set, with event: UIEvent?) { super.touchesMoved(touches, with: event) - + let disabled = UserDefaults.standard.bool(forKey: "disableTouch") + guard !disabled else { return } setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9) - - if !disabled { - for touch in touches { - if ignoredTouches.contains(touch) { - continue - } - - let location = touch.location(in: self) - guard let scaledLocation = scaleToTargetResolution(location) else { - if let index = activeTouches.firstIndex(of: touch) { - activeTouches.remove(at: index) - // // print("Touch left active area, removed index \(index)") - touch_ended(Int32(index)) - } - continue - } - - if let index = activeTouches.firstIndex(of: touch) { - // // print("Touch moved to: \(scaledLocation)") - touch_moved(Float(scaledLocation.x), Float(scaledLocation.y), Int32(index)) - } + + for touch in touches { + if ignoredTouches.contains(touch) { + continue } + + guard let touchIndex = touchIndexMap[touch] else { + continue + } + + let location = touch.location(in: self) + guard let scaledLocation = scaleToTargetResolution(location) else { + touch_ended(Int32(touchIndex)) + + if let arrayIndex = activeTouches.firstIndex(of: touch) { + activeTouches.remove(at: arrayIndex) + } + touchIndexMap.removeValue(forKey: touch) + ignoredTouches.insert(touch) + continue + } + + touch_moved(Float(scaledLocation.x), Float(scaledLocation.y), Int32(touchIndex)) } } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + touchesEnded(touches, with: event) + } + + + func resetTouchTracking() { + activeTouches.removeAll() + ignoredTouches.removeAll() + touchIndexMap.removeAll() + } } + diff --git a/src/MeloNX/MeloNX/App/Views/Main/UI/GamesList/GameListView.swift b/src/MeloNX/MeloNX/App/Views/Main/UI/GamesList/GameListView.swift index 6125bdae9..47124f48e 100644 --- a/src/MeloNX/MeloNX/App/Views/Main/UI/GamesList/GameListView.swift +++ b/src/MeloNX/MeloNX/App/Views/Main/UI/GamesList/GameListView.swift @@ -1252,3 +1252,16 @@ extension View { } } } + + +extension View { + @available(iOS, introduced: 14.0, deprecated: 19.0, message: "") + func glassEffect(_ style: Glass, in shape: some Shape) -> some View { + return self + } +} + +@available(iOS, introduced: 14.0, deprecated: 19.0, message: "") +struct Glass: Hashable { + static var regular = Glass() +} diff --git a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/Info.plist b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/Info.plist index 6b69c67ad..176855fa8 100644 Binary files a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/Info.plist and b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/Info.plist differ diff --git a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/RyujinxHelper b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/RyujinxHelper index b89e9d5b0..b411095c9 100755 Binary files a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/RyujinxHelper and b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/RyujinxHelper differ diff --git a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/_CodeSignature/CodeResources b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/_CodeSignature/CodeResources index 0483b32cc..a342a7acb 100644 --- a/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/_CodeSignature/CodeResources +++ b/src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/RyujinxHelper.framework/_CodeSignature/CodeResources @@ -10,7 +10,7 @@ Info.plist - RTwvCLsTMs+YfZ9ZeF25QYe7/LE= + GYWZONTCP5su4yOAk0d5jCd2K88= Modules/module.modulemap diff --git a/src/Ryujinx.Graphics.Vulkan/Constants.cs b/src/Ryujinx.Graphics.Vulkan/Constants.cs index 8103e2de8..2267172e3 100644 --- a/src/Ryujinx.Graphics.Vulkan/Constants.cs +++ b/src/Ryujinx.Graphics.Vulkan/Constants.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan public const int MaxShaderStages = 5; public const int MaxUniformBuffersPerStage = 18; public const int MaxStorageBuffersPerStage = 16; - public const int MaxTexturesPerStage = 31; + public const int MaxTexturesPerStage = 18; public const int MaxImagesPerStage = 16; public const int MaxUniformBufferBindings = MaxUniformBuffersPerStage * MaxShaderStages; public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages; diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index 3fe20950c..e7fb5f1f7 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -702,12 +702,13 @@ namespace Ryujinx.Graphics.Vulkan if (true) { try - { - UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp); - } catch (Exception e) { UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp); } + catch (Exception e) + { + UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp); + } } else { @@ -763,7 +764,7 @@ namespace Ryujinx.Graphics.Vulkan if (info.Buffer.Handle == 0) { info.Buffer = dummyBuffer?.Get(cbs).Value ?? default; - info.Offset = 0; + // info.Offset = 0; info.Range = Vk.WholeSize; } @@ -798,6 +799,13 @@ namespace Ryujinx.Graphics.Vulkan } } + var dummyImageInfo = new DescriptorImageInfo + { + ImageView = _dummyTexture.GetImageView().Get(cbs).Value, + Sampler = _dummySampler.GetSampler().Get(cbs).Value, + ImageLayout = ImageLayout.General + }; + DescriptorSetTemplate template = program.Templates[setIndex]; DescriptorSetTemplateWriter tu = _templateUpdater.Begin(template); @@ -871,12 +879,12 @@ namespace Ryujinx.Graphics.Vulkan if (texture.ImageView.Handle == 0) { - texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value; + texture.ImageView = dummyImageInfo.ImageView; } if (texture.Sampler.Handle == 0) { - texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value; + texture.Sampler = dummyImageInfo.Sampler; } } @@ -916,7 +924,7 @@ namespace Ryujinx.Graphics.Vulkan for (int i = 0; i < count; i++) { - images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default; + images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? dummyImageInfo.ImageView; } tu.Push(images[..count]); diff --git a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs index 439fcb8ea..205be5aeb 100644 --- a/src/Ryujinx.Graphics.Vulkan/ImageArray.cs +++ b/src/Ryujinx.Graphics.Vulkan/ImageArray.cs @@ -188,15 +188,21 @@ namespace Ryujinx.Graphics.Vulkan var dsc = program.GetNewDescriptorSetCollection(setIndex, out var isNew).Get(cbs); + DescriptorSetTemplate template = program.Templates[setIndex]; + + DescriptorSetTemplateWriter tu = templateUpdater.Begin(template); + if (!_isBuffer) { - dsc.UpdateImages(0, 0, GetImageInfos(_gd, cbs, dummyTexture), DescriptorType.StorageImage); + tu.Push(GetImageInfos(_gd, cbs, dummyTexture)); } else { - dsc.UpdateBufferImages(0, 0, GetBufferViews(cbs), DescriptorType.StorageTexelBuffer); + tu.Push(GetBufferViews(cbs)); } + templateUpdater.Commit(_gd, device, sets[0]); + sets = dsc.GetSets(); return sets; diff --git a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs index 99238b1f5..d2e16fc32 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureArray.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureArray.cs @@ -159,8 +159,8 @@ namespace Ryujinx.Graphics.Vulkan } texture.ImageLayout = ImageLayout.General; - texture.ImageView = refs.View?.Get(cbs).Value ?? default; - texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default; + texture.ImageView = refs.View?.Get(cbs).Value ?? dummyTexture.GetImageView().Get(cbs).Value; + texture.Sampler = refs.Sampler?.Get(cbs).Value ?? dummySampler.GetSampler().Get(cbs).Value; if (texture.ImageView.Handle == 0) { diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 5f3e91cdc..bb4792dbe 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -647,6 +647,15 @@ namespace Ryujinx.Graphics.Vulkan Format.Bc7Srgb, Format.Bc7Unorm); + if (!OperatingSystem.IsIOSVersionAtLeast(16, 4)) + { + // On iOS 16.4 and later, these formats are supported. + // On earlier versions, it is not supported. + supportsBc123CompressionFormat = false; + supportsBc45CompressionFormat = false; + supportsBc67CompressionFormat = false; + } + bool supportsEtc2CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags, Format.Etc2RgbaSrgb, Format.Etc2RgbaUnorm, @@ -714,7 +723,7 @@ namespace Ryujinx.Graphics.Vulkan SystemMemoryType memoryType; - if (IsSharedMemory) + if (IsSharedMemory && !IsMoltenVk) { memoryType = SystemMemoryType.UnifiedMemory; } diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs index fc02ea172..d0f1f8da3 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs @@ -1,10 +1,14 @@ using Ryujinx.Common; +using System.Runtime.InteropServices; using System; namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy { class ILibraryAppletSelfAccessor : IpcService { + [DllImport("RyujinxHelper.framework/RyujinxHelper", CallingConvention = CallingConvention.Cdecl)] + public static extern void TriggerCallback(string cIdentifier); + private readonly AppletStandalone _appletStandalone = new(); public ILibraryAppletSelfAccessor(ServiceCtx context) @@ -45,6 +49,14 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib return ResultCode.Success; } + [CommandCmif(1)] + public ResultCode PushOutData(ServiceCtx context) + { + TriggerCallback("exit-emulation"); + return ResultCode.Success; + } + + [CommandCmif(11)] // GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo public ResultCode GetLibraryAppletInfo(ServiceCtx context) diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs index 311084aa1..664ff07bd 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletAE/IStorage.cs @@ -11,6 +11,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE Data = data; } + public byte[] GetData() + { + return Data; + } + [CommandCmif(0)] // Open() -> object public ResultCode Open(ServiceCtx context)