Add Config Editor

This commit is contained in:
Stossy11 2024-11-25 09:49:10 +11:00
parent 098467f3f3
commit e02927cadb
5 changed files with 235 additions and 59 deletions

View File

@ -23,7 +23,7 @@
<BreakpointActionProxy <BreakpointActionProxy
ActionExtensionID = "Xcode.BreakpointAction.DebuggerCommand"> ActionExtensionID = "Xcode.BreakpointAction.DebuggerCommand">
<ActionContent <ActionContent
consoleCommand = "process handle --stop false SIGUSR1"> consoleCommand = "process handle -s false -n false">
</ActionContent> </ActionContent>
</BreakpointActionProxy> </BreakpointActionProxy>
</Actions> </Actions>
@ -45,5 +45,30 @@
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "900AC928-2B0F-4BBE-A47D-D6B17570E9BB"
shouldBeEnabled = "Yes"
nameForDebugger = "SIGUSR1-Disable"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "MeloNX/Views/ContentView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "131"
endingLineNumber = "131"
landmarkName = "start(displayid:)"
landmarkType = "7">
<Actions>
<BreakpointActionProxy
ActionExtensionID = "Xcode.BreakpointAction.DebuggerCommand">
<ActionContent
consoleCommand = "process handle --stop false SIGUSR1">
</ActionContent>
</BreakpointActionProxy>
</Actions>
</BreakpointContent>
</BreakpointProxy>
</Breakpoints> </Breakpoints>
</Bucket> </Bucket>

View File

@ -20,25 +20,48 @@ class Ryujinx {
@Published var controllerMap: [Controller] = [] @Published var controllerMap: [Controller] = []
public struct Configuration { public struct Configuration : Codable {
let gamepath: String var gamepath: String
let inputids: [String] var inputids: [String]
let debuglogs: Bool var debuglogs: Bool
let tracelogs: Bool var tracelogs: Bool
let listinputids: Bool var listinputids: Bool
let fullscreen: Bool var fullscreen: Bool
var hostMappedMemory: Bool
var disableVSync: Bool
var disableShaderCache: Bool
var disableDockedMode: Bool
var enableTextureRecompression: Bool
var additionalArgs: [String] var additionalArgs: [String]
init(gamepath: String, additionalArgs: [String] = [], debuglogs: Bool = false, tracelogs: Bool = false, listinputids: Bool = false, inputids: [String] = [], ryufullscreen: Bool = false) { init(gamepath: String,
inputids: [String] = [],
debuglogs: Bool = false,
tracelogs: Bool = false,
listinputids: Bool = false,
fullscreen: Bool = false,
hostMappedMemory: Bool = false,
disableVSync: Bool = true,
disableShaderCache: Bool = false,
disableDockedMode: Bool = true,
enableTextureRecompression: Bool = true,
additionalArgs: [String] = []) {
self.gamepath = gamepath self.gamepath = gamepath
self.inputids = inputids
self.debuglogs = debuglogs self.debuglogs = debuglogs
self.tracelogs = tracelogs self.tracelogs = tracelogs
self.inputids = inputids
self.listinputids = listinputids self.listinputids = listinputids
self.fullscreen = ryufullscreen self.fullscreen = fullscreen
self.disableVSync = disableVSync
self.disableShaderCache = disableShaderCache
self.disableDockedMode = disableDockedMode
self.enableTextureRecompression = enableTextureRecompression
self.additionalArgs = additionalArgs self.additionalArgs = additionalArgs
self.hostMappedMemory = hostMappedMemory
} }
} }
func start(with config: Configuration) throws { func start(with config: Configuration) throws {
guard !isRunning else { guard !isRunning else {
@ -94,25 +117,36 @@ class Ryujinx {
args.append("Vulkan") args.append("Vulkan")
// Fixes the Stubs.DispatchLoop Crash // Fixes the Stubs.DispatchLoop Crash
// args.append(contentsOf: ["--memory-manager-mode", "HostMapped"]) if config.hostMappedMemory {
args.append(contentsOf: ["--memory-manager-mode", "SoftwarePageTable"]) args.append(contentsOf: ["--memory-manager-mode", "HostMapped"])
} else {
args.append(contentsOf: ["--memory-manager-mode", "SoftwarePageTable"])
}
if config.fullscreen { if config.fullscreen {
// args.append(contentsOf: ["--fullscreen", String(config.fullscreen)])
args.append(contentsOf: ["--exclusive-fullscreen", String(config.fullscreen)]) args.append(contentsOf: ["--exclusive-fullscreen", String(config.fullscreen)])
args.append(contentsOf: ["--exclusive-fullscreen-width", "1280"]) args.append(contentsOf: ["--exclusive-fullscreen-width", "1280"])
args.append(contentsOf: ["--exclusive-fullscreen-height", "720"]) args.append(contentsOf: ["--exclusive-fullscreen-height", "720"])
// exclusive-fullscreen
} }
args.append(contentsOf: ["--disable-vsync", "true"]) // ios already forces vsync
args.append(contentsOf: ["--disable-shader-cache", "false"]) // Adding default args directly into additionalArgs
args.append(contentsOf: ["--disable-docked-mode", "true"]) if config.disableVSync {
args.append(contentsOf: ["--enable-texture-recompression", "true"]) args.append("--disable-vsync")
}
if config.disableShaderCache {
args.append("--disable-shader-cache")
}
if config.disableDockedMode {
args.append("--disable-docked-mode")
}
if config.enableTextureRecompression {
args.append("--enable-texture-recompression")
}
if config.debuglogs { if config.debuglogs {
args.append(contentsOf: ["--enable-debug-logs", String(config.debuglogs)]) args.append(contentsOf: ["--enable-debug-logs"])
} }
if config.tracelogs { if config.tracelogs {
args.append(contentsOf: ["--enable-trace-logs", String(config.tracelogs)]) args.append(contentsOf: ["--enable-trace-logs"])
} }
// List the input ids // List the input ids

View File

@ -20,6 +20,7 @@ struct ContentView: View {
@State var game: URL? = nil @State var game: URL? = nil
@State var controllersList: [Controller] = [] @State var controllersList: [Controller] = []
@State var currentControllers: [Controller] = [] @State var currentControllers: [Controller] = []
@State var config: Ryujinx.Configuration = Ryujinx.Configuration(gamepath: "")
@State private var settings: [MoltenVKSettings] = [ @State private var settings: [MoltenVKSettings] = [
MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0"), MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "0"),
@ -77,26 +78,35 @@ struct ContentView: View {
} }
List { List {
Button { Section("Settings") {
controllersList = Ryujinx().getConnectedControllers() NavigationLink {
controllersList.removeAll(where: { $0.id == "0" }) SettingsView(config: $config)
} label: { } label: {
Text("Refresh") Text("Config")
}
} }
ForEach(controllersList, id: \.self) { controller in Section("Controller") {
HStack { Button {
Button { controllersList = Ryujinx().getConnectedControllers()
if currentControllers.contains(where: { $0.id == controller.id }) { controllersList.removeAll(where: { $0.id == "0" })
currentControllers.removeAll(where: { $0.id == controller.id }) } label: {
} else { Text("Refresh")
currentControllers.append(controller) }
ForEach(controllersList, id: \.self) { controller in
HStack {
Button {
if currentControllers.contains(where: { $0.id == controller.id }) {
currentControllers.removeAll(where: { $0.id == controller.id })
} else {
currentControllers.append(controller)
}
} label: {
Text(controller.name)
}
Spacer()
if currentControllers.contains(where: { $0.id == controller.id }) {
Image(systemName: "checkmark.circle.fill")
} }
} label: {
Text(controller.name)
}
Spacer()
if currentControllers.contains(where: { $0.id == controller.id }) {
Image(systemName: "checkmark.circle.fill")
} }
} }
} }
@ -109,30 +119,41 @@ struct ContentView: View {
func start(displayid: UInt32) { func start(displayid: UInt32) {
let config = Ryujinx.Configuration( if let game {
gamepath: game!.path, self.config.gamepath = game.path
additionalArgs: [
// "--display-id", String(displayid)
],
debuglogs: false,
tracelogs: false,
listinputids: false,
inputids: currentControllers.map(\.id),// "1-dc180005-045e-0000-130b-0000ff870001"], // "2-1fd70005-057e-0000-0920-0000ff870000"],
ryufullscreen: true
) allocateSixGB()
// Start the emulation
do {
setupVirtualController()
try Ryujinx().start(with: config) // Start the emulation
do {
setupVirtualController()
try Ryujinx().start(with: config)
} catch {
print("Error \(error.localizedDescription)")
}
} else {
} catch {
print("Error \(error.localizedDescription)")
} }
}
func allocateSixGB() -> UnsafeMutableRawPointer? {
let physicalMemory = ProcessInfo.processInfo.physicalMemory
let totalMemoryInGB = Double(physicalMemory) / (1024 * 1024 * 1024)
let mem = totalMemoryInGB - 1
print(mem)
// Allocate memory
let pointer = UnsafeMutableRawPointer.allocate(byteCount: Int(mem), alignment: MemoryLayout<UInt8>.alignment)
// Optionally initialize the memory
pointer.initializeMemory(as: UInt8.self, repeating: 0, count: Int(mem))
print("Successfully allocated 6GB of memory.")
return pointer
} }
func patchMakeKeyAndVisible() { func patchMakeKeyAndVisible() {
@ -145,10 +166,32 @@ struct ContentView: View {
private func setMoltenVKSettings() { private func setMoltenVKSettings() {
if let configs = loadSettings() {
self.config = configs
print(configs)
}
settings.forEach { setting in settings.forEach { setting in
setenv(setting.string, setting.value, 1) setenv(setting.string, setting.value, 1)
} }
} }
}
func loadSettings() -> Ryujinx.Configuration? {
guard let jsonString = UserDefaults.standard.string(forKey: "config") else {
return nil
}
do {
let decoder = JSONDecoder()
if let data = jsonString.data(using: .utf8) {
return try decoder.decode(Ryujinx.Configuration.self, from: data)
}
} catch {
print("Failed to load settings: \(error)")
}
return nil
} }
extension UIWindow { extension UIWindow {

View File

@ -0,0 +1,74 @@
//
// SettingsView.swift
// MeloNX
//
// Created by Stossy11 on 25/11/2024.
//
import SwiftUI
struct SettingsView: View {
@Binding var config: Ryujinx.Configuration
var body: some View {
Form {
Section(header: Text("Graphics and Performance")) {
Toggle("Fullscreen", isOn: $config.fullscreen)
Toggle("Disable V-Sync", isOn: $config.disableVSync)
Toggle("Disable Shader Cache", isOn: $config.disableShaderCache)
Toggle("Enable Texture Recompression", isOn: $config.enableTextureRecompression)
}
Section(header: Text("Input Settings")) {
Toggle("List Input IDs", isOn: $config.listinputids)
Toggle("Host Mapped Memory", isOn: $config.hostMappedMemory)
Toggle("Disable Docked Mode", isOn: $config.disableDockedMode)
}
Section(header: Text("Logging Settings")) {
Toggle("Enable Debug Logs", isOn: $config.debuglogs)
Toggle("Enable Trace Logs", isOn: $config.tracelogs)
}
Section(header: Text("Game Settings")) {
//TextField("Game Path", text: $config.gamepath)
TextField("Additional Arguments", text: Binding(
get: {
config.additionalArgs.joined(separator: ", ")
},
set: { newValue in
config.additionalArgs = newValue.split(separator: ",").map { String($0).trimmingCharacters(in: .whitespaces) }
}
))
}
}
.onAppear {
if let configs = loadSettings() {
self.config = configs
print(configs)
}
}
.navigationTitle("Settings")
.navigationBarItems(trailing: Button("Save") {
saveSettings()
})
}
func saveSettings() {
do {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // Optional: Makes the JSON easier to read
let data = try encoder.encode(config)
let jsonString = String(data: data, encoding: .utf8)
// Save to UserDefaults
UserDefaults.standard.set(jsonString, forKey: "config")
print("Settings saved successfully!")
} catch {
print("Failed to save settings: \(error)")
}
}
}