Compare commits

..

No commits in common. "XC-ios-ht" and "1.8.0" have entirely different histories.

25 changed files with 200 additions and 327 deletions

View file

@ -28,10 +28,6 @@ MeloNX works on iPhone XS/XR and later and iPad 8th Gen and later. Check out the
- Recommended Device: iPhone 15 Pro or newer. - Recommended Device: iPhone 15 Pro or newer.
- Low-End Recommended Device: iPhone 13 Pro. - Low-End Recommended Device: iPhone 13 Pro.
## Discord Server
We have a discord server!
- https://discord.gg/melonx
## How to install ## How to install
@ -145,12 +141,12 @@ If having Issues installing firmware (Make sure your keys are installed first)
- **GPU** - **GPU**
The GPU emulator emulates the Switch's Maxwell GPU using Metal (via MoltenVK) APIs through a custom build of Silk.NET. The GPU emulator emulates the Switch's Maxwell GPU using Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
- **Input** - **Input**
We currently have support for keyboard, touch input, JoyCon input support, and nearly all MFI controllers. We currently have support for keyboard, touch input, JoyCon input support, and nearly all controllers.
Motion controls are natively supported in most cases, however JoyCons do not have motion support doe to an iOS limitation. Motion controls are natively supported in most cases.
- **DLC & Modifications** - **DLC & Modifications**
@ -161,13 +157,14 @@ If having Issues installing firmware (Make sure your keys are installed first)
The emulator has settings for enabling or disabling some logging, remapping controllers, and more. The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
# License ## License
This software is licensed under the terms of the [MeloNX license](LICENSE.txt). This software is licensed under the terms of the [MeloNX license (Based on MIT License)](LICENSE.txt).
This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3. This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3.
See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details. See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details.
# Credits ## Credits
- [Ryujinx](https://github.com/ryujinx-mirror/ryujinx) is used for the base of this emulator. (link is to ryujinx-mirror since they were supportive) - [Ryujinx](https://github.com/ryujinx-mirror/ryujinx) is used for the base of this emulator. (link is to ryujinx-mirror since they were supportive)
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system. - [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation. - [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.

View file

@ -8,4 +8,4 @@
// Configuration settings file format documentation can be found at: // Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974 // https://help.apple.com/xcode/#/dev745c5c974
VERSION = 2.0.1 VERSION = 2.0

View file

@ -788,9 +788,6 @@
"$(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",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
GCC_OPTIMIZATION_LEVEL = z; GCC_OPTIMIZATION_LEVEL = z;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -1042,10 +1039,6 @@
"$(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",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
MARKETING_VERSION = "$(VERSION)"; MARKETING_VERSION = "$(VERSION)";
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
@ -1204,9 +1197,6 @@
"$(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",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
GCC_OPTIMIZATION_LEVEL = z; GCC_OPTIMIZATION_LEVEL = z;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -1458,10 +1448,6 @@
"$(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",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
MARKETING_VERSION = "$(VERSION)"; MARKETING_VERSION = "$(VERSION)";
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;

View file

@ -58,7 +58,6 @@
buildConfiguration = "Release" buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
disableMainThreadChecker = "YES"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
@ -69,8 +68,7 @@
allowLocationSimulation = "YES" allowLocationSimulation = "YES"
queueDebuggingEnabled = "No" queueDebuggingEnabled = "No"
consoleMode = "0" consoleMode = "0"
structuredConsoleMode = "2" structuredConsoleMode = "2">
disablePerformanceAntipatternChecker = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
<BuildableReference <BuildableReference

View file

@ -16,12 +16,10 @@
#include <SDL2/SDL_syswm.h> #include <SDL2/SDL_syswm.h>
#include <StosJIT/StosJIT-Swift.h> #include <StosJIT/StosJIT-Swift.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct GameInfo { struct GameInfo {
long FileSize; long FileSize;
char TitleName[512]; char TitleName[512];
@ -43,10 +41,6 @@ struct DlcNcaList {
struct DlcNcaListItem* items; struct DlcNcaListItem* items;
}; };
typedef void (^SwiftCallback)(NSString *result);
void RegisterCallback(NSString *identifier, SwiftCallback callback);
extern struct GameInfo get_game_info(int, char*); extern struct GameInfo get_game_info(int, char*);
extern struct DlcNcaList get_dlc_nca_list(const char* titleIdPtr, const char* pathPtr); extern struct DlcNcaList get_dlc_nca_list(const char* titleIdPtr, const char* pathPtr);

View file

@ -62,6 +62,7 @@ func allocateTest() -> Bool {
memcpy(jitMemory, code, code.count) memcpy(jitMemory, code, code.count)
if mprotect(jitMemory, pageSize, PROT_READ | PROT_EXEC) != 0 { if mprotect(jitMemory, pageSize, PROT_READ | PROT_EXEC) != 0 {
return false return false
} }

View file

@ -12,7 +12,8 @@ class NativeController: Hashable, BaseController {
private var instanceID: SDL_JoystickID = -1 private var instanceID: SDL_JoystickID = -1
private var controller: OpaquePointer? private var controller: OpaquePointer?
private var nativeController: GCController private var nativeController: GCController
private var controllerMotionProvider: DSUMotionProvider? private var controllerMotionProvider: ControllerMotionProvider?
private var deviceMotionProvider: DeviceMotionProvider?
private let controllerHaptics: CHHapticEngine? private let controllerHaptics: CHHapticEngine?
private let rumbleController: RumbleController? private let rumbleController: RumbleController?
@ -21,21 +22,21 @@ class NativeController: Hashable, BaseController {
init(_ controller: GCController) { init(_ controller: GCController) {
nativeController = controller nativeController = controller
var ncontrollerHaptics = nativeController.haptics?.createEngine(withLocality: .default) controllerHaptics = nativeController.haptics?.createEngine(withLocality: .default)
let vendorName = nativeController.vendorName ?? "Unknown"
var usesdeviceHaptics = (ncontrollerHaptics == nil || vendorName.lowercased().hasSuffix("backbone") || vendorName.lowercased() == "backbone one")
controllerHaptics = usesdeviceHaptics ? ncontrollerHaptics : try? CHHapticEngine()
// Make sure the haptic engine exists before attempting to start it or initialize the controller. // Make sure the haptic engine exists before attempting to start it or initialize the controller.
if let hapticsEngine = controllerHaptics { if let hapticsEngine = controllerHaptics {
do { do {
try hapticsEngine.start() try hapticsEngine.start()
rumbleController = RumbleController(engine: hapticsEngine, rumbleMultiplier: 1.2) rumbleController = RumbleController(engine: hapticsEngine, rumbleMultiplier: 2.5)
// print("CHHapticEngine started and RumbleController initialized.")
} catch { } catch {
// print("Error starting CHHapticEngine: \(error.localizedDescription)")
rumbleController = nil rumbleController = nil
} }
} else { } else {
// print("CHHapticEngine is nil. Cannot initialize RumbleController.")
rumbleController = nil rumbleController = nil
} }
setupHandheldController() setupHandheldController()
@ -48,17 +49,27 @@ class NativeController: Hashable, BaseController {
internal func tryRegisterMotion(slot: UInt8) { internal func tryRegisterMotion(slot: UInt8) {
// Setup Motion // Setup Motion
let dsuServer = DSUServer.shared let dsuServer = DSUServer.shared
let vendorName = nativeController.vendorName ?? "Unknown"
var usesdevicemotion = (vendorName.lowercased() == "Joy-Con (l/R)".lowercased() || vendorName.lowercased().hasSuffix("backbone") || vendorName.lowercased() == "backbone one")
controllerMotionProvider = usesdevicemotion ? DeviceMotionProvider(slot: slot) : ControllerMotionProvider(controller: nativeController, slot: slot)
if nativeController.vendorName?.lowercased() == "Joy-Con (l/R)".lowercased() {
deviceMotionProvider = DeviceMotionProvider(slot: slot)
if let provider = deviceMotionProvider {
dsuServer.register(provider)
}
} else {
controllerMotionProvider = ControllerMotionProvider(controller: nativeController, slot: slot)
if let provider = controllerMotionProvider { if let provider = controllerMotionProvider {
dsuServer.register(provider) dsuServer.register(provider)
} }
} }
}
internal func tryGetMotionProvider() -> DSUMotionProvider? { return controllerMotionProvider } internal func tryGetMotionProvider() -> DSUMotionProvider? {
if nativeController.vendorName == "Joy-Con (l/R)" {
return deviceMotionProvider
} else {
return controllerMotionProvider
}
}
private func setupHandheldController() { private func setupHandheldController() {
if SDL_WasInit(Uint32(SDL_INIT_GAMECONTROLLER)) == 0 { if SDL_WasInit(Uint32(SDL_INIT_GAMECONTROLLER)) == 0 {
@ -83,39 +94,38 @@ class NativeController: Hashable, BaseController {
}, },
SetPlayerIndex: { userdata, playerIndex in SetPlayerIndex: { userdata, playerIndex in
// print("Player index set to \(playerIndex)") // print("Player index set to \(playerIndex)")
guard let userdata, let player = GCControllerPlayerIndex(rawValue: Int(playerIndex)) else { return }
let _self = Unmanaged<NativeController>.fromOpaque(userdata).takeUnretainedValue()
_self.nativeController.playerIndex = player
}, },
Rumble: { userdata, lowFreq, highFreq in Rumble: { userdata, lowFreq, highFreq in
// print("Rumble with \(lowFreq), \(highFreq)")
guard let userdata else { return 0 } guard let userdata else { return 0 }
let _self = Unmanaged<NativeController>.fromOpaque(userdata).takeUnretainedValue() let _self = Unmanaged<NativeController>.fromOpaque(userdata).takeUnretainedValue()
_self.rumbleController?.rumble(lowFreq: Float(lowFreq), highFreq: Float(highFreq)) _self.rumbleController?.rumble(lowFreq: Float(lowFreq), highFreq: Float(highFreq))
return 0 return 0
}, },
RumbleTriggers: { userdata, leftRumble, rightRumble in RumbleTriggers: { userdata, leftRumble, rightRumble in
// print("Trigger rumble with \(leftRumble), \(rightRumble)")
return 0 return 0
}, },
SetLED: { userdata, red, green, blue in SetLED: { userdata, red, green, blue in
guard let userdata else { return 0 } // print("Set LED to RGB(\(red), \(green), \(blue))")
let _self = Unmanaged<NativeController>.fromOpaque(userdata).takeUnretainedValue()
guard let light = _self.nativeController.light else { return 0 }
light.color = .init(red: Float(red), green: Float(green), blue: Float(blue))
return 0 return 0
}, },
SendEffect: { userdata, data, size in SendEffect: { userdata, data, size in
// print("Effect sent with size \(size)")
return 0 return 0
} }
) )
instanceID = SDL_JoystickAttachVirtualEx(&joystickDesc) instanceID = SDL_JoystickAttachVirtualEx(&joystickDesc)// SDL_JoystickAttachVirtual(SDL_JoystickType(SDL_JOYSTICK_TYPE_GAMECONTROLLER.rawValue), 6, 15, 1)
if instanceID < 0 { if instanceID < 0 {
// print("Failed to create virtual joystick: \(String(cString: SDL_GetError()))")
return return
} }
controller = SDL_GameControllerOpen(Int32(instanceID)) controller = SDL_GameControllerOpen(Int32(instanceID))
if controller == nil { if controller == nil {
// print("Failed to create virtual controller: \(String(cString: SDL_GetError()))")
return return
} }
@ -204,6 +214,7 @@ class NativeController: Hashable, BaseController {
func setButtonState(_ state: Uint8, for button: VirtualControllerButton) { func setButtonState(_ state: Uint8, for button: VirtualControllerButton) {
guard controller != nil else { return } guard controller != nil else { return }
// // print("Button: \(button.rawValue) {state: \(state)}")
if (button == .leftTrigger || button == .rightTrigger) && (state == 1 || state == 0) { if (button == .leftTrigger || button == .rightTrigger) && (state == 1 || state == 0) {
let axis: SDL_GameControllerAxis = (button == .leftTrigger) ? SDL_CONTROLLER_AXIS_TRIGGERLEFT : SDL_CONTROLLER_AXIS_TRIGGERRIGHT let axis: SDL_GameControllerAxis = (button == .leftTrigger) ? SDL_CONTROLLER_AXIS_TRIGGERLEFT : SDL_CONTROLLER_AXIS_TRIGGERRIGHT
let value: Int = (state == 1) ? 32767 : 0 let value: Int = (state == 1) ? 32767 : 0

View file

@ -213,6 +213,7 @@ class Ryujinx : ObservableObject {
var language: SystemLanguage = .americanEnglish var language: SystemLanguage = .americanEnglish
var regioncode: SystemRegionCode = .usa var regioncode: SystemRegionCode = .usa
var handHeldController: Bool = true var handHeldController: Bool = true
var backendMultithreading: Bool = true
init(gamepath: String = "", init(gamepath: String = "",
@ -241,6 +242,7 @@ class Ryujinx : ObservableObject {
language: SystemLanguage = .americanEnglish, language: SystemLanguage = .americanEnglish,
regioncode: SystemRegionCode = .usa, regioncode: SystemRegionCode = .usa,
handHeldController: Bool = false, handHeldController: Bool = false,
backendMultithreading: Bool = true
) { ) {
self.gamepath = gamepath self.gamepath = gamepath
self.inputids = inputids self.inputids = inputids
@ -268,6 +270,7 @@ class Ryujinx : ObservableObject {
self.language = language self.language = language
self.regioncode = regioncode self.regioncode = regioncode
self.handHeldController = handHeldController self.handHeldController = handHeldController
self.backendMultithreading = backendMultithreading
} }
@ -535,9 +538,9 @@ class Ryujinx : ObservableObject {
args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode]) args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode])
args.append(contentsOf: ["--exclusive-fullscreen", String(true)]) // args.append(contentsOf: ["--exclusive-fullscreen", String(true)])
args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"]) // 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-height", "\(Int(UIScreen.main.bounds.height))"])
// We don't need this. Ryujinx should handle it fine :3 // We don't need this. Ryujinx should handle it fine :3
// this also causes crashes in some games :3 // this also causes crashes in some games :3
@ -565,9 +568,13 @@ class Ryujinx : ObservableObject {
args.append(contentsOf: ["--aspect-ratio", config.aspectRatio.rawValue]) args.append(contentsOf: ["--aspect-ratio", config.aspectRatio.rawValue])
args.append(contentsOf: ["--system-timezone", TimeZone.current.identifier]) // args.append(contentsOf: ["--system-timezone", TimeZone.current.identifier])
// args.append(contentsOf: ["--system-time-offset", String(TimeZone.current.secondsFromGMT())]) args.append(contentsOf: ["--system-time-offset", String(TimeZone.current.secondsFromGMT())])
if !config.backendMultithreading {
args.append(contentsOf: ["--backend-multithreading", "Off"])
}
if config.nintendoinput { if config.nintendoinput {

View file

@ -264,6 +264,7 @@ struct ABXYView: View {
struct ButtonView: View { struct ButtonView: View {
var button: VirtualControllerButton var button: VirtualControllerButton
var callback: (() -> Void)? = nil
@AppStorage("onscreenhandheld") var onscreenjoy: Bool = false @AppStorage("onscreenhandheld") var onscreenjoy: Bool = false
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0 @AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
@ -344,6 +345,9 @@ struct ButtonView: View {
} }
private func handleButtonPress() { private func handleButtonPress() {
if let callback {
callback()
} else {
guard !isPressed || istoggle else { return } guard !isPressed || istoggle else { return }
if istoggle { if istoggle {
@ -358,10 +362,13 @@ struct ButtonView: View {
Haptics.shared.play(.medium) Haptics.shared.play(.medium)
} }
} }
}
private func handleButtonRelease() { private func handleButtonRelease() {
if istoggle { return } if istoggle { return }
if let callback { return }
guard isPressed else { return } guard isPressed else { return }
isPressed = false isPressed = false
@ -397,40 +404,23 @@ struct ButtonView: View {
// Centralized button configuration // Centralized button configuration
private var buttonConfig: ButtonConfiguration { private var buttonConfig: ButtonConfiguration {
switch button { switch button {
case .A: case .A: return .init(iconName: "a.circle.fill")
return ButtonConfiguration(iconName: "a.circle.fill") case .B: return .init(iconName: "b.circle.fill")
case .B: case .X: return .init(iconName: "x.circle.fill")
return ButtonConfiguration(iconName: "b.circle.fill") case .Y: return .init(iconName: "y.circle.fill")
case .X: case .leftStick: return .init(iconName: "l.joystick.press.down.fill")
return ButtonConfiguration(iconName: "x.circle.fill") case .rightStick: return .init(iconName: "r.joystick.press.down.fill")
case .Y: case .dPadUp: return .init(iconName: "arrowtriangle.up.circle.fill")
return ButtonConfiguration(iconName: "y.circle.fill") case .dPadDown: return .init(iconName: "arrowtriangle.down.circle.fill")
case .leftStick: case .dPadLeft: return .init(iconName: "arrowtriangle.left.circle.fill")
return ButtonConfiguration(iconName: "l.joystick.press.down.fill") case .dPadRight: return .init(iconName: "arrowtriangle.right.circle.fill")
case .rightStick: case .leftTrigger: return .init(iconName: "zl.rectangle.roundedtop.fill")
return ButtonConfiguration(iconName: "r.joystick.press.down.fill") case .rightTrigger: return .init(iconName: "zr.rectangle.roundedtop.fill")
case .dPadUp: case .leftShoulder: return .init(iconName: "l.rectangle.roundedbottom.fill")
return ButtonConfiguration(iconName: "arrowtriangle.up.circle.fill") case .rightShoulder: return .init(iconName: "r.rectangle.roundedbottom.fill")
case .dPadDown: case .start: return .init(iconName: "plus.circle.fill")
return ButtonConfiguration(iconName: "arrowtriangle.down.circle.fill") case .back: return .init(iconName: "minus.circle.fill")
case .dPadLeft: case .guide: return .init(iconName: "gearshape.fill")
return ButtonConfiguration(iconName: "arrowtriangle.left.circle.fill")
case .dPadRight:
return ButtonConfiguration(iconName: "arrowtriangle.right.circle.fill")
case .leftTrigger:
return ButtonConfiguration(iconName: "zl.rectangle.roundedtop.fill")
case .rightTrigger:
return ButtonConfiguration(iconName: "zr.rectangle.roundedtop.fill")
case .leftShoulder:
return ButtonConfiguration(iconName: "l.rectangle.roundedbottom.fill")
case .rightShoulder:
return ButtonConfiguration(iconName: "r.rectangle.roundedbottom.fill")
case .start:
return ButtonConfiguration(iconName: "plus.circle.fill")
case .back:
return ButtonConfiguration(iconName: "minus.circle.fill")
case .guide:
return ButtonConfiguration(iconName: "house.circle.fill")
} }
} }

View file

@ -142,15 +142,6 @@ struct EmulationView: View {
// print(cool) // 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 .onChange(of: scenePhase) { newPhase in
// Detect when the app enters the background // Detect when the app enters the background

View file

@ -35,6 +35,7 @@ class InGameSettingsManager: PerGameSettingsManaging {
Ryujinx.shared.config = config[currentgame.titleId] Ryujinx.shared.config = config[currentgame.titleId]
let args = Ryujinx.shared.buildCommandLineArgs(from: config[currentgame.titleId] ?? Ryujinx.Arguments()) let args = Ryujinx.shared.buildCommandLineArgs(from: config[currentgame.titleId] ?? Ryujinx.Arguments())
// Convert Arguments to ones that Ryujinx can Read
let cArgs = args.map { strdup($0) } let cArgs = args.map { strdup($0) }
defer { cArgs.forEach { free($0) } } defer { cArgs.forEach { free($0) } }
var argvPtrs = cArgs var argvPtrs = cArgs

View file

@ -9,9 +9,9 @@ import MetalKit
import UIKit import UIKit
class MeloMTKView: MTKView { class MeloMTKView: MTKView {
private var activeTouches: [UITouch] = [] private var activeTouches: [UITouch] = []
private var ignoredTouches: Set<UITouch> = [] private var ignoredTouches: Set<UITouch> = []
private var touchIndexMap: [UITouch: Int] = [:]
private let baseWidth: CGFloat = 1280 private let baseWidth: CGFloat = 1280
private let baseHeight: CGFloat = 720 private let baseHeight: CGFloat = 720
@ -84,65 +84,51 @@ class MeloMTKView: MTKView {
return CGPoint(x: scaledX, y: scaledY) return CGPoint(x: scaledX, y: scaledY)
} }
private func getNextAvailableIndex() -> Int {
for i in 0..<Int.max {
if !touchIndexMap.values.contains(i) {
return i
}
}
return 0
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
let disabled = UserDefaults.standard.bool(forKey: "disableTouch") let disabled = UserDefaults.standard.bool(forKey: "disableTouch")
guard !disabled else { return }
setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9) setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9)
if !disabled {
for touch in touches { for touch in touches {
let location = touch.location(in: self) let location = touch.location(in: self)
guard let scaledLocation = scaleToTargetResolution(location) else { if scaleToTargetResolution(location) == nil {
ignoredTouches.insert(touch) ignoredTouches.insert(touch)
continue continue
} }
let index = getNextAvailableIndex()
touchIndexMap[touch] = index
activeTouches.append(touch) 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)) touch_began(Float(scaledLocation.x), Float(scaledLocation.y), Int32(index))
} }
} }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event) super.touchesEnded(touches, with: event)
let disabled = UserDefaults.standard.bool(forKey: "disableTouch") let disabled = UserDefaults.standard.bool(forKey: "disableTouch")
guard !disabled else {
for touch in touches {
ignoredTouches.remove(touch)
if let index = activeTouches.firstIndex(of: touch) {
activeTouches.remove(at: index)
}
touchIndexMap.removeValue(forKey: touch)
}
return
}
setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9)
if !disabled {
for touch in touches { for touch in touches {
if ignoredTouches.remove(touch) != nil { if ignoredTouches.contains(touch) {
ignoredTouches.remove(touch)
continue continue
} }
if let touchIndex = touchIndexMap[touch] { if let index = activeTouches.firstIndex(of: touch) {
touch_ended(Int32(touchIndex)) activeTouches.remove(at: index)
if let arrayIndex = activeTouches.firstIndex(of: touch) { // // print("Touch ended for index \(index)")
activeTouches.remove(at: arrayIndex) touch_ended(Int32(index))
} }
touchIndexMap.removeValue(forKey: touch)
} }
} }
} }
@ -151,45 +137,30 @@ class MeloMTKView: MTKView {
super.touchesMoved(touches, with: event) super.touchesMoved(touches, with: event)
let disabled = UserDefaults.standard.bool(forKey: "disableTouch") let disabled = UserDefaults.standard.bool(forKey: "disableTouch")
guard !disabled else { return }
setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9) setAspectRatio(Ryujinx.shared.config?.aspectRatio ?? .fixed16x9)
if !disabled {
for touch in touches { for touch in touches {
if ignoredTouches.contains(touch) { if ignoredTouches.contains(touch) {
continue continue
} }
guard let touchIndex = touchIndexMap[touch] else {
continue
}
let location = touch.location(in: self) let location = touch.location(in: self)
guard let scaledLocation = scaleToTargetResolution(location) else { guard let scaledLocation = scaleToTargetResolution(location) else {
touch_ended(Int32(touchIndex)) if let index = activeTouches.firstIndex(of: touch) {
activeTouches.remove(at: index)
if let arrayIndex = activeTouches.firstIndex(of: touch) { // // print("Touch left active area, removed index \(index)")
activeTouches.remove(at: arrayIndex) touch_ended(Int32(index))
} }
touchIndexMap.removeValue(forKey: touch)
ignoredTouches.insert(touch)
continue continue
} }
touch_moved(Float(scaledLocation.x), Float(scaledLocation.y), Int32(touchIndex)) if let index = activeTouches.firstIndex(of: touch) {
// // print("Touch moved to: \(scaledLocation)")
touch_moved(Float(scaledLocation.x), Float(scaledLocation.y), Int32(index))
} }
} }
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
touchesEnded(touches, with: event)
} }
func resetTouchTracking() {
activeTouches.removeAll()
ignoredTouches.removeAll()
touchIndexMap.removeAll()
} }
} }

View file

@ -81,6 +81,8 @@ struct ContentView: View {
_settings = State(initialValue: defaultSettings) _settings = State(initialValue: defaultSettings)
// print(SDL_CONTROLLER_BUTTON_LEFTSTICK.rawValue)
initializeSDL() initializeSDL()
} }
@ -130,6 +132,7 @@ struct ContentView: View {
JITPopover() { JITPopover() {
ryujinx.jitenabled = false ryujinx.jitenabled = false
} }
// .interactiveDismissDisabled()
} }
} }
@ -150,8 +153,11 @@ struct ContentView: View {
refreshControllersList() refreshControllersList()
} }
UserDefaults.standard.set(false, forKey: "lockInApp") UserDefaults.standard.set(false, forKey: "lockInApp")
// print(MTLHud.shared.isEnabled)
initControllerObservers() initControllerObservers()
Air.play(AnyView( Air.play(AnyView(
@ -160,6 +166,7 @@ struct ContentView: View {
refreshControllersList() refreshControllersList()
ryujinx.addGames() ryujinx.addGames()
checkJitStatus() checkJitStatus()
@ -280,6 +287,7 @@ struct ContentView: View {
queue: .main queue: .main
) { notification in ) { notification in
if let controller = notification.object as? GCController { if let controller = notification.object as? GCController {
// print("Controller connected: \(controller.productCategory)")
nativeControllers[controller] = .init(controller) nativeControllers[controller] = .init(controller)
refreshControllersList() refreshControllersList()
} }
@ -291,8 +299,7 @@ struct ContentView: View {
queue: .main queue: .main
) { notification in ) { notification in
if let controller = notification.object as? GCController { if let controller = notification.object as? GCController {
currentControllers = [] // print("Controller disconnected: \(controller.productCategory)")
controllersList = []
nativeControllers[controller]?.cleanup() nativeControllers[controller]?.cleanup()
nativeControllers[controller] = nil nativeControllers[controller] = nil
refreshControllersList() refreshControllersList()
@ -309,9 +316,6 @@ struct ContentView: View {
} }
private func refreshControllersList() { private func refreshControllersList() {
currentControllers = []
controllersList = []
controllersList = ryujinx.getConnectedControllers() controllersList = ryujinx.getConnectedControllers()
if let onscreen = controllersList.first(where: { $0.name == ryujinx.virtualController.controllername }) { if let onscreen = controllersList.first(where: { $0.name == ryujinx.virtualController.controllername }) {
@ -321,6 +325,8 @@ struct ContentView: View {
controllersList.removeAll(where: { $0.id == "0" || (!$0.name.starts(with: "GC - ") && $0 != onscreencontroller) }) controllersList.removeAll(where: { $0.id == "0" || (!$0.name.starts(with: "GC - ") && $0 != onscreencontroller) })
controllersList.mutableForEach { $0.name = $0.name.replacingOccurrences(of: "GC - ", with: "") } controllersList.mutableForEach { $0.name = $0.name.replacingOccurrences(of: "GC - ", with: "") }
currentControllers = []
if controllersList.count == 1 { if controllersList.count == 1 {
currentControllers.append(controllersList[0]) currentControllers.append(controllersList[0])
} else if (controllersList.count - 1) >= 1 { } else if (controllersList.count - 1) >= 1 {

View file

@ -1252,16 +1252,3 @@ 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()
}

View file

@ -1129,6 +1129,9 @@ struct SettingsViewNew: View {
Divider() Divider()
SettingsToggle(isOn: config.backendMultithreading, icon: "inset.filled.rectangle.and.person.filled", label: "Backend Multithreading")
Divider()
if MTLHud.shared.canMetalHud { if MTLHud.shared.canMetalHud {
SettingsToggle(isOn: $metalHudEnabler.metalHudEnabled, icon: "speedometer", label: "Metal Performance HUD") SettingsToggle(isOn: $metalHudEnabler.metalHudEnabled, icon: "speedometer", label: "Metal Performance HUD")

View file

@ -10,7 +10,7 @@
</data> </data>
<key>Info.plist</key> <key>Info.plist</key>
<data> <data>
GYWZONTCP5su4yOAk0d5jCd2K88= RTwvCLsTMs+YfZ9ZeF25QYe7/LE=
</data> </data>
<key>Modules/module.modulemap</key> <key>Modules/module.modulemap</key>
<data> <data>

View file

@ -699,21 +699,13 @@ namespace Ryujinx.Graphics.Vulkan
if (_dirty.HasFlag(DirtyFlags.Texture)) if (_dirty.HasFlag(DirtyFlags.Texture))
{ {
if (true) if (false)
{
try
{
UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
}
catch (Exception e)
{ {
UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp); UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp);
} }
}
else else
{ {
try try {
{
UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp); UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
} }
catch (Exception e) catch (Exception e)
@ -764,7 +756,7 @@ namespace Ryujinx.Graphics.Vulkan
if (info.Buffer.Handle == 0) if (info.Buffer.Handle == 0)
{ {
info.Buffer = dummyBuffer?.Get(cbs).Value ?? default; info.Buffer = dummyBuffer?.Get(cbs).Value ?? default;
// info.Offset = 0; info.Offset = 0;
info.Range = Vk.WholeSize; info.Range = Vk.WholeSize;
} }
@ -799,13 +791,6 @@ 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]; DescriptorSetTemplate template = program.Templates[setIndex];
DescriptorSetTemplateWriter tu = _templateUpdater.Begin(template); DescriptorSetTemplateWriter tu = _templateUpdater.Begin(template);
@ -879,12 +864,12 @@ namespace Ryujinx.Graphics.Vulkan
if (texture.ImageView.Handle == 0) if (texture.ImageView.Handle == 0)
{ {
texture.ImageView = dummyImageInfo.ImageView; texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
} }
if (texture.Sampler.Handle == 0) if (texture.Sampler.Handle == 0)
{ {
texture.Sampler = dummyImageInfo.Sampler; texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
} }
} }
@ -924,7 +909,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? dummyImageInfo.ImageView; images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
} }
tu.Push<DescriptorImageInfo>(images[..count]); tu.Push<DescriptorImageInfo>(images[..count]);
@ -961,25 +946,23 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty); _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp) private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
{ {
int setIndex = PipelineBase.TextureSetIndex; int setIndex = PipelineBase.TextureSetIndex;
var bindingSegments = program.BindingSegments[setIndex]; ResourceBindingSegment[] bindingSegments = program.BindingSegments[setIndex];
if (bindingSegments.Length == 0) if (bindingSegments.Length == 0)
{ {
return; return;
} }
var dummyImageInfo = new DescriptorImageInfo if (_updateDescriptorCacheCbIndex)
{ {
ImageView = _dummyTexture.GetImageView().Get(cbs).Value, _updateDescriptorCacheCbIndex = false;
Sampler = _dummySampler.GetSampler().Get(cbs).Value, program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
ImageLayout = ImageLayout.General }
};
var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs); DescriptorSetCollection dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
foreach (ResourceBindingSegment segment in bindingSegments) foreach (ResourceBindingSegment segment in bindingSegments)
{ {
@ -990,78 +973,56 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (segment.Type != ResourceType.BufferTexture) if (segment.Type != ResourceType.BufferTexture)
{ {
Span<DescriptorImageInfo> textures = _textures;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
int index = binding + i; ref DescriptorImageInfo texture = ref textures[i];
ref var textureRef = ref _textureRefs[index]; ref TextureRef refs = ref _textureRefs[binding + i];
var imageView = textureRef.ImageView?.Get(cbs).Value ?? dummyImageInfo.ImageView; texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
var sampler = textureRef.Sampler?.Get(cbs).Value ?? dummyImageInfo.Sampler; texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
var imageInfo = new DescriptorImageInfo if (texture.ImageView.Handle == 0)
{ {
ImageView = imageView.Handle != 0 ? imageView : dummyImageInfo.ImageView, texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
Sampler = sampler.Handle != 0 ? sampler : dummyImageInfo.Sampler, }
ImageLayout = ImageLayout.General
};
dsc.UpdateImages(0, index, new[] { imageInfo }, DescriptorType.CombinedImageSampler); if (texture.Sampler.Handle == 0)
{
texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
}
}
dsc.UpdateImages(0, binding, textures[..count], DescriptorType.CombinedImageSampler);
}
else
{
Span<BufferView> bufferTextures = _bufferTextures;
for (int i = 0; i < count; i++)
{
bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
}
dsc.UpdateBufferImages(0, binding, bufferTextures[..count], DescriptorType.UniformTexelBuffer);
} }
} }
else else
{ {
for (int i = 0; i < count; i++)
{
int index = binding + i;
var bufferView = _bufferTextureRefs[index]?.GetBufferView(cbs, false) ?? default;
dsc.UpdateBufferImages(0, index, new[] { bufferView }, DescriptorType.UniformTexelBuffer);
}
}
}
else
{
var arrayRef = _textureArrayRefs[binding];
if (segment.Type != ResourceType.BufferTexture) if (segment.Type != ResourceType.BufferTexture)
{ {
var imageInfos = arrayRef.Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler); dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler);
if (imageInfos != null)
{
for (int i = 0; i < imageInfos.Length && i < count; i++)
{
dsc.UpdateImages(0, binding + i, new[] { imageInfos[i] }, DescriptorType.CombinedImageSampler);
}
} }
else else
{ {
for (int i = 0; i < count; i++) dsc.UpdateBufferImages(0, binding, _textureArrayRefs[binding].Array.GetBufferViews(cbs), DescriptorType.UniformTexelBuffer);
{
dsc.UpdateImages(0, binding + i, new[] { dummyImageInfo }, DescriptorType.CombinedImageSampler);
}
}
}
else
{
var bufferViews = arrayRef.Array.GetBufferViews(cbs);
if (bufferViews != null)
{
for (int i = 0; i < bufferViews.Length && i < count; i++)
{
dsc.UpdateBufferImages(0, binding + i, new[] { bufferViews[i] }, DescriptorType.UniformTexelBuffer);
}
}
else
{
for (int i = 0; i < count; i++)
{
dsc.UpdateBufferImages(0, binding + i, new[] { default(BufferView) }, DescriptorType.UniformTexelBuffer);
}
}
} }
} }
} }
var sets = dsc.GetSets(); DescriptorSet[] sets = dsc.GetSets();
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty); _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
} }

View file

@ -188,21 +188,15 @@ namespace Ryujinx.Graphics.Vulkan
var dsc = program.GetNewDescriptorSetCollection(setIndex, out var isNew).Get(cbs); var dsc = program.GetNewDescriptorSetCollection(setIndex, out var isNew).Get(cbs);
DescriptorSetTemplate template = program.Templates[setIndex];
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
if (!_isBuffer) if (!_isBuffer)
{ {
tu.Push(GetImageInfos(_gd, cbs, dummyTexture)); dsc.UpdateImages(0, 0, GetImageInfos(_gd, cbs, dummyTexture), DescriptorType.StorageImage);
} }
else else
{ {
tu.Push(GetBufferViews(cbs)); dsc.UpdateBufferImages(0, 0, GetBufferViews(cbs), DescriptorType.StorageTexelBuffer);
} }
templateUpdater.Commit(_gd, device, sets[0]);
sets = dsc.GetSets(); sets = dsc.GetSets();
return sets; return sets;

View file

@ -159,8 +159,8 @@ namespace Ryujinx.Graphics.Vulkan
} }
texture.ImageLayout = ImageLayout.General; texture.ImageLayout = ImageLayout.General;
texture.ImageView = refs.View?.Get(cbs).Value ?? dummyTexture.GetImageView().Get(cbs).Value; texture.ImageView = refs.View?.Get(cbs).Value ?? default;
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? dummySampler.GetSampler().Get(cbs).Value; texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
if (texture.ImageView.Handle == 0) if (texture.ImageView.Handle == 0)
{ {

View file

@ -647,14 +647,6 @@ namespace Ryujinx.Graphics.Vulkan
Format.Bc7Srgb, Format.Bc7Srgb,
Format.Bc7Unorm); Format.Bc7Unorm);
if (!OperatingSystem.IsIOSVersionAtLeast(16, 4))
{
// On iOS 16.3.1 and earlier, these formats are not supported.
supportsBc123CompressionFormat = false;
supportsBc45CompressionFormat = false;
supportsBc67CompressionFormat = false;
}
bool supportsEtc2CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags, bool supportsEtc2CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
Format.Etc2RgbaSrgb, Format.Etc2RgbaSrgb,
Format.Etc2RgbaUnorm, Format.Etc2RgbaUnorm,
@ -722,7 +714,7 @@ namespace Ryujinx.Graphics.Vulkan
SystemMemoryType memoryType; SystemMemoryType memoryType;
if (IsSharedMemory && !IsMoltenVk) if (IsSharedMemory)
{ {
memoryType = SystemMemoryType.UnifiedMemory; memoryType = SystemMemoryType.UnifiedMemory;
} }

View file

@ -1,14 +1,10 @@
using Ryujinx.Common; using Ryujinx.Common;
using System.Runtime.InteropServices;
using System; using System;
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
{ {
class ILibraryAppletSelfAccessor : IpcService class ILibraryAppletSelfAccessor : IpcService
{ {
[DllImport("RyujinxHelper.framework/RyujinxHelper", CallingConvention = CallingConvention.Cdecl)]
public static extern void TriggerCallback(string cIdentifier);
private readonly AppletStandalone _appletStandalone = new(); private readonly AppletStandalone _appletStandalone = new();
public ILibraryAppletSelfAccessor(ServiceCtx context) public ILibraryAppletSelfAccessor(ServiceCtx context)
@ -49,14 +45,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
return ResultCode.Success; return ResultCode.Success;
} }
[CommandCmif(1)]
public ResultCode PushOutData(ServiceCtx context)
{
TriggerCallback("exit-emulation");
return ResultCode.Success;
}
[CommandCmif(11)] [CommandCmif(11)]
// GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo // GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo
public ResultCode GetLibraryAppletInfo(ServiceCtx context) public ResultCode GetLibraryAppletInfo(ServiceCtx context)

View file

@ -11,11 +11,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
Data = data; Data = data;
} }
public byte[] GetData()
{
return Data;
}
[CommandCmif(0)] [CommandCmif(0)]
// Open() -> object<nn::am::service::IStorageAccessor> // Open() -> object<nn::am::service::IStorageAccessor>
public ResultCode Open(ServiceCtx context) public ResultCode Open(ServiceCtx context)