@@ -17,12 +17,70 @@ struct LauncherView: View {
1717 @FetchRequest ( sortDescriptors: [ SortDescriptor ( \. title) ] ) var launcherRepos : FetchedResults < LauncherRepos >
1818 @State var existingRepo = URL ( string: " " )
1919 @State var repoTitle = " "
20- @State var currentVersion = " v1.1.3 \n "
20+ @State var currentVersion = " v1.1.6 \n "
2121 @State var updateAlert = false
2222 @State var latestVersion = " "
2323 @State var repoArgs = " "
24+ @State var crashStatus = false
25+ @State var crashLog = " "
26+ @State var readableCrashLog = " "
27+ @State var allowAddingRepos = true
2428 @AppStorage ( " firstLaunch " ) var firstLaunch = true
29+ @State var romURL = URL ( string: " " )
2530 let sm64 : UTType = . init( filenameExtension: " f3dex2e " ) !
31+ let rom : UTType = . init( filenameExtension: " z64 " ) !
32+
33+ func launcherShell( _ command: String ) throws -> String {
34+ self . crashLog = " "
35+
36+ let task = Process ( )
37+ var output = " "
38+ task. launchPath = " /bin/zsh "
39+ task. arguments = [ " -cl " , command]
40+
41+ let pipe = Pipe ( )
42+ task. standardOutput = pipe
43+ task. standardError = pipe
44+ let outHandle = pipe. fileHandleForReading
45+ outHandle. waitForDataInBackgroundAndNotify ( )
46+
47+ var obs1 : NSObjectProtocol !
48+ obs1 = NotificationCenter . default. addObserver ( forName: Notification . Name. NSFileHandleDataAvailable, object: outHandle, queue: nil ) { notification -> Void in
49+ let data = outHandle. availableData
50+
51+ if data. count > 0 {
52+ if let str = String ( data: data, encoding: . utf8) {
53+ print ( " got output: \( str) " )
54+
55+ output. append ( str)
56+
57+ self . crashLog. append ( str)
58+ }
59+ outHandle. waitForDataInBackgroundAndNotify ( )
60+ } else {
61+ print ( " EOF on stdout from process " )
62+ NotificationCenter . default. removeObserver ( obs1 as Any )
63+ }
64+ }
65+
66+ var obs2 : NSObjectProtocol !
67+ obs2 = NotificationCenter . default. addObserver ( forName: Process . didTerminateNotification, object: task, queue: nil ) { notification -> Void in
68+ print ( " terminated " )
69+
70+ if task. terminationStatus != 0 {
71+ self . crashLog. append ( " A Crash has happend. Termination Status: \( task. terminationStatus) " )
72+
73+ self . crashStatus = true
74+ }
75+
76+ NotificationCenter . default. removeObserver ( obs2 as Any )
77+ }
78+
79+ try ? task. run ( )
80+
81+ return ( output)
82+ }
83+
2684
2785 func showOpenPanel( ) -> URL ? {
2886 let openPanel = NSOpenPanel ( )
@@ -34,6 +92,40 @@ struct LauncherView: View {
3492 return response == . OK ? openPanel. url : nil
3593 }
3694
95+ func showOpenPanelForRom( ) -> URL ? {
96+ let openPanel = NSOpenPanel ( )
97+ openPanel. allowedContentTypes = [ rom]
98+ openPanel. allowsMultipleSelection = false
99+ openPanel. canChooseDirectories = false
100+ openPanel. canChooseFiles = true
101+ let response = openPanel. runModal ( )
102+ return response == . OK ? openPanel. url : nil
103+ }
104+
105+ func checkRom( _ command: String ) throws -> Bool {
106+ let task = Process ( )
107+ var output = false
108+ task. launchPath = " /bin/zsh "
109+ task. arguments = [ " -cl " , command]
110+
111+ let pipe = Pipe ( )
112+ task. standardOutput = pipe
113+ task. standardError = pipe
114+ let outHandle = pipe. fileHandleForReading
115+ outHandle. waitForDataInBackgroundAndNotify ( )
116+
117+ try ? task. run ( )
118+ task. waitUntilExit ( )
119+ if task. terminationStatus != 0 {
120+ output = true
121+ }
122+ else {
123+ output = false
124+ }
125+
126+ return ( output)
127+ }
128+
37129 var body : some View {
38130 ZStack {
39131 VStack {
@@ -87,6 +179,16 @@ struct LauncherView: View {
87179 print ( " Its broken \( error) " )
88180 }
89181 }
182+
183+ Button ( " Change Repo " ) {
184+ existingRepo = showOpenPanel ( )
185+
186+ launcherRepos [ i] . path = existingRepo? . path
187+
188+ for i in 0 ... launcherRepos. count - 1 {
189+ launcherRepos [ i] . isEditing = false
190+ }
191+ }
90192 } . onAppear {
91193 repoTitle = launcherRepos [ i] . title ?? " "
92194 repoArgs = launcherRepos [ i] . args ?? " "
@@ -95,6 +197,10 @@ struct LauncherView: View {
95197
96198 Button ( action: {
97199
200+ for i in 0 ... launcherRepos. count - 1 {
201+ launcherRepos [ i] . isEditing = false
202+ }
203+
98204 let launcherRepo = launcherRepos [ i]
99205
100206 moc. delete ( launcherRepo)
@@ -110,7 +216,12 @@ struct LauncherView: View {
110216 }
111217
112218 Button ( action: {
113- try ? print ( shell. asyncShell ( " \( LauncherRepo . path ?? " its broken " ) \( LauncherRepo . args ?? " " ) " , waitTillExit: false ) )
219+
220+ for i in 0 ... launcherRepos. count - 1 {
221+ launcherRepos [ i] . isEditing = false
222+ }
223+
224+ print ( try ? launcherShell ( " \( LauncherRepo . path ?? " its broken " ) \( LauncherRepo . args ?? " " ) " ) )
114225
115226 print ( LauncherRepo . path ?? " " )
116227 } ) {
@@ -132,23 +243,62 @@ struct LauncherView: View {
132243
133244 Spacer ( )
134245
246+ if allowAddingRepos {
247+ Button ( action: {
248+
249+ for i in 0 ... launcherRepos. count - 1 {
250+ launcherRepos [ i] . isEditing = false
251+ }
252+
253+ romURL = showOpenPanelForRom ( )
254+
255+ romURL? = URL ( fileURLWithPath: romURL? . path. replacingOccurrences ( of: " " , with: " \\ " ) ?? " " )
256+
257+ print ( romURL? . path ?? " " )
258+ print ( romURL? . pathExtension ?? " " )
259+
260+ print ( try ? shell. shell ( " cp \( romURL? . path ?? " " ) ~/SM64Repos/baserom.us.z64 " ) ?? " " )
261+
262+ if let doesExist = try ? checkRom ( " ls ~/SM64Repos/baserom.us.z64 " ) {
263+ if doesExist {
264+ allowAddingRepos = true
265+ }
266+ else {
267+ allowAddingRepos = false
268+ }
269+ }
270+ } ) {
271+ Text ( " Select Rom " )
272+ }
273+ }
274+
135275 Button ( action: {
276+
277+ for i in 0 ... launcherRepos. count - 1 {
278+ launcherRepos [ i] . isEditing = false
279+ }
280+
136281 repoView = true
137282 } ) {
138283 Text ( " Add New Repo " )
139284 } . buttonStyle ( . borderedProminent) . sheet ( isPresented: $repoView) {
140285 RepoView ( repoView: $repoView)
141286 . frame ( minWidth: 750 , minHeight: 500 )
142- }
287+ } . disabled ( allowAddingRepos )
143288
144289 Button ( " Add Existing Repo " ) {
290+
291+ for i in 0 ... launcherRepos. count - 1 {
292+ launcherRepos [ i] . isEditing = false
293+ }
294+
145295 existingRepo = showOpenPanel ( )
146296
147297 if existingRepo != nil {
148298
149299 let repo = LauncherRepos ( context: moc)
150300
151- repo. title = " Repo \( launcherRepos. count) "
301+ repo. title = " New Repo \( launcherRepos. count) "
152302 repo. path = existingRepo? . path
153303 repo. args = " "
154304 repo. id = UUID ( )
@@ -162,31 +312,18 @@ struct LauncherView: View {
162312 }
163313 }
164314
165- Button ( " Install Homebrew " ) {
166- print ( shell. installBrew ( " /bin/bash -c \" $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh) \" " ) )
167-
168- let content = UNMutableNotificationContent ( )
169- content. title = " Finished installing homebrew "
170- content. subtitle = " Homebrew is now installed. If this is your first time with homebrew, please hit the install dependencies button. "
171- content. sound = UNNotificationSound . default
172-
173- // show this notification instantly
174- let trigger = UNTimeIntervalNotificationTrigger ( timeInterval: 0.0001 , repeats: false )
175-
176- // choose a random identifier
177- let request = UNNotificationRequest ( identifier: UUID ( ) . uuidString, content: content, trigger: trigger)
178-
179- // add our notification request
180- UNUserNotificationCenter . current ( ) . add ( request)
181- }
182-
183315 Text ( " Homebrew is REQUIRED for this software to work, please install homebrew at brew.sh " )
184316 . padding ( . horizontal)
185317
186318 Text ( " \n Optional: Homebrew Intel version is nice to have. Install by launching terminal with Rosetta and installing at brew.sh " )
187319 . padding ( . horizontal)
188320
189321 Button ( action: {
322+
323+ for i in 0 ... launcherRepos. count - 1 {
324+ launcherRepos [ i] . isEditing = false
325+ }
326+
190327 print ( try ! shell. shell ( " brew install make mingw-w64 gcc sdl2 pkg-config glew glfw3 libusb audiofile coreutils " ) )
191328
192329 print ( " its intel's turn nerd what an idiot man " )
@@ -210,7 +347,14 @@ struct LauncherView: View {
210347 Text ( " Install Dependencies " )
211348 } . buttonStyle ( . bordered) . padding ( . vertical)
212349 }
350+
213351 } . onAppear {
352+ if try ! checkRom ( " ls ~/SM64Repos/baserom.us.z64 " ) {
353+ allowAddingRepos = true
354+ }
355+ else {
356+ allowAddingRepos = false
357+ }
214358
215359 latestVersion = try ! shell. shell ( " curl https://github.com/EmeraldLoc/sm_osx/releases/latest -s | grep -o 'v[0-9].[0-9].[0-9]*' | sort -u " )
216360
@@ -238,12 +382,34 @@ struct LauncherView: View {
238382
239383 } . alert ( " An Update is Avalible " , isPresented: $updateAlert) {
240384 Button ( " Update " , role: . none) {
241- print ( try ! shell. shell ( " cd ~/Downloads && wget https://github.com/EmeraldLoc/sm_osx/releases/latest/download/sm_osx.zip && unzip sm_osx.zip && rm -rf sm_osx.zip /Applications/sm_osx.app && mv sm_osx.app /Applications " ) )
385+ print ( try ! shell. shell ( " cd ~/Downloads && wget https://github.com/EmeraldLoc/sm_osx/releases/latest/download/sm_osx.zip && unzip sm_osx.zip && rm -rf sm_osx.zip /Applications/sm_osx.app && mv sm_osx.app /Applications && open /Applications/sm_osx.app " ) )
242386
243387 exit ( 0 )
244388 }
245389
246390 Button ( " Not now " , role: . cancel) { }
391+ } . sheet ( isPresented: $crashStatus) {
392+ VStack {
393+ Text ( " Your Game Crashed " )
394+
395+ ScrollView {
396+
397+ TextEditor ( text: $readableCrashLog)
398+ . frame ( minWidth: 350 , minHeight: 350 )
399+ . onChange ( of: readableCrashLog) { _ in
400+ readableCrashLog = crashLog
401+ }
402+ . onAppear {
403+ readableCrashLog = crashLog
404+ }
405+ }
406+
407+ Button ( " Close " ) {
408+ crashLog = " "
409+
410+ crashStatus = false
411+ }
412+ } . frame ( minWidth: 350 , maxHeight: 350 )
247413 }
248414 }
249415}
0 commit comments