LCOV - code coverage report
Current view: top level - Core - GameController.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 29 0.0 %
Date: 2026-01-23 10:53:51 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : GameController.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2013 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 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"
      31             : #import "PlayerEntityLoadSave.h"
      32             : #include <stdlib.h>
      33             : #import "OOCollectionExtractors.h"
      34             : #import "OOOXPVerifier.h"
      35             : #import "OOLoggingExtended.h"
      36             : #import "NSFileManagerOOExtensions.h"
      37             : #import "OOLogOutputHandler.h"
      38             : #import "OODebugFlags.h"
      39             : #import "OOJSFrameCallbacks.h"
      40             : #import "OOOpenGLExtensionManager.h"
      41             : #import "OOOpenALController.h"
      42             : #import "OODebugSupport.h"
      43             : #import "legacy_random.h"
      44             : #import "OOOXZManager.h"
      45             : #import "OOOpenGLMatrixManager.h"
      46             : 
      47             : #if OOLITE_MAC_OS_X
      48             : #import "JAPersistentFileReference.h"
      49             : #import <Sparkle/Sparkle.h>
      50             : #import "OoliteApp.h"
      51             : #import "OOMacJoystickManager.h"
      52             : 
      53             : static void SetUpSparkle(void);
      54             : #elif (OOLITE_GNUSTEP && !defined(NDEBUG))
      55             : #import "OODebugMonitor.h"
      56             : #endif
      57             : 
      58             : 
      59           0 : static GameController *sSharedController = nil;
      60             : 
      61             : 
      62             : @interface GameController (OOPrivate)
      63             : 
      64           0 : - (void)reportUnhandledStartupException:(NSException *)exception;
      65             : 
      66           0 : - (void)doPerformGameTick;
      67             : 
      68             : @end
      69             : 
      70             : 
      71             : @implementation GameController
      72             : 
      73             : + (GameController *) sharedController
      74             : {
      75             :         if (sSharedController == nil)
      76             :         {
      77             :                 sSharedController = [[self alloc] init];
      78             :         }
      79             :         return sSharedController;
      80             : }
      81             : 
      82             : 
      83           0 : - (id) init
      84             : {
      85             :         if (sSharedController != nil)
      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           0 : - (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             : 
     127             : - (BOOL) isGamePaused
     128             : {
     129             :         return gameIsPaused;
     130             : }
     131             : 
     132             : 
     133             : - (void) setGamePaused:(BOOL)value
     134             : {
     135             :         if (value && !gameIsPaused)
     136             :         {
     137             :                 _resumeMode = [self mouseInteractionMode];
     138             :                 [self setMouseInteractionModeForUIWithMouseInteraction:NO];
     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             : 
     151             : - (OOMouseInteractionMode) mouseInteractionMode
     152             : {
     153             :         return _mouseMode;
     154             : }
     155             : 
     156             : 
     157             : - (void) setMouseInteractionMode:(OOMouseInteractionMode)mode
     158             : {
     159             :         OOMouseInteractionMode oldMode = _mouseMode;
     160             :         if (mode == oldMode)  return;
     161             :         
     162             :         _mouseMode = mode;
     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             :         {
     168             :                 [_fullScreenController noteMouseInteractionModeChangedFrom:oldMode to:mode];
     169             :         }
     170             :         else
     171             : #endif
     172             :         {
     173             :                 [[self gameView] noteMouseInteractionModeChangedFrom:oldMode to:mode];
     174             :         }
     175             : }
     176             : 
     177             : 
     178             : - (void) setMouseInteractionModeForFlight
     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             : 
     190             : - (MyOpenGLView *) gameView
     191             : {
     192             :         return gameView;
     193             : }
     194             : 
     195             : 
     196             : - (void) setGameView:(MyOpenGLView *)view
     197             : {
     198             :         [gameView release];
     199             :         gameView = [view retain];
     200             :         [gameView setGameController:self];
     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
     233             :                 [OOJoystickManager setStickHandlerClass:[OOMacJoystickManager class]];
     234             :                 SetUpSparkle();
     235             : #endif
     236             :                 
     237             :                 [self setUpDisplayModes];
     238             :                 
     239             :                 // moved to before the Universe is created
     240             :                 if (expansionPathsToInclude)
     241             :                 {
     242             :                         for (i = 0; i < [expansionPathsToInclude count]; i++)
     243             :                         {
     244             :                                 [ResourceManager addExternalPath: (NSString*)[expansionPathsToInclude objectAtIndex: i]];
     245             :                         }
     246             :                 }
     247             :                 
     248             :                 // initialise OXZ manager
     249             :                 [OOOXZManager sharedManager];
     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             :                 
     255             :                 [self loadPlayerIfRequired];
     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             : 
     287             : - (BOOL) finishedLaunching
     288             : {
     289             :         return _finishedLaunching;
     290             : }
     291             : 
     292             : 
     293             : - (void) loadPlayerIfRequired
     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             : 
     307             : - (void) beginSplashScreen
     308             : {
     309             : #if !OOLITE_MAC_OS_X
     310             :         if(!gameView)
     311             :         {
     312             :                 gameView = [MyOpenGLView alloc];
     313             :                 [gameView init];
     314             :                 [gameView setGameController:self];
     315             :                 [gameView initSplashScreen];
     316             :         }
     317             : #else
     318             :         [gameView updateScreen];
     319             : #endif
     320             : }
     321             : 
     322             : 
     323             : #if OOLITE_MAC_OS_X
     324             : 
     325             : - (void) performGameTick:(id)sender
     326             : {
     327             :         [gameView pollControls];
     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             : 
     346           0 : - (void) doPerformGameTick
     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             :                 {
     368             :                         OOJSFrameCallbacksInvoke(delta_t);
     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             : 
     384             : - (void) startAnimationTimer
     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             : 
     401             : - (void) stopAnimationTimer
     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             : 
     414             : - (void) recenterVirtualJoystick
     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.
     435           0 : static 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             : 
     444           0 : static void SetPreference(NSString *key, id value)
     445             : {
     446             :         [[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
     447             : }
     448             : 
     449             : 
     450           0 : static void RemovePreference(NSString *key)
     451             : {
     452             :         [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
     453             : }
     454             : 
     455             : 
     456           0 : #define kSnapshotsDirRefKey             @"snapshots-directory-reference"
     457           0 : #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             :         {
     468             :                 url = JAURLFromPersistentFileReference(snapshotDirDict, kJAPersistentFileReferenceWithoutUI | kJAPersistentFileReferenceWithoutMounting, &stale);
     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             :                 {
     526             :                         RemovePreference(kSnapshotsDirRefKey);
     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           0 : - (BOOL) isDirectoryAtPath:(NSString *)path
     570             : {
     571             :         BOOL isDirectory;
     572             :         return [NSFileManager.defaultManager fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory;
     573             : }
     574             : 
     575             : 
     576           0 : - (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           0 : - (void) openPath:(NSString *)path
     592             : {
     593             :         [NSWorkspace.sharedWorkspace openURL:[NSURL fileURLWithPath:path]];
     594             : }
     595             : 
     596             : 
     597           0 : - (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           0 : - (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             : 
     724             : static 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             : 
     758             : - (void) endSplashScreen
     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.
     764             :         splashProgressTextField = nil;
     765             :         splashView = nil;
     766             :         
     767             :         [gameWindow setAcceptsMouseMovedEvents:YES];
     768             :         [gameWindow setContentView:gameView];
     769             :         [gameWindow makeFirstResponder:gameView];
     770             : #elif OOLITE_SDL
     771             :         [gameView endSplashScreen];
     772             : #endif
     773             : }
     774             : 
     775             : 
     776             : #if OOLITE_MAC_OS_X
     777             : 
     778             : // NIB methods
     779           0 : - (void)awakeFromNib
     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           0 : - (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             :                 {
     810             :                         if (expansionPathsToInclude == nil)
     811             :                         {
     812             :                                 expansionPathsToInclude = [[NSMutableArray alloc] init];
     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           0 : - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
     831             : {
     832             :         [[OOCacheManager sharedCache] finishOngoingFlush];
     833             :         OOLoggingTerminate();
     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.");
     856             :         OOLoggingTerminate();
     857             :         SDL_Quit();
     858             :         [[OOOpenALController sharedController] shutdown];
     859             :         exit(0);
     860             : }
     861             : 
     862             : #else
     863             :         #error Unknown environment!
     864             : #endif
     865             : 
     866             : 
     867             : - (void) exitAppCommandQ
     868             : {
     869             :         [self exitAppWithContext:@"Command-Q"];
     870             : }
     871             : 
     872             : 
     873             : - (void)windowDidResize:(NSNotification *)aNotification
     874             : {
     875             :         [gameView updateScreen];
     876             : }
     877             : 
     878             : 
     879             : - (NSString *) playerFileToLoad
     880             : {
     881             :         return playerFileToLoad;
     882             : }
     883             : 
     884             : 
     885             : - (void) setPlayerFileToLoad:(NSString *)filename
     886             : {
     887             :         if (playerFileToLoad)
     888             :                 [playerFileToLoad autorelease];
     889             :         playerFileToLoad = nil;
     890             :         if ([[[filename pathExtension] lowercaseString] isEqual:@"oolite-save"])
     891             :                 playerFileToLoad = [filename copy];
     892             : }
     893             : 
     894             : 
     895             : - (NSString *) playerFileDirectory
     896             : {
     897             :         if (playerFileDirectory == nil)
     898             :         {
     899             :                 playerFileDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"save-directory"];
     900             :                 if (playerFileDirectory != nil && ![[NSFileManager defaultManager] fileExistsAtPath:playerFileDirectory])
     901             :                 {
     902             :                         playerFileDirectory = nil;
     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             : {       
     915             :         if (playerFileDirectory != nil)
     916             :         {
     917             :                 [playerFileDirectory autorelease];
     918             :                 playerFileDirectory = nil;
     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           0 : - (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             : {
     945             :         OOOpenGLExtensionManager        *extMgr = [OOOpenGLExtensionManager sharedManager];
     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             : */
    1007           0 : - (BOOL) suppressClangStuff
    1008             : {
    1009             :         return pauseSelector &&
    1010             :         pauseTarget;
    1011             : }
    1012             : #endif
    1013             : 
    1014             : @end
    1015             : 
    1016             : 
    1017             : #if OOLITE_MAC_OS_X
    1018             : 
    1019           0 : static void SetUpSparkle(void)
    1020             : {
    1021           0 : #define FEED_URL_BASE                   "http://www.oolite.org/updates/"
    1022           0 : #define TEST_RELEASE_FEED_NAME  "oolite-mac-test-release-appcast.xml"
    1023           0 : #define DEPLOYMENT_FEED_NAME    "oolite-mac-appcast.xml"
    1024             : 
    1025           0 : #define TEST_RELEASE_FEED_URL   (@ FEED_URL_BASE TEST_RELEASE_FEED_NAME)
    1026           0 : #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           0 : #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

Generated by: LCOV version 1.14