Skip to content

Commit

Permalink
Commit dump + fix legendary signin crash
Browse files Browse the repository at this point in the history
  • Loading branch information
vapidinfinity committed Apr 23, 2024
1 parent 6dc69fd commit 0dfaf12
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 35 deletions.
4 changes: 2 additions & 2 deletions Mythic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2582;
CURRENT_PROJECT_VERSION = 2599;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"Mythic/Preview Content\"";
DEVELOPMENT_TEAM = 67ZBY275P8;
Expand Down Expand Up @@ -904,7 +904,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2582;
CURRENT_PROJECT_VERSION = 2599;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"Mythic/Preview Content\"";
DEVELOPMENT_TEAM = 67ZBY275P8;
Expand Down
11 changes: 9 additions & 2 deletions Mythic/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ class AppDelegate: NSObject, NSApplicationDelegate { // https://arc.net/l/quote/
)
} catch {
Logger.file.error("Unable to move Mythic to Applications: \(error)")

let error = NSAlert()
error.messageText = "Unable to move Mythic to \"\(globalApps.prettyPath())\"."
error.addButton(withTitle: "Quit")

if error.runModal() == .alertFirstButtonReturn {
exit(1)
}
}
}
}
Expand Down Expand Up @@ -109,8 +117,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { // https://arc.net/l/quote/

func applicationWillTerminate(_: Notification) {
if defaults.bool(forKey: "quitOnAppClose") { Wine.killAll() }
// TODO: stop download alert if downloading before closure
Legendary.stopAllCommands()
Legendary.stopAllCommands(forced: true)
}
}

Expand Down
21 changes: 21 additions & 0 deletions Mythic/Assets.xcassets/EvilSteam.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "t.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Binary file added Mythic/Assets.xcassets/EvilSteam.imageset/t.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 29 additions & 22 deletions Mythic/Controllers/Legendary/LegendaryInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ class Legendary {
Executes Legendary's command-line process with the specified arguments and handles its output and input interactions.

- Parameters:
- args: The arguments to pass to the command-line process.
- waits: Indicates whether the function should wait for the command-line process to complete before returning.
- identifier: A unique identifier for the command-line process.
- input: A closure that processes the output of the command-line process and provides input back to it.
- environment: Additional environment variables to set for the command-line process.
- completion: A closure to call with the output of the command-line process.
- args: The arguments to pass to the command-line process.
- waits: Indicates whether the function should wait for the command-line process to complete before returning.
- identifier: A unique identifier for the command-line process.
- input: A closure that processes the output of the command-line process and provides input back to it.
- environment: Additional environment variables to set for the command-line process.
- completion: A closure to call with the output of the command-line process.

- Throws: An error if the command-line process encounters an issue.

Expand Down Expand Up @@ -105,7 +105,7 @@ class Legendary {
stdin.fileHandleForWriting.write(data)
}
output.stderr = availableOutput
completion(output, task)
completion(output, task) // ⚠️ FIXME: critical performance issues
}

stdout.fileHandleForReading.readabilityHandler = { [stdin, output] handle in
Expand All @@ -115,7 +115,7 @@ class Legendary {
stdin.fileHandleForWriting.write(data)
}
output.stdout = availableOutput
completion(output, task)
completion(output, task) // ⚠️ FIXME: critical performance issues
}

task.terminationHandler = { [stdin] _ in
Expand Down Expand Up @@ -147,30 +147,34 @@ class Legendary {

- Parameter identifier: The unique identifier of the command to be stopped.
*/
static func stopCommand(identifier: String) { // TODO: pause and replay downloads using task.suspend() and task.resume()
static func stopCommand(identifier: String, forced: Bool = false) { // TODO: pause and replay downloads using task.suspend() and task.resume()
if let task = runningCommands[identifier] {
task.interrupt() // SIGTERM
if forced {
task.interrupt() // SIGTERM
} else {
task.terminate() // SIGKILL
}
runningCommands.removeValue(forKey: identifier)
} else {
log.error("Unable to stop Legendary command: Bad identifier.")
}
}

/// Stops the execution of all commands.
static func stopAllCommands() { runningCommands.keys.forEach { stopCommand(identifier: $0) } }
static func stopAllCommands(forced: Bool) { runningCommands.keys.forEach { stopCommand(identifier: $0, forced: forced) } }

// MARK: Install Method
/**
Installs, updates, or repairs games using legendary.

- Parameters:
- game: The game's `app_name`. (referred to as id)
- platform: The game's platform.
- type: The nature of the game modification.
- optionalPacks: Optional packs to install along with the base game.
- baseURL: A custom ``URL`` for the game to install to.
- gameFolder: The folder where the game should be installed.
- priority: Whether the game should interrupt the currently queued game installation.
- game: The game's `app_name`. (referred to as id)
- platform: The game's platform.
- type: The nature of the game modification.
- optionalPacks: Optional packs to install along with the base game.
- baseURL: A custom ``URL`` for the game to install to.
- gameFolder: The folder where the game should be installed.
- priority: Whether the game should interrupt the currently queued game installation.

- Throws: A `NotSignedInError` or an `InstallationError`.
*/
Expand Down Expand Up @@ -323,18 +327,21 @@ class Legendary {
return try await withCheckedThrowingContinuation { continuation in
Task.sync {
do {
var isLoggedIn = true

try await command(
arguments: ["auth", "--code", authKey],
identifier: "signin"
identifier: "signin",
waits: true
) { output, _ in
continuation.resume(returning: output.stderr.contains("Successfully logged in as"))
isLoggedIn = (isLoggedIn == true ? true : output.stderr.contains("Successfully logged in as"))
}

continuation.resume(returning: isLoggedIn)
} catch {
continuation.resume(throwing: error)
}
}

continuation.resume(returning: false)
}
}

Expand Down
4 changes: 2 additions & 2 deletions Mythic/Controllers/Wine/WineInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class Wine { // TODO: https://forum.winehq.org/viewtopic.php?t=15416
stdin.fileHandleForWriting.write(data)
}
output.stderr = availableOutput
completion(output, task)
completion(output, task) // ⚠️ FIXME: critical performance issues
}

stdout.fileHandleForReading.readabilityHandler = { [stdin, output] handle in
Expand All @@ -191,7 +191,7 @@ class Wine { // TODO: https://forum.winehq.org/viewtopic.php?t=15416
stdin.fileHandleForWriting.write(data)
}
output.stdout = availableOutput
completion(output, task)
completion(output, task) // ⚠️ FIXME: critical performance issues
}

task.terminationHandler = { [stdin] _ in
Expand Down
2 changes: 1 addition & 1 deletion Mythic/Extensions/Double.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

extension Double {
func rounded(_ to: Int) -> Double {
func rounded(toPlaces: Int) -> Double {
let multiplier = pow(10, Double(to))
return Darwin.round(self * multiplier) / multiplier
}
Expand Down
2 changes: 1 addition & 1 deletion Mythic/Extensions/Global.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ class GameOperation: ObservableObject {
static func advance() {
log.debug("[operation.advance] attempting operation advancement")
guard shared.current == nil, let first = shared.queue.first else { return }
// shared.status = .init() FIXME: reset status before next game installation - this implementation doesn't work.
shared.status = InstallStatus()
log.debug("[operation.advance] queuing configuration can advance, no active downloads, game present in queue")
DispatchQueue.main.async {
shared.current = first; shared.queue.removeFirst()
Expand Down
6 changes: 6 additions & 0 deletions Mythic/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -26094,6 +26094,9 @@
}
}
}
},
"No other downloads are pending." : {

},
"Not implemented yet" : {
"localizations" : {
Expand Down Expand Up @@ -28567,6 +28570,9 @@
}
}
}
},
"Remove from download queue" : {

},
"Remove Mythic Engine" : {
"localizations" : {
Expand Down
6 changes: 3 additions & 3 deletions Mythic/Views/InstallationProgress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ struct InstallationProgressView: View {
@ObservedObject private var operation: GameOperation = .shared
@State private var isStopGameModificationAlertPresented: Bool = false
@State private var isInstallStatusViewPresented: Bool = false
@State private var hoveringOverDestructiveButton: Bool = false
@State private var isHoveringOverDestructiveButton: Bool = false

@State private var paused: Bool = false // https://github.com/derrod/legendary/issues/40

Expand Down Expand Up @@ -44,12 +44,12 @@ struct InstallationProgressView: View {
} label: {
Image(systemName: "xmark")
.padding(5)
.foregroundStyle(hoveringOverDestructiveButton ? .red : .primary)
.foregroundStyle(isHoveringOverDestructiveButton ? .red : .primary)
}
.clipShape(.circle)
.help("Stop installing \"\(game.title)\"")
.onHover { hovering in
withAnimation(.easeInOut(duration: 0.1)) { hoveringOverDestructiveButton = hovering }
withAnimation(.easeInOut(duration: 0.1)) { isHoveringOverDestructiveButton = hovering }
}
.alert(isPresented: $isStopGameModificationAlertPresented) {
stopGameOperationAlert(
Expand Down
16 changes: 14 additions & 2 deletions Mythic/Views/Navigation/DownloadsEvo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ struct DownloadsEvo: View {

if operation.queue.isEmpty {
Text("No other downloads are pending.")
.font(.bold(.title)())
.bold()
.padding()
} else {
ForEach(operation.queue, id: \.self) { args in
DownloadCard(game: args.game, style: .normal)
Expand All @@ -40,6 +41,7 @@ struct DownloadsEvo: View {
struct DownloadCard: View {

@ObservedObject private var operation: GameOperation = .shared
@State private var isHoveringOverDestructiveButton: Bool = false

var game: Game
var style: DownloadCardStyle
Expand Down Expand Up @@ -156,7 +158,7 @@ struct DownloadCard: View {
case .normal:
return .caption
case .prominent:
return .callout
return .callout
}
}())

Expand All @@ -168,6 +170,16 @@ struct DownloadCard: View {

if operation.current?.game == game {
InstallationProgressView(withPercentage: false)
} else if operation.queue.contains(where: { $0.game == game }) {
Button {
operation.queue.removeAll(where: { $0.game == game })
} label: {
Image(systemName: "minus")
.padding(5)
.foregroundStyle(isHoveringOverDestructiveButton ? .red : .primary)
}
.clipShape(.circle)
.help("Remove from download queue")
}
}
.padding(.horizontal)
Expand Down

0 comments on commit 0dfaf12

Please sign in to comment.