28#import "MyOpenGLView.h"
49#import <Sparkle/Sparkle.h>
54#elif (OOLITE_GNUSTEP && !defined(NDEBUG))
62@interface GameController (OOPrivate)
64- (void)reportUnhandledStartupException:(NSException *)exception;
88 [
NSException raise:NSInternalInconsistencyException format:@"%s: expected only one GameController to exist at a time.", __PRETTY_FUNCTION__];
91 if ((
self = [super
init]))
93 _finishedLaunching = NO;
100 ranrot_srand((uint32_t)[[NSDate date] timeIntervalSince1970]);
112 [[[
NSWorkspace sharedWorkspace] notificationCenter] removeObserver:UNIVERSE];
119 [playerFileToLoad release];
120 [playerFileDirectory release];
121 [expansionPathsToInclude release];
133- (void) setGamePaused:(BOOL)value
140 [PLAYER doScriptEvent:OOJSID("gamePaused")];
146 [PLAYER doScriptEvent:OOJSID("gameResumed")];
160 if (
mode == oldMode)
return;
165#if OO_USE_FULLSCREEN_CONTROLLER
180 [
self setMouseInteractionMode:[PLAYER isMouseControlOn] ? MOUSE_MODE_FLIGHT_WITH_MOUSE_CONTROL : MOUSE_MODE_FLIGHT_NO_MOUSE_CONTROL];
184- (void) setMouseInteractionModeForUIWithMouseInteraction:(BOOL)interaction
186 [
self setMouseInteractionMode:interaction ? MOUSE_MODE_UI_SCREEN_WITH_INTERACTION : MOUSE_MODE_UI_SCREEN_NO_INTERACTION];
201 [UNIVERSE setGameView:gameView];
205- (void) applicationDidFinishLaunching:(NSNotification *)notification
207 NSAutoreleasePool *pool =
nil;
217#if OO_OXP_VERIFIER_ENABLED
242 for (i = 0; i < [expansionPathsToInclude count]; i++)
253 [[
Universe alloc] initWithGameView:gameView];
264 @catch (NSException *exception)
270 OOLog(
@"startup.complete",
@"========== Loading complete in %.2f seconds. ==========", -[
_splashStart timeIntervalSinceNow]);
272#if OO_USE_FULLSCREEN_CONTROLLER
276 _finishedLaunching = YES;
289 return _finishedLaunching;
300 [UNIVERSE useGUILightSource:YES];
301 [UNIVERSE useGUILightSource:NO];
302 [PLAYER loadPlayerFromFile:playerFileToLoad asNew:NO];
325- (void) performGameTick:(
id)sender
333- (void) performGameTick:(
id)sender
335 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
337 [gameView pollControls];
338 [
self doPerformGameTick];
354 delta_t = [
NSDate timeIntervalSinceReferenceDate] - last_timeInterval;
355 last_timeInterval += delta_t;
360 [UNIVERSE update:delta_t];
363 [UNIVERSE reinitAndShowDemo:YES];
371 @catch (
id exception)
373 OOLog(
@"exception.backtrace",
@"%@",[exception callStackSymbols]);
380 @catch (
id exception) {}
390 timer = [[
NSTimer timerWithTimeInterval:ti target:
self selector:@selector(performGameTick:) userInfo:nil repeats:YES] retain];
392 [[
NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
394 [[
NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
418 [
gameView setVirtualJoystick:0.0 :0.0];
422- (IBAction) showLogAction:sender
424 [[
NSWorkspace sharedWorkspace] openFile:[OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:@"Previous.log"]];
428- (IBAction) showLogFolderAction:sender
430 [[
NSWorkspace sharedWorkspace] openFile:OOLogHandlerGetLogBasePath()];
437 id result = [[
NSUserDefaults standardUserDefaults] objectForKey:key];
438 if (expectedClass != Nil && ![result isKindOfClass:expectedClass]) result =
nil;
446 [[
NSUserDefaults standardUserDefaults] setObject:value forKey:key];
456#define kSnapshotsDirRefKey @"snapshots-directory-reference"
457#define kSnapshotsDirNameKey @"snapshots-directory-name"
459- (NSURL *) snapshotsURLCreatingIfNeeded:(BOOL)create
464 NSString *name =
DESC(
@"snapshots-directory-name-mac");
466 if (snapshotDirDict !=
nil)
471 NSString *existingName = [[
url path] lastPathComponent];
472 if ([existingName compare:name options:NSCaseInsensitiveSearch] != 0)
476 if (originalOldName ==
nil || [existingName compare:originalOldName options:NSCaseInsensitiveSearch] != 0)
483 Boolean inTrash =
false;
484 const UInt8 *utfPath = (
const UInt8 *)[[url path] UTF8String];
486 OSStatus err = DetermineIfPathIsEnclosedByFolder(kOnAppropriateDisk, kTrashFolderType, utfPath,
false, &inTrash);
488 if (err == noErr && inTrash ==
true) url =
nil;
494 NSString *path =
nil;
495 NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
496 if ([searchPaths
count] > 0)
498 path = [[
searchPaths objectAtIndex:0] stringByAppendingPathComponent:name];
500 url = [
NSURL fileURLWithPath:path];
508 if (![fmgr fileExistsAtPath:path])
510 [
fmgr oo_createDirectoryAtPath:path attributes:nil];
519 if (snapshotDirDict !=
nil)
534- (IBAction) showSnapshotsAction:sender
540- (IBAction) showAddOnsAction:sender
545 for (NSString *path in paths) {
546 if ([
self addOnsExistAtPath:path]) {
553 for (NSString *path in paths) {
554 if ([
self isDirectoryAtPath:path]) {
562 withIntermediateDirectories:YES
569- (BOOL) isDirectoryAtPath:(NSString *)path
576- (BOOL) addOnsExistAtPath:(NSString *)path
578 if (![
self isDirectoryAtPath:path])
return NO;
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;
591- (void) openPath:(NSString *)path
597- (BOOL) validateMenuItem:(NSMenuItem *)menuItem
599 SEL action = menuItem.action;
601 if (action ==
@selector(showLogAction:))
604 return ([[NSFileManager defaultManager] fileExistsAtPath:[
OOLogHandlerGetLogBasePath() stringByAppendingPathComponent:
@"Previous.log"]]);
607 if (action ==
@selector(showAddOnsAction:))
613 if (action ==
@selector(showSnapshotsAction:))
615 BOOL pathIsDirectory;
616 if(![[NSFileManager defaultManager] fileExistsAtPath:[
self snapshotsURLCreatingIfNeeded:NO].path isDirectory:&pathIsDirectory])
620 return pathIsDirectory;
623 if (action ==
@selector(toggleFullScreenAction:))
628 menuItem.title = NSLocalizedString(
@"Exit Full Screen", NULL);
632 menuItem.title = NSLocalizedString(
@"Enter Full Screen", NULL);
641- (NSMenu *)applicationDockMenu:(NSApplication *)sender
648- (NSURL *) snapshotsURLCreatingIfNeeded:(BOOL)create
650 NSURL *url = [NSURL fileURLWithPath:[NSHomeDirectory() stringByAppendingPathComponent:DESC(@"snapshots-directory-name")]];
654 NSString *path = [url path];
655 NSFileManager *fmgr = [NSFileManager defaultManager];
656 if (![fmgr fileExistsAtPath:path])
658 [fmgr oo_createDirectoryAtPath:path attributes:nil];
665 #error Unknown environment!
668- (void) logProgress:(NSString *)message
670 if (![
UNIVERSE doingStartUp])
return;
673 [splashProgressTextField setStringValue:message];
674 [splashProgressTextField display];
676 if([message length] > 0)
678 OOLog(
@"startup.progress",
@"===== [%.2f s] %@", -[
_splashStart timeIntervalSinceNow], message);
685- (BOOL) debugMessageTrackingIsOn
687 return splashProgressTextField !=
nil;
691- (NSString *) debugMessageCurrentString
693 return [splashProgressTextField stringValue];
696- (BOOL) debugMessageTrackingIsOn
702- (NSString *) debugMessageCurrentString
708- (void) debugLogProgress:(NSString *)format, ...
711 va_start(args, format);
712 [
self debugLogProgress:format arguments:args];
717- (void) debugLogProgress:(NSString *)format arguments:(va_list)arguments
719 NSString *message = [[[NSString alloc] initWithFormat:format arguments:arguments] autorelease];
720 [
self logProgress:message];
724static NSMutableArray *sMessageStack;
726- (void) debugPushProgressMessage:(NSString *)format, ...
728 if ([
self debugMessageTrackingIsOn])
730 if (sMessageStack ==
nil) sMessageStack = [[NSMutableArray alloc] init];
731 [sMessageStack addObject:[
self debugMessageCurrentString]];
734 va_start(args, format);
735 [
self debugLogProgress:format arguments:args];
743- (void) debugPopProgressMessage
747 if ([sMessageStack
count] > 0)
749 NSString *message = [sMessageStack lastObject];
750 if ([message length] > 0) [
self logProgress:message];
751 [sMessageStack removeLastObject];
781 NSString *path =
nil;
784 path = [[
NSBundle mainBundle] pathForResource:@"OoliteReadMe" ofType:@"pdf"];
787 PDFDocument *document = [[
PDFDocument alloc] initWithURL:[
NSURL fileURLWithPath:path]];
796- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
798 if ([[
filename pathExtension] isEqual:
@"oolite-save"])
804 if ([[
filename pathExtension] isEqualToString:
@"oxp"])
807 [[
NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&dir_test];
814 [expansionPathsToInclude addObject:filename];
822- (void) exitAppWithContext:(NSString *)context
826 [
NSApp terminate:
self];
830- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
834 return NSTerminateNow;
839- (void) exitAppWithContext:(NSString *)context
841 OOLog(
@"exit.context",
@"Exiting: %@.", context);
842#if (OOLITE_GNUSTEP && !defined(NDEBUG))
848 if (![gameView atDesktopResolution])
850 OOLog(
@"gameController.exitApp",
@"%@",
@"Restoring desktop resolution.");
851 ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
854 [[NSUserDefaults standardUserDefaults] synchronize];
855 OOLog(
@"gameController.exitApp",
@"%@",
@".GNUstepDefaults synchronized.");
863 #error Unknown environment!
873- (void)windowDidResize:(NSNotification *)aNotification
885- (void) setPlayerFileToLoad:(NSString *)filename
888 [playerFileToLoad autorelease];
890 if ([[[
filename pathExtension] lowercaseString] isEqual:
@"oolite-save"])
906 [playerFileDirectory retain];
913- (void) setPlayerFileDirectory:(NSString *)filename
917 [playerFileDirectory autorelease];
921 if ([[[
filename pathExtension] lowercaseString] isEqual:
@"oolite-save"])
923 filename = [filename stringByDeletingLastPathComponent];
927 [[
NSUserDefaults standardUserDefaults] setObject:filename forKey:@"save-directory"];
931- (void)reportUnhandledStartupException:(NSException *)exception
933 OOLog(
@"startup.exception",
@"***** Unhandled exception during startup: %@ (%@).", [exception name], [exception reason]);
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]);
943- (void)setUpBasicOpenGLStateWithSize:(NSSize)viewSize
948 float aspect = viewSize.height/viewSize.width;
950 OOGL(glClearColor(0.0, 0.0, 0.0, 0.0));
951 OOGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
953 OOGL(glClearDepth(1.0));
954 OOGL(glViewport(0, 0, viewSize.width, viewSize.height));
959 OOGL(glDepthFunc(GL_LESS));
963 [UNIVERSE setLighting];
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};
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));
979 if ([extMgr usePointSmoothing])
OOGL(glEnable(GL_POINT_SMOOTH));
980 if ([extMgr useLineSmoothing])
OOGL(glEnable(GL_LINE_SMOOTH));
983#if GL_APPLE_transform_hint
984 if ([extMgr haveExtension:
@"GL_APPLE_transform_hint"])
986 OOGL(glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST));
990 OOGL(glDisable(GL_NORMALIZE));
991 OOGL(glDisable(GL_RESCALE_NORMAL));
995 if ([extMgr versionIsAtLeastMajor:1 minor:2])
997 OOGL(glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR));
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"
1025#define TEST_RELEASE_FEED_URL (@ FEED_URL_BASE TEST_RELEASE_FEED_NAME)
1026#define DEPLOYMENT_FEED_URL (@ FEED_URL_BASE DEPLOYMENT_FEED_NAME)
1030#define DEFAULT_TEST_RELEASE 0
1032#define DEFAULT_TEST_RELEASE 1
1035 BOOL useTestReleases = [[NSUserDefaults standardUserDefaults] oo_boolForKey:@"use-test-release-updates"
1036 defaultValue:DEFAULT_TEST_RELEASE];
1038 SUUpdater *updater = [SUUpdater sharedUpdater];
1039 [updater setFeedURL:[NSURL URLWithString:useTestReleases ? TEST_RELEASE_FEED_URL : DEPLOYMENT_FEED_URL]];
#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)
void OOJSFrameCallbacksInvoke(OOTimeDelta delta)
NSString * OOLogHandlerGetLogBasePath(void)
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
#define OOLogOutdentIf(class)
#define OOLog(class, format,...)
#define OOLogIndentIf(class)
void OOLoggingTerminate(void)
void OOLogSetDisplayMessagesInClass(NSString *inClass, BOOL inFlag)
NSString * OOStringFromMouseInteractionMode(OOMouseInteractionMode mode)
void OOGLFrustum(double left, double right, double bottom, double top, double near, double far)
void OOGLResetProjection(void)
void setMouseInteractionMode:(OOMouseInteractionMode mode)
void setMouseInteractionModeForUIWithMouseInteraction:(BOOL interaction)
IBOutlet NSTextField * splashProgressTextField
static id GetPreference(NSString *key, Class expectedClass)
OOMouseInteractionMode mouseInteractionMode()
NSString * playerFileToLoad
BOOL suppressClangStuff()
GameController * sharedController()
NSMutableArray * expansionPathsToInclude
OOMouseInteractionMode _resumeMode
NSTimeInterval last_timeInterval
void recenterVirtualJoystick()
NSString * playerFileDirectory
void stopAnimationTimer()
void reportUnhandledStartupException:(NSException *exception)
void openPath:(NSString *path)
void logProgress:(NSString *message)
NSTimeInterval _animationTimerInterval
void exitAppWithContext:(NSString *context)
static void SetPreference(NSString *key, id value)
OOMouseInteractionMode _mouseMode
void setPlayerFileDirectory:(NSString *filename)
void setMouseInteractionModeForFlight()
void startAnimationTimer()
void setFullScreenMode:(BOOL value)
NSURL * snapshotsURLCreatingIfNeeded:(BOOL create)
IBOutlet MyOpenGLView * gameView
void loadPlayerIfRequired()
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 setGameController:(GameController *controller)
void finishOngoingFlush()
OOCacheManager * sharedCache()
OODebugMonitor * sharedDebugMonitor()
void noteMouseInteractionModeChangedFrom:to:(OOMouseInteractionMode oldMode,[to] OOMouseInteractionMode newMode)
BOOL setStickHandlerClass:(Class aClass)
OOOXZManager * sharedManager()
OOOpenALController * sharedController()
OOOpenGLExtensionManager * sharedManager()
void setExitContext:(NSString *exitContext)
void addExternalPath:(NSString *fileName)
NSArray * userRootPaths()
void ranrot_srand(uint32_t seed)