Oolite 1.93.0.7767-260207-f2a8cb5
Loading...
Searching...
No Matches
GameController.m
Go to the documentation of this file.
1/*
2
3GameController.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "GameController.h"
26#import "Universe.h"
27#import "ResourceManager.h"
28#import "MyOpenGLView.h"
29#import "OOSound.h"
30#import "OOOpenGL.h"
32#include <stdlib.h>
34#import "OOOXPVerifier.h"
35#import "OOLoggingExtended.h"
38#import "OODebugFlags.h"
42#import "OODebugSupport.h"
43#import "legacy_random.h"
44#import "OOOXZManager.h"
46
47#if OOLITE_MAC_OS_X
49#import <Sparkle/Sparkle.h>
50#import "OoliteApp.h"
52
53static void SetUpSparkle(void);
54#elif (OOLITE_GNUSTEP && !defined(NDEBUG))
55#import "OODebugMonitor.h"
56#endif
57
58
60
61
62@interface GameController (OOPrivate)
63
64- (void)reportUnhandledStartupException:(NSException *)exception;
65
66- (void)doPerformGameTick;
67
68@end
69
70
71@implementation GameController
72
74{
76 {
77 sSharedController = [[self alloc] init];
78 }
79 return sSharedController;
80}
81
82
83- (id) init
84{
86 {
87 [self release];
88 [NSException raise:NSInternalInconsistencyException format:@"%s: expected only one GameController to exist at a time.", __PRETTY_FUNCTION__];
89 }
90
91 if ((self = [super init]))
92 {
93 _finishedLaunching = NO;
94 last_timeInterval = [NSDate timeIntervalSinceReferenceDate];
95 delta_t = 0.01; // one hundredth of a second
96 _animationTimerInterval = [[NSUserDefaults standardUserDefaults] oo_doubleForKey:@"animation_timer_interval" defaultValue:MINIMUM_ANIMATION_TICK];
97
98 // rather than seeding this with the date repeatedly, seed it
99 // once here at startup
100 ranrot_srand((uint32_t)[[NSDate date] timeIntervalSince1970]); // reset randomiser with current time
101
102 _splashStart = [[NSDate alloc] init];
103 }
104
105 return self;
106}
107
108
109- (void) dealloc
110{
111#if OOLITE_MAC_OS_X
112 [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:UNIVERSE];
113#endif
114
115 [timer release];
116 [gameView release];
117 [UNIVERSE release];
118
119 [playerFileToLoad release];
120 [playerFileDirectory release];
121 [expansionPathsToInclude release];
122
123 [super dealloc];
124}
125
126
128{
129 return gameIsPaused;
130}
131
132
133- (void) setGamePaused:(BOOL)value
134{
135 if (value && !gameIsPaused)
136 {
139 gameIsPaused = YES;
140 [PLAYER doScriptEvent:OOJSID("gamePaused")];
141 }
142 else if (!value && gameIsPaused)
143 {
144 [self setMouseInteractionMode:_resumeMode];
145 gameIsPaused = NO;
146 [PLAYER doScriptEvent:OOJSID("gameResumed")];
147 }
148}
149
150
155
156
157- (void) setMouseInteractionMode:(OOMouseInteractionMode)mode
158{
160 if (mode == oldMode) return;
161
163 OOLog(@"input.mouseMode.changed", @"Mouse interaction mode changed from %@ to %@", OOStringFromMouseInteractionMode(oldMode), OOStringFromMouseInteractionMode(mode));
164
165#if OO_USE_FULLSCREEN_CONTROLLER
166 if ([self inFullScreenMode])
167 {
169 }
170 else
171#endif
172 {
173 [[self gameView] noteMouseInteractionModeChangedFrom:oldMode to:mode];
174 }
175}
176
177
179{
180 [self setMouseInteractionMode:[PLAYER isMouseControlOn] ? MOUSE_MODE_FLIGHT_WITH_MOUSE_CONTROL : MOUSE_MODE_FLIGHT_NO_MOUSE_CONTROL];
181}
182
183
184- (void) setMouseInteractionModeForUIWithMouseInteraction:(BOOL)interaction
185{
186 [self setMouseInteractionMode:interaction ? MOUSE_MODE_UI_SCREEN_WITH_INTERACTION : MOUSE_MODE_UI_SCREEN_NO_INTERACTION];
187}
188
189
191{
192 return gameView;
193}
194
195
196- (void) setGameView:(MyOpenGLView *)view
197{
198 [gameView release];
199 gameView = [view retain];
201 [UNIVERSE setGameView:gameView];
202}
203
204
205- (void) applicationDidFinishLaunching:(NSNotification *)notification
206{
207 NSAutoreleasePool *pool = nil;
208 unsigned i;
209
210 pool = [[NSAutoreleasePool alloc] init];
211
212 @try
213 {
214 // if not verifying oxps, ensure that gameView is drawn to using beginSplashScreen
215 // OpenGL is initialised and that allows textures to initialise too.
216
217#if OO_OXP_VERIFIER_ENABLED
218
219 if ([OOOXPVerifier runVerificationIfRequested])
220 {
221 [self exitAppWithContext:@"OXP verifier run"];
222 }
223 else
224 {
225 [self beginSplashScreen];
226 }
227
228#else
229 [self beginSplashScreen];
230#endif
231
232#if OOLITE_MAC_OS_X
234 SetUpSparkle();
235#endif
236
237 [self setUpDisplayModes];
238
239 // moved to before the Universe is created
241 {
242 for (i = 0; i < [expansionPathsToInclude count]; i++)
243 {
244 [ResourceManager addExternalPath: (NSString*)[expansionPathsToInclude objectAtIndex: i]];
245 }
246 }
247
248 // initialise OXZ manager
250
251 // moved here to try to avoid initialising this before having an Open GL context
252 //[self logProgress:DESC(@"Initialising universe")]; // DESC expansions only possible after Universe init
253 [[Universe alloc] initWithGameView:gameView];
254
256
257 [self logProgress:@""];
258
259 // get the run loop and add the call to performGameTick:
260 [self startAnimationTimer];
261
262 [self endSplashScreen];
263 }
264 @catch (NSException *exception)
265 {
266 [self reportUnhandledStartupException:exception];
267 exit(EXIT_FAILURE);
268 }
269
270 OOLog(@"startup.complete", @"========== Loading complete in %.2f seconds. ==========", -[_splashStart timeIntervalSinceNow]);
271
272#if OO_USE_FULLSCREEN_CONTROLLER
273 [self setFullScreenMode:[[NSUserDefaults standardUserDefaults] boolForKey:@"fullscreen"]];
274#endif
275
276 _finishedLaunching = YES;
277
278 // Release anything allocated above that is not required.
279 [pool release];
280
281#if !OOLITE_MAC_OS_X
282 [[NSRunLoop currentRunLoop] run];
283#endif
284}
285
286
288{
289 return _finishedLaunching;
290}
291
292
294{
295 if (playerFileToLoad != nil)
296 {
297 [self logProgress:DESC(@"loading-player")];
298 // fix problem with non-shader lighting when starting skips
299 // the splash screen
300 [UNIVERSE useGUILightSource:YES];
301 [UNIVERSE useGUILightSource:NO];
302 [PLAYER loadPlayerFromFile:playerFileToLoad asNew:NO];
303 }
304}
305
306
308{
309#if !OOLITE_MAC_OS_X
310 if(!gameView)
311 {
312 gameView = [MyOpenGLView alloc];
313 [gameView init];
316 }
317#else
319#endif
320}
321
322
323#if OOLITE_MAC_OS_X
324
325- (void) performGameTick:(id)sender
326{
328 [self doPerformGameTick];
329}
330
331#else
332
333- (void) performGameTick:(id)sender
334{
335 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
336
337 [gameView pollControls];
338 [self doPerformGameTick];
339
340 [pool release];
341}
342
343#endif
344
345
347{
348 @try
349 {
350 if (gameIsPaused)
351 delta_t = 0.0; // no movement!
352 else
353 {
354 delta_t = [NSDate timeIntervalSinceReferenceDate] - last_timeInterval;
355 last_timeInterval += delta_t;
356 if (delta_t > MINIMUM_GAME_TICK)
357 delta_t = MINIMUM_GAME_TICK; // peg the maximum pause (at 0.5->1.0 seconds) to protect against when the machine sleeps
358 }
359
360 [UNIVERSE update:delta_t];
361 if (EXPECT_NOT([PLAYER status] == STATUS_RESTART_GAME))
362 {
363 [UNIVERSE reinitAndShowDemo:YES];
364 }
365 [OOSound update];
366 if (!gameIsPaused)
367 {
369 }
370 }
371 @catch (id exception)
372 {
373 OOLog(@"exception.backtrace",@"%@",[exception callStackSymbols]);
374 }
375
376 @try
377 {
378 [gameView display];
379 }
380 @catch (id exception) {}
381}
382
383
385{
386 if (timer == nil)
387 {
388 NSTimeInterval ti = _animationTimerInterval; // default one two-hundredth of a second (should be a fair bit faster than expected frame rate ~60Hz to avoid problems with phase differences)
389
390 timer = [[NSTimer timerWithTimeInterval:ti target:self selector:@selector(performGameTick:) userInfo:nil repeats:YES] retain];
391
392 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
393#if OOLITE_MAC_OS_X
394 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
395#endif
396
397 }
398}
399
400
402{
403 if (timer != nil)
404 {
405 [timer invalidate];
406 [timer release];
407 timer = nil;
408 }
409}
410
411
412#if OOLITE_MAC_OS_X
413
415{
416 // FIXME: does this really need to be spread across GameController and MyOpenGLView? -- Ahruman 2011-01-22
417 my_mouse_x = my_mouse_y = 0; // center mouse
418 [gameView setVirtualJoystick:0.0 :0.0];
419}
420
421
422- (IBAction) showLogAction:sender
423{
424 [[NSWorkspace sharedWorkspace] openFile:[OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"]];
425}
426
427
428- (IBAction) showLogFolderAction:sender
429{
430 [[NSWorkspace sharedWorkspace] openFile:OOLogHandlerGetLogBasePath()];
431}
432
433
434// Helpers to allow -snapshotsURLCreatingIfNeeded: code to be identical here and in dock tile plug-in.
435static id GetPreference(NSString *key, Class expectedClass)
436{
437 id result = [[NSUserDefaults standardUserDefaults] objectForKey:key];
438 if (expectedClass != Nil && ![result isKindOfClass:expectedClass]) result = nil;
439
440 return result;
441}
442
443
444static void SetPreference(NSString *key, id value)
445{
446 [[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
447}
448
449
450static void RemovePreference(NSString *key)
451{
452 [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
453}
454
455
456#define kSnapshotsDirRefKey @"snapshots-directory-reference"
457#define kSnapshotsDirNameKey @"snapshots-directory-name"
458
459- (NSURL *) snapshotsURLCreatingIfNeeded:(BOOL)create
460{
461 BOOL stale = NO;
462 NSDictionary *snapshotDirDict = GetPreference(kSnapshotsDirRefKey, [NSDictionary class]);
463 NSURL *url = nil;
464 NSString *name = DESC(@"snapshots-directory-name-mac");
465
466 if (snapshotDirDict != nil)
467 {
469 if (url != nil)
470 {
471 NSString *existingName = [[url path] lastPathComponent];
472 if ([existingName compare:name options:NSCaseInsensitiveSearch] != 0)
473 {
474 // Check name from previous access, because we might have changed localizations.
475 NSString *originalOldName = GetPreference(kSnapshotsDirNameKey, [NSString class]);
476 if (originalOldName == nil || [existingName compare:originalOldName options:NSCaseInsensitiveSearch] != 0)
477 {
478 url = nil;
479 }
480 }
481
482 // did we put the old directory in the trash?
483 Boolean inTrash = false;
484 const UInt8 *utfPath = (const UInt8 *)[[url path] UTF8String];
485
486 OSStatus err = DetermineIfPathIsEnclosedByFolder(kOnAppropriateDisk, kTrashFolderType, utfPath, false, &inTrash);
487 // if so, create a new directory.
488 if (err == noErr && inTrash == true) url = nil;
489 }
490 }
491
492 if (url == nil)
493 {
494 NSString *path = nil;
495 NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
496 if ([searchPaths count] > 0)
497 {
498 path = [[searchPaths objectAtIndex:0] stringByAppendingPathComponent:name];
499 }
500 url = [NSURL fileURLWithPath:path];
501
502 if (url != nil)
503 {
504 stale = YES;
505 if (create)
506 {
507 NSFileManager *fmgr = [NSFileManager defaultManager];
508 if (![fmgr fileExistsAtPath:path])
509 {
510 [fmgr oo_createDirectoryAtPath:path attributes:nil];
511 }
512 }
513 }
514 }
515
516 if (stale)
517 {
518 snapshotDirDict = JAPersistentFileReferenceFromURL(url);
519 if (snapshotDirDict != nil)
520 {
521 SetPreference(kSnapshotsDirRefKey, snapshotDirDict);
522 SetPreference(kSnapshotsDirNameKey, [[url path] lastPathComponent]);
523 }
524 else
525 {
527 }
528 }
529
530 return url;
531}
532
533
534- (IBAction) showSnapshotsAction:sender
535{
536 [[NSWorkspace sharedWorkspace] openURL:[self snapshotsURLCreatingIfNeeded:YES]];
537}
538
539
540- (IBAction) showAddOnsAction:sender
541{
542 NSArray *paths = ResourceManager.userRootPaths;
543
544 // Look for an AddOns directory that actually contains some AddOns.
545 for (NSString *path in paths) {
546 if ([self addOnsExistAtPath:path]) {
547 [self openPath:path];
548 return;
549 }
550 }
551
552 // If that failed, look for an AddOns directory that actually exists.
553 for (NSString *path in paths) {
554 if ([self isDirectoryAtPath:path]) {
555 [self openPath:path];
556 return;
557 }
558 }
559
560 // None found, create the default path.
561 [NSFileManager.defaultManager createDirectoryAtPath:[paths objectAtIndex:0]
562 withIntermediateDirectories:YES
563 attributes:nil
564 error:NULL];
565 [self openPath:[paths objectAtIndex:0]];
566}
567
568
569- (BOOL) isDirectoryAtPath:(NSString *)path
570{
571 BOOL isDirectory;
572 return [NSFileManager.defaultManager fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory;
573}
574
575
576- (BOOL) addOnsExistAtPath:(NSString *)path
577{
578 if (![self isDirectoryAtPath:path]) return NO;
579
580 NSWorkspace *workspace = NSWorkspace.sharedWorkspace;
581 for (NSString *subPath in [NSFileManager.defaultManager enumeratorAtPath:path]) {
582 subPath = [path stringByAppendingPathComponent:subPath];
583 NSString *type = [workspace typeOfFile:subPath error:NULL];
584 if ([workspace type:type conformsToType:@"org.aegidian.oolite.expansion"]) return YES;
585 }
586
587 return NO;
588}
589
590
591- (void) openPath:(NSString *)path
592{
593 [NSWorkspace.sharedWorkspace openURL:[NSURL fileURLWithPath:path]];
594}
595
596
597- (BOOL) validateMenuItem:(NSMenuItem *)menuItem
598{
599 SEL action = menuItem.action;
600
601 if (action == @selector(showLogAction:))
602 {
603 // the first path is always Resources
604 return ([[NSFileManager defaultManager] fileExistsAtPath:[OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"]]);
605 }
606
607 if (action == @selector(showAddOnsAction:))
608 {
609 // Always enabled in unrestricted mode, to allow users to add OXPs more easily.
610 return [ResourceManager useAddOns] != nil;
611 }
612
613 if (action == @selector(showSnapshotsAction:))
614 {
615 BOOL pathIsDirectory;
616 if(![[NSFileManager defaultManager] fileExistsAtPath:[self snapshotsURLCreatingIfNeeded:NO].path isDirectory:&pathIsDirectory])
617 {
618 return NO;
619 }
620 return pathIsDirectory;
621 }
622
623 if (action == @selector(toggleFullScreenAction:))
624 {
625 if (_fullScreenController.fullScreenMode)
626 {
627 // NOTE: not DESC, because menu titles are not generally localizable.
628 menuItem.title = NSLocalizedString(@"Exit Full Screen", NULL);
629 }
630 else
631 {
632 menuItem.title = NSLocalizedString(@"Enter Full Screen", NULL);
633 }
634 }
635
636 // default
637 return YES;
638}
639
640
641- (NSMenu *)applicationDockMenu:(NSApplication *)sender
642{
643 return dockMenu;
644}
645
646#elif OOLITE_SDL
647
648- (NSURL *) snapshotsURLCreatingIfNeeded:(BOOL)create
649{
650 NSURL *url = [NSURL fileURLWithPath:[NSHomeDirectory() stringByAppendingPathComponent:DESC(@"snapshots-directory-name")]];
651
652 if (create)
653 {
654 NSString *path = [url path];
655 NSFileManager *fmgr = [NSFileManager defaultManager];
656 if (![fmgr fileExistsAtPath:path])
657 {
658 [fmgr oo_createDirectoryAtPath:path attributes:nil];
659 }
660 }
661 return url;
662}
663
664#else
665 #error Unknown environment!
666#endif
667
668- (void) logProgress:(NSString *)message
669{
670 if (![UNIVERSE doingStartUp]) return;
671
672#if OOLITE_MAC_OS_X
673 [splashProgressTextField setStringValue:message];
674 [splashProgressTextField display];
675#endif
676 if([message length] > 0)
677 {
678 OOLog(@"startup.progress", @"===== [%.2f s] %@", -[_splashStart timeIntervalSinceNow], message);
679 }
680}
681
682
683#if OO_DEBUG
684#if OOLITE_MAC_OS_X
685- (BOOL) debugMessageTrackingIsOn
686{
687 return splashProgressTextField != nil;
688}
689
690
691- (NSString *) debugMessageCurrentString
692{
693 return [splashProgressTextField stringValue];
694}
695#else
696- (BOOL) debugMessageTrackingIsOn
697{
698 return OOLogWillDisplayMessagesInClass(@"startup.progress");
699}
700
701
702- (NSString *) debugMessageCurrentString
703{
704 return @"";
705}
706#endif
707
708- (void) debugLogProgress:(NSString *)format, ...
709{
710 va_list args;
711 va_start(args, format);
712 [self debugLogProgress:format arguments:args];
713 va_end(args);
714}
715
716
717- (void) debugLogProgress:(NSString *)format arguments:(va_list)arguments
718{
719 NSString *message = [[[NSString alloc] initWithFormat:format arguments:arguments] autorelease];
720 [self logProgress:message];
721}
722
723
724static NSMutableArray *sMessageStack;
725
726- (void) debugPushProgressMessage:(NSString *)format, ...
727{
728 if ([self debugMessageTrackingIsOn])
729 {
730 if (sMessageStack == nil) sMessageStack = [[NSMutableArray alloc] init];
731 [sMessageStack addObject:[self debugMessageCurrentString]];
732
733 va_list args;
734 va_start(args, format);
735 [self debugLogProgress:format arguments:args];
736 va_end(args);
737 }
738
739 OOLogIndentIf(@"startup.progress");
740}
741
742
743- (void) debugPopProgressMessage
744{
745 OOLogOutdentIf(@"startup.progress");
746
747 if ([sMessageStack count] > 0)
748 {
749 NSString *message = [sMessageStack lastObject];
750 if ([message length] > 0) [self logProgress:message];
751 [sMessageStack removeLastObject];
752 }
753}
754
755#endif
756
757
759{
760 OOLogSetDisplayMessagesInClass(@"startup.progress", NO);
761
762#if OOLITE_MAC_OS_X
763 // These views will be released when we replace the content view.
765 splashView = nil;
766
767 [gameWindow setAcceptsMouseMovedEvents:YES];
768 [gameWindow setContentView:gameView];
769 [gameWindow makeFirstResponder:gameView];
770#elif OOLITE_SDL
772#endif
773}
774
775
776#if OOLITE_MAC_OS_X
777
778// NIB methods
780{
781 NSString *path = nil;
782
783 // Set contents of Help window
784 path = [[NSBundle mainBundle] pathForResource:@"OoliteReadMe" ofType:@"pdf"];
785 if (path != nil)
786 {
787 PDFDocument *document = [[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath:path]];
788 [helpView setDocument:document];
789 [document release];
790 }
791 [helpView setBackgroundColor:[NSColor whiteColor]];
792}
793
794
795// delegate methods
796- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
797{
798 if ([[filename pathExtension] isEqual:@"oolite-save"])
799 {
800 [self setPlayerFileToLoad:filename];
801 [self setPlayerFileDirectory:filename];
802 return YES;
803 }
804 if ([[filename pathExtension] isEqualToString:@"oxp"])
805 {
806 BOOL dir_test;
807 [[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&dir_test];
808 if (dir_test)
809 {
811 {
813 }
814 [expansionPathsToInclude addObject:filename];
815 return YES;
816 }
817 }
818 return NO;
819}
820
821
822- (void) exitAppWithContext:(NSString *)context
823{
824 [gameView.window orderOut:nil];
825 [(OoliteApp *)NSApp setExitContext:context];
826 [NSApp terminate:self];
827}
828
829
830- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
831{
834 return NSTerminateNow;
835}
836
837#elif OOLITE_SDL
838
839- (void) exitAppWithContext:(NSString *)context
840{
841 OOLog(@"exit.context", @"Exiting: %@.", context);
842#if (OOLITE_GNUSTEP && !defined(NDEBUG))
843 [[OODebugMonitor sharedDebugMonitor] applicationWillTerminate];
844#endif
845#if OOLITE_WINDOWS
846 // This should not be required normally but we have to ensure that
847 // desktop resolution is restored also on some Intel cards on Win10
848 if (![gameView atDesktopResolution])
849 {
850 OOLog(@"gameController.exitApp", @"%@", @"Restoring desktop resolution.");
851 ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
852 }
853#endif
854 [[NSUserDefaults standardUserDefaults] synchronize];
855 OOLog(@"gameController.exitApp", @"%@", @".GNUstepDefaults synchronized.");
857 SDL_Quit();
859 exit(0);
860}
861
862#else
863 #error Unknown environment!
864#endif
865
866
868{
869 [self exitAppWithContext:@"Command-Q"];
870}
871
872
873- (void)windowDidResize:(NSNotification *)aNotification
874{
876}
877
878
879- (NSString *) playerFileToLoad
880{
881 return playerFileToLoad;
882}
883
884
885- (void) setPlayerFileToLoad:(NSString *)filename
886{
888 [playerFileToLoad autorelease];
890 if ([[[filename pathExtension] lowercaseString] isEqual:@"oolite-save"])
891 playerFileToLoad = [filename copy];
892}
893
894
896{
898 {
899 playerFileDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"save-directory"];
900 if (playerFileDirectory != nil && ![[NSFileManager defaultManager] fileExistsAtPath:playerFileDirectory])
901 {
903 }
904 if (playerFileDirectory == nil) playerFileDirectory = [[NSFileManager defaultManager] defaultCommanderPath];
905
906 [playerFileDirectory retain];
907 }
908
909 return playerFileDirectory;
910}
911
912
913- (void) setPlayerFileDirectory:(NSString *)filename
914{
916 {
917 [playerFileDirectory autorelease];
919 }
920
921 if ([[[filename pathExtension] lowercaseString] isEqual:@"oolite-save"])
922 {
923 filename = [filename stringByDeletingLastPathComponent];
924 }
925
926 playerFileDirectory = [filename retain];
927 [[NSUserDefaults standardUserDefaults] setObject:filename forKey:@"save-directory"];
928}
929
930
931- (void)reportUnhandledStartupException:(NSException *)exception
932{
933 OOLog(@"startup.exception", @"***** Unhandled exception during startup: %@ (%@).", [exception name], [exception reason]);
934
935 #if OOLITE_MAC_OS_X
936 // Display an error alert.
937 // TODO: provide better information on reporting bugs in the manual, and refer to it here.
938 NSRunCriticalAlertPanel(@"Oolite failed to start up, because an unhandled exception occurred.", @"An exception of type %@ occurred. If this problem persists, please file a bug report.", @"OK", NULL, NULL, [exception name]);
939 #endif
940}
941
942
943- (void)setUpBasicOpenGLStateWithSize:(NSSize)viewSize
944{
946
947 float ratio = 0.5;
948 float aspect = viewSize.height/viewSize.width;
949
950 OOGL(glClearColor(0.0, 0.0, 0.0, 0.0));
951 OOGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
952
953 OOGL(glClearDepth(1.0));
954 OOGL(glViewport(0, 0, viewSize.width, viewSize.height));
955
956 OOGLResetProjection(); // reset matrix
957 OOGLFrustum(-ratio, ratio, -aspect*ratio, aspect*ratio, 1.0, MAX_CLEAR_DEPTH); // set projection matrix
958
959 OOGL(glDepthFunc(GL_LESS)); // depth buffer
960
961 if (UNIVERSE)
962 {
963 [UNIVERSE setLighting];
964 }
965 else
966 {
967 GLfloat black[4] = {0.0, 0.0, 0.0, 1.0};
968 GLfloat white[] = {1.0, 1.0, 1.0, 1.0};
969 GLfloat stars_ambient[] = {0.25, 0.2, 0.25, 1.0};
970
971 OOGL(glLightfv(GL_LIGHT1, GL_AMBIENT, black));
972 OOGL(glLightfv(GL_LIGHT1, GL_SPECULAR, white));
973 OOGL(glLightfv(GL_LIGHT1, GL_DIFFUSE, white));
974 OOGL(glLightfv(GL_LIGHT1, GL_POSITION, black));
975 OOGL(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, stars_ambient));
976
977 }
978
979 if ([extMgr usePointSmoothing]) OOGL(glEnable(GL_POINT_SMOOTH));
980 if ([extMgr useLineSmoothing]) OOGL(glEnable(GL_LINE_SMOOTH));
981
982 // world's simplest OpenGL optimisations...
983#if GL_APPLE_transform_hint
984 if ([extMgr haveExtension:@"GL_APPLE_transform_hint"])
985 {
986 OOGL(glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST));
987 }
988#endif
989
990 OOGL(glDisable(GL_NORMALIZE));
991 OOGL(glDisable(GL_RESCALE_NORMAL));
992
993#if GL_VERSION_1_2
994 // For OpenGL 1.2 or later, we want GL_SEPARATE_SPECULAR_COLOR all the time.
995 if ([extMgr versionIsAtLeastMajor:1 minor:2])
996 {
997 OOGL(glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR));
998 }
999#endif
1000}
1001
1002
1003#ifndef NDEBUG
1004/* This method exists purely to suppress Clang static analyzer warnings that
1005 these ivars are unused (but may be used by categories, which they are).
1006*/
1008{
1009 return pauseSelector &&
1011}
1012#endif
1013
1014@end
1015
1016
1017#if OOLITE_MAC_OS_X
1018
1019static void SetUpSparkle(void)
1020{
1021#define FEED_URL_BASE "http://www.oolite.org/updates/"
1022#define TEST_RELEASE_FEED_NAME "oolite-mac-test-release-appcast.xml"
1023#define DEPLOYMENT_FEED_NAME "oolite-mac-appcast.xml"
1024
1025#define TEST_RELEASE_FEED_URL (@ FEED_URL_BASE TEST_RELEASE_FEED_NAME)
1026#define DEPLOYMENT_FEED_URL (@ FEED_URL_BASE DEPLOYMENT_FEED_NAME)
1027
1028// Default to test releases in test release or debug builds, and stable releases for deployment builds.
1029#ifdef NDEBUG
1030#define DEFAULT_TEST_RELEASE 0
1031#else
1032#define DEFAULT_TEST_RELEASE 1
1033#endif
1034
1035 BOOL useTestReleases = [[NSUserDefaults standardUserDefaults] oo_boolForKey:@"use-test-release-updates"
1036 defaultValue:DEFAULT_TEST_RELEASE];
1037
1038 SUUpdater *updater = [SUUpdater sharedUpdater];
1039 [updater setFeedURL:[NSURL URLWithString:useTestReleases ? TEST_RELEASE_FEED_URL : DEPLOYMENT_FEED_URL]];
1040}
1041
1042#endif
#define MAX_CLEAR_DEPTH
#define MINIMUM_GAME_TICK
static GameController * sSharedController
#define kSnapshotsDirNameKey
#define kSnapshotsDirRefKey
static void SetUpSparkle(void)
@ kJAPersistentFileReferenceWithoutUI
@ kJAPersistentFileReferenceWithoutMounting
NSURL * JAURLFromPersistentFileReference(NSDictionary *fileRef, JAPersistentFileReferenceResolveFlags flags, BOOL *isStale)
NSDictionary * JAPersistentFileReferenceFromURL(NSURL *url)
#define EXPECT_NOT(x)
void OOJSFrameCallbacksInvoke(OOTimeDelta delta)
NSString * OOLogHandlerGetLogBasePath(void)
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
Definition OOLogging.m:144
#define OOLogOutdentIf(class)
Definition OOLogging.h:102
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define OOLogIndentIf(class)
Definition OOLogging.h:101
void OOLoggingTerminate(void)
Definition OOLogging.m:612
void OOLogSetDisplayMessagesInClass(NSString *inClass, BOOL inFlag)
Definition OOLogging.m:182
OOMouseInteractionMode
NSString * OOStringFromMouseInteractionMode(OOMouseInteractionMode mode)
void OOGLFrustum(double left, double right, double bottom, double top, double near, double far)
void OOGLResetProjection(void)
#define OOGL(statement)
Definition OOOpenGL.h:251
unsigned count
return nil
#define PLAYER
#define UNIVERSE
Definition Universe.h:844
#define DESC(key)
Definition Universe.h:850
void setMouseInteractionMode:(OOMouseInteractionMode mode)
void setMouseInteractionModeForUIWithMouseInteraction:(BOOL interaction)
IBOutlet NSTextField * splashProgressTextField
static id GetPreference(NSString *key, Class expectedClass)
OOMouseInteractionMode mouseInteractionMode()
NSString * playerFileToLoad
GameController * sharedController()
NSMutableArray * expansionPathsToInclude
OOMouseInteractionMode _resumeMode
NSTimeInterval last_timeInterval
void recenterVirtualJoystick()
NSString * playerFileDirectory
void reportUnhandledStartupException:(NSException *exception)
void openPath:(NSString *path)
void logProgress:(NSString *message)
NSDate * _splashStart
NSTimeInterval _animationTimerInterval
void exitAppWithContext:(NSString *context)
static void SetPreference(NSString *key, id value)
OOMouseInteractionMode _mouseMode
void setPlayerFileDirectory:(NSString *filename)
void setMouseInteractionModeForFlight()
NSObject * pauseTarget
void setFullScreenMode:(BOOL value)
NSURL * snapshotsURLCreatingIfNeeded:(BOOL create)
IBOutlet MyOpenGLView * gameView
static void RemovePreference(NSString *key)
void setPlayerFileToLoad:(NSString *filename)
IBOutlet NSView * splashView
OOFullScreenController * _fullScreenController
IBOutlet NSMenu * dockMenu
void noteMouseInteractionModeChangedFrom:to:(OOMouseInteractionMode oldMode,[to] OOMouseInteractionMode newMode)
void endSplashScreen()
void setGameController:(GameController *controller)
void initSplashScreen()
OOCacheManager * sharedCache()
OODebugMonitor * sharedDebugMonitor()
void noteMouseInteractionModeChangedFrom:to:(OOMouseInteractionMode oldMode,[to] OOMouseInteractionMode newMode)
BOOL setStickHandlerClass:(Class aClass)
OOOXZManager * sharedManager()
OOOpenALController * sharedController()
OOOpenGLExtensionManager * sharedManager()
void update()
Definition OOALSound.m:149
void setExitContext:(NSString *exitContext)
Definition OoliteApp.m:58
void addExternalPath:(NSString *fileName)
NSString * useAddOns()
NSArray * userRootPaths()
const char * filename
Definition ioapi.h:133
const char int mode
Definition ioapi.h:133
void ranrot_srand(uint32_t seed)