From 661e9ba114b23b6d568dd7f1ce586ea08caa7930 Mon Sep 17 00:00:00 2001 From: esiayo <41133734+vapidinfinity@users.noreply.github.com> Date: Wed, 15 Jan 2025 21:06:18 +0800 Subject: [PATCH] fix: annoying swiftui bug with nonfunctional copyItem method + light code refactoring --- Mythic.xcodeproj/project.pbxproj | 4 ++-- .../Extensions/Built-in/FileManager.swift | 20 ++++++++++++++++ .../Extensions/Built-in/Process.swift | 24 ++++++++++++------- Mythic/Utilities/Game.swift | 2 +- Mythic/Utilities/Wine/WineInterface.swift | 8 +++---- .../Sheets/ContainerSettingsView.swift | 12 ++++++---- 6 files changed, 49 insertions(+), 21 deletions(-) diff --git a/Mythic.xcodeproj/project.pbxproj b/Mythic.xcodeproj/project.pbxproj index 3a88aba..59b5667 100644 --- a/Mythic.xcodeproj/project.pbxproj +++ b/Mythic.xcodeproj/project.pbxproj @@ -805,7 +805,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3278; + CURRENT_PROJECT_VERSION = 3290; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"Mythic/Preview Content\""; @@ -852,7 +852,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 3278; + CURRENT_PROJECT_VERSION = 3290; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = "\"Mythic/Preview Content\""; diff --git a/Mythic/Utilities/Extensions/Built-in/FileManager.swift b/Mythic/Utilities/Extensions/Built-in/FileManager.swift index 7c2db9c..737384d 100644 --- a/Mythic/Utilities/Extensions/Built-in/FileManager.swift +++ b/Mythic/Utilities/Extensions/Built-in/FileManager.swift @@ -13,4 +13,24 @@ extension FileManager { try files.removeItem(at: url) } } + + func forceCopyItem(at sourceURL: URL, to destinationURL: URL) throws { + let (stderr, _) = try Process.execute( + executableURL: .init(filePath: "/bin/cp"), + arguments: [ + "-f", + sourceURL.path(percentEncoded: false), + destinationURL.path(percentEncoded: false) + ] + ) + + if !stderr.isEmpty { + throw ForceCopyFailedError() + } + } + + /// An error indicating that force-copying files has failed. + struct ForceCopyFailedError: LocalizedError { + var errorDescription: String? = "Failed to force-copy files." + } } diff --git a/Mythic/Utilities/Extensions/Built-in/Process.swift b/Mythic/Utilities/Extensions/Built-in/Process.swift index f3ee766..a1fa00e 100644 --- a/Mythic/Utilities/Extensions/Built-in/Process.swift +++ b/Mythic/Utilities/Extensions/Built-in/Process.swift @@ -18,21 +18,27 @@ import Foundation import OSLog extension Process { - static func execute(executableURL: URL, arguments: [String]) throws -> String { + static func execute(executableURL: URL, arguments: [String]) throws -> (stderr: String, stdout: String) { let process = Process() process.executableURL = executableURL process.arguments = arguments - - let pipe = Pipe() - process.standardOutput = pipe - + + let stderr = Pipe() + let stdout = Pipe() + + process.standardError = stderr + process.standardOutput = stdout + try? process.run() process.waitUntilExit() - let data = pipe.fileHandleForReading.readDataToEndOfFile() - let output = String(decoding: data, as: UTF8.self) - - return output.trimmingCharacters(in: .whitespacesAndNewlines) + let stdoutData = stdout.fileHandleForReading.readDataToEndOfFile() + let stderrData = stderr.fileHandleForReading.readDataToEndOfFile() + + let stderrOutput = String(decoding: stderrData, as: UTF8.self) + let stdoutOutput = String(decoding: stdoutData, as: UTF8.self) + + return (stderr: stderrOutput, stdout: stdoutOutput) } static func executeAsync(executableURL: URL, arguments: [String], completion: @escaping (CommandOutput) -> Void) async throws { diff --git a/Mythic/Utilities/Game.swift b/Mythic/Utilities/Game.swift index aa3e5ce..4c40960 100644 --- a/Mythic/Utilities/Game.swift +++ b/Mythic/Utilities/Game.swift @@ -369,7 +369,7 @@ class GameOperation: ObservableObject { case .macOS: workspace.runningApplications.contains(where: { $0.bundleURL?.path == gamePath }) // debounce may be necessary because macOS is slow at opening apps case .windows: - (try? Process.execute(executableURL: .init(fileURLWithPath: "/bin/bash"), arguments: ["-c", "ps aux | grep -i '\(gamePath)' | grep -v grep"]))?.isEmpty == false + (try? Process.execute(executableURL: .init(fileURLWithPath: "/bin/bash"), arguments: ["-c", "ps aux | grep -i '\(gamePath)' | grep -v grep"]))?.stdout.isEmpty == false } }() diff --git a/Mythic/Utilities/Wine/WineInterface.swift b/Mythic/Utilities/Wine/WineInterface.swift index 91ad256..9cacf2c 100644 --- a/Mythic/Utilities/Wine/WineInterface.swift +++ b/Mythic/Utilities/Wine/WineInterface.swift @@ -288,20 +288,20 @@ final class Wine { // TODO: https://forum.winehq.org/viewtopic.php?t=15416 } // MARK: - Kill All Method - static func killAll(containerURL: URL? = nil) throws { + static func killAll(containerURLs urls: [URL] = .init()) throws { let task = Process() task.executableURL = Engine.directory.appending(path: "wine/bin/wineserver") task.arguments = ["-k"] - let urls: [URL] = containerURL.map { [$0] } ?? .init(containerURLs) - + let urls: [URL] = urls.isEmpty ? .init(containerURLs) : urls + for url in urls { task.environment = ["WINEPREFIX": url.path(percentEncoded: false)] task.qualityOfService = .utility try task.run() } } - + // MARK: - Clear Shader Cache Method static func purgeShaderCache(game: Game? = nil) -> Bool { let task = Process() diff --git a/Mythic/Views/Unified/Sheets/ContainerSettingsView.swift b/Mythic/Views/Unified/Sheets/ContainerSettingsView.swift index 32a5fa0..22fc65d 100644 --- a/Mythic/Views/Unified/Sheets/ContainerSettingsView.swift +++ b/Mythic/Views/Unified/Sheets/ContainerSettingsView.swift @@ -165,6 +165,8 @@ struct ContainerSettingsView: View { do { withAnimation { modifyingDXVK = true } + try Wine.killAll(containerURLs: [container.url]) + // x64 try files.removeItemIfExists(at: container.url.appending(path: "drive_c/windows/system32/d3d10core.dll")) try files.removeItemIfExists(at: container.url.appending(path: "drive_c/windows/system32/d3d11.dll")) @@ -182,21 +184,21 @@ struct ContainerSettingsView: View { ) } else { // x64 - try files.copyItem( + try files.forceCopyItem( at: Engine.directory.appending(path: "DXVK/x64/d3d10core.dll"), to: container.url.appending(path: "drive_c/windows/system32") ) - try files.copyItem( + try files.forceCopyItem( at: Engine.directory.appending(path: "DXVK/x64/d3d11.dll"), to: container.url.appending(path: "drive_c/windows/system32") ) // x32 - try files.copyItem( + try files.forceCopyItem( at: Engine.directory.appending(path: "DXVK/x32/d3d10core.dll"), to: container.url.appending(path: "drive_c/windows/syswow64") ) - try files.copyItem( + try files.forceCopyItem( at: Engine.directory.appending(path: "DXVK/x32/d3d11.dll"), to: container.url.appending(path: "drive_c/windows/syswow64") ) @@ -232,7 +234,7 @@ struct ContainerSettingsView: View { get: { container.settings.dxvkAsync }, set: { container.settings.dxvkAsync = $0 } )) - .disabled(!container.settings.dxvk) + .disabled(!container.settings.dxvk || modifyingDXVK) if !modifyingWindowsVersion, windowsVersionError == nil { Picker("Windows Version", selection: Binding(