MeloNX/MeloNX-XC/MeloNX/ContentView.swift
2024-10-28 10:22:25 +11:00

119 lines
3.4 KiB
Swift

//
// ContentView.swift
// MeloNX
//
// Created by Stossy11 on 27/10/2024.
//
import SwiftUI
import SDL2
import GameController
var theWindow: UIWindow? = nil
struct ContentView: View {
@State var device: MTLDevice? = MTLCreateSystemDefaultDevice()
@State var gameUrl: URL?
@State var showFileImporter: Bool = false
@State var emulationStarted: Bool = false
var body: some View {
ZStack {
VStack {
Text("NX iOS")
Button {
showFileImporter.toggle()
} label: {
Text("Select Game")
}
if let gameUrl {
Button {
emulationStarted = true
gameUrl.startAccessingSecurityScopedResource()
showVirtualController(url: gameUrl)
} label: {
Text("Go!")
}
.padding(8)
}
}
}
.padding()
.fileImporter(isPresented: $showFileImporter, allowedContentTypes: [.item]) { result in
switch result {
case .success(let url):
gameUrl = url
case .failure(let err):
print(err.localizedDescription)
}
}
}
}
func startEmulation(game: URL) {
setenv("DOTNET_EnableDiagnostics", "0", 1)
setenv("HOME", String(validatingUTF8: getenv("HOME"))! + "/Documents", 1)
setenv("MVK_CONFIG_LOG_LEVEL", "4", 1)
let config = RyujinxEmulator.Configuration(
inputPath: game.path,
enableKeyboard: false,
graphicsBackend: "Vulkan"
)
patchMakeKeyAndVisible()
SDL_SetMainReady()
SDL_iPhoneSetEventPump(SDL_TRUE)
let emulator = RyujinxEmulator()
do {
try emulator.startWithRunLoop(config: config)
} catch {
print(error)
}
}
func patchMakeKeyAndVisible() {
let uiwindowClass = UIWindow.self
let m1 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.makeKeyAndVisible))!
let m2 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.wdb_makeKeyAndVisible))!
method_exchangeImplementations(m1, m2)
}
extension UIWindow {
@objc func wdb_makeKeyAndVisible() {
print("Making window key and visible...")
self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
self.wdb_makeKeyAndVisible()
theWindow = self
reconnectVirtualController()
}
}
@available(iOS 15.0, *)
var g_gcVirtualController: GCVirtualController!
@available(iOS 15.0, *)
func showVirtualController(url: URL) {
print("Showing virtual controller...")
let config = GCVirtualController.Configuration()
config.elements = [
GCInputDirectionalDpad, GCInputButtonA, GCInputButtonB, GCInputButtonX, GCInputButtonY,
]
g_gcVirtualController = GCVirtualController(configuration: config)
g_gcVirtualController.connect { err in
print("Controller connect: \(String(describing: err))")
startEmulation(game: url)
}
}
@available(iOS 15.0, *)
func reconnectVirtualController() {
print("Reconnecting virtual controller...")
g_gcVirtualController.disconnect()
DispatchQueue.main.async {
g_gcVirtualController.connect { err in
print("Reconnected: err \(String(describing: err))")
}
}
}