restore displaying statistics at the end of a game and restore warning lower views that they are going to appear
authorkoda
Sun, 13 Nov 2011 18:23:05 +0100 (2011-11-13)
changeset 6353 d8f62c805619
parent 6352 2448f5390bd5
child 6355 734fed7aefd3
restore displaying statistics at the end of a game and restore warning lower views that they are going to appear
project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h
project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m
project_files/HedgewarsMobile/Classes/GameConfigViewController.m
project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h
project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m
project_files/HedgewarsMobile/Classes/HWUtils.h
project_files/HedgewarsMobile/Classes/MainMenuViewController.m
project_files/HedgewarsMobile/Classes/MissionTrainingViewController.m
project_files/HedgewarsMobile/Classes/RestoreViewController.m
project_files/HedgewarsMobile/Classes/SavedGamesViewController.m
--- a/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h	Sun Nov 13 18:23:05 2011 +0100
@@ -22,21 +22,15 @@
 #import <Foundation/Foundation.h>
 #import "SDL_net.h"
 
-@protocol EngineProtocolDelegate <NSObject>
-
--(void) gameHasEndedWithStats:(NSArray *)stats;
-
-@end
 
 @interface EngineProtocolNetwork : NSObject {
-    id<EngineProtocolDelegate> delegate;
-
+    NSArray *statsArray;
     NSOutputStream *stream;
     TCPsocket csd;
     NSInteger enginePort;
 }
 
-@property (nonatomic,assign) id<EngineProtocolDelegate> delegate;
+@property (nonatomic,assign) NSArray *statsArray;
 @property (nonatomic,retain) NSOutputStream *stream;
 @property (assign) TCPsocket csd;
 @property (assign) NSInteger enginePort;
@@ -44,11 +38,10 @@
 
 -(id)   init;
 
-+(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary;
+-(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary;
 +(NSInteger) activeEnginePort;
 
 -(void) engineProtocol:(id) object;
--(void) gameHasEndedWithStats:(NSArray *)stats;
 
 -(int)  sendToEngine:(NSString *)string;
 -(int)  sendToEngineNoSave:(NSString *)string;
--- a/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m	Sun Nov 13 18:23:05 2011 +0100
@@ -28,12 +28,11 @@
 static NSInteger activeEnginePort;
 
 @implementation EngineProtocolNetwork
-@synthesize delegate, stream, csd, enginePort;
+@synthesize statsArray, stream, csd, enginePort;
 
 -(id) init {
     if (self = [super init]) {
-        self.delegate = nil;
-
+        self.statsArray = nil;
         self.csd = NULL;
         self.stream = nil;
         self.enginePort = [HWUtils randomPort];
@@ -42,31 +41,22 @@
     return self;
 }
 
--(void) gameHasEndedWithStats:(NSArray *)stats {
-    if (self.delegate != nil && [self.delegate respondsToSelector:@selector(gameHasEndedWithStats:)])
-        [self.delegate gameHasEndedWithStats:stats];
-    else
-        DLog(@"Error! delegate == nil");
-}
-
 -(void) dealloc {
-    self.delegate = nil;
+    releaseAndNil(statsArray);
     releaseAndNil(stream);
     [super dealloc];
 }
 
 #pragma mark -
 #pragma mark Spawner functions
-+(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
-    id proto = [[self alloc] init];
-    [proto setStream: (onSaveFile) ? [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES] : nil];
-    [[proto stream] open];
+-(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
+    self.stream = (onSaveFile) ? [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES] : nil;
+    [self.stream open];
 
     // +detachNewThreadSelector retain/release self automatically
     [NSThread detachNewThreadSelector:@selector(engineProtocol:)
-                             toTarget:proto
+                             toTarget:self
                            withObject:dictionary];
-    [proto release];
 }
 
 +(NSInteger) activeEnginePort {
@@ -232,7 +222,7 @@
 -(void) engineProtocol:(id) object {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     NSDictionary *gameConfig = (NSDictionary *)object;
-    NSMutableArray *statsArray = nil;
+    NSMutableArray *tempStats = nil;
     TCPsocket sd;
     IPaddress ip;
     int eProto;
@@ -347,10 +337,10 @@
                 }
                 break;
             case 'i':
-                if (statsArray == nil) {
-                    statsArray = [[NSMutableArray alloc] initWithCapacity:10 - 2];
+                if (tempStats == nil) {
+                    tempStats = [[NSMutableArray alloc] initWithCapacity:10 - 2];
                     NSMutableArray *ranking = [[NSMutableArray alloc] initWithCapacity:4];
-                    [statsArray insertObject:ranking atIndex:0];
+                    [tempStats insertObject:ranking atIndex:0];
                     [ranking release];
                 }
                 NSString *tempStr = [NSString stringWithUTF8String:&buffer[2]];
@@ -359,16 +349,16 @@
                 int index = [arg length] + 3;
                 switch (buffer[1]) {
                     case 'r':           // winning team
-                        [statsArray insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1];
+                        [tempStats insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1];
                         break;
                     case 'D':           // best shot
-                        [statsArray addObject:[NSString stringWithFormat:@"The best shot award won by %s (with %@ points)", &buffer[index], arg]];
+                        [tempStats addObject:[NSString stringWithFormat:@"The best shot award won by %s (with %@ points)", &buffer[index], arg]];
                         break;
                     case 'k':           // best hedgehog
-                        [statsArray addObject:[NSString stringWithFormat:@"The best killer is %s with %@ kills in a turn", &buffer[index], arg]];
+                        [tempStats addObject:[NSString stringWithFormat:@"The best killer is %s with %@ kills in a turn", &buffer[index], arg]];
                         break;
                     case 'K':           // number of hogs killed
-                        [statsArray addObject:[NSString stringWithFormat:@"%@ hedgehog(s) were killed during this round", arg]];
+                        [tempStats addObject:[NSString stringWithFormat:@"%@ hedgehog(s) were killed during this round", arg]];
                         break;
                     case 'H':           // team health/graph
                         break;
@@ -376,16 +366,16 @@
                         // still WIP in statsPage.cpp
                         break;
                     case 'P':           // teams ranking
-                        [[statsArray objectAtIndex:0] addObject:tempStr];
+                        [[tempStats objectAtIndex:0] addObject:tempStr];
                         break;
                     case 's':           // self damage
-                        [statsArray addObject:[NSString stringWithFormat:@"%s thought it's good to shoot his own hedgehogs with %@ points", &buffer[index], arg]];
+                        [tempStats addObject:[NSString stringWithFormat:@"%s thought it's good to shoot his own hedgehogs with %@ points", &buffer[index], arg]];
                         break;
                     case 'S':           // friendly fire
-                        [statsArray addObject:[NSString stringWithFormat:@"%s killed %@ of his own hedgehogs", &buffer[index], arg]];
+                        [tempStats addObject:[NSString stringWithFormat:@"%s killed %@ of his own hedgehogs", &buffer[index], arg]];
                         break;
                     case 'B':           // turn skipped
-                        [statsArray addObject:[NSString stringWithFormat:@"%s was scared and skipped turn %@ times", &buffer[index], arg]];
+                        [tempStats addObject:[NSString stringWithFormat:@"%s was scared and skipped turn %@ times", &buffer[index], arg]];
                         break;
                     default:
                         DLog(@"Unhandled stat message, see statsPage.cpp");
@@ -393,12 +383,15 @@
                 }
                 break;
             case 'q':
-                // game ended, can remove the savefile and present the statistics of the match
+                // game ended and match finished, statsArray is full of delicious statistics
                 [HWUtils setGameStatus:gsEnded];
-                [self gameHasEndedWithStats:statsArray];
+                self.statsArray = [[NSArray arrayWithArray:tempStats] retain];
+                // closing connection here would trigger a "IPC connection lost" error, so we have to wait until recv fails
                 break;
             case 'Q':
-                // game exited but not completed, nothing to do (just don't save the message)
+                // game exited but not completed, skip this message in the savefile
+                [HWUtils setGameStatus:gsInterrupted];
+                // same here, don't set clientQuit to YES
                 break;
             default:
                 [self dumpRawData:buffer ofSize:msgSize];
@@ -406,9 +399,10 @@
         }
     }
     DLog(@"Engine exited, ending thread");
+
     [self.stream close];
     [self.stream release];
-    [statsArray release];
+    [tempStats release];
 
     // Close the client socket
     SDLNet_TCP_Close(csd);
--- a/project_files/HedgewarsMobile/Classes/GameConfigViewController.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/GameConfigViewController.m	Sun Nov 13 18:23:05 2011 +0100
@@ -223,6 +223,7 @@
                                     script,@"mission_command",
                                     nil];
 
+    [GameInterfaceBridge registerCallingController:self];
     [GameInterfaceBridge startLocalGame:gameDictionary];
     [gameDictionary release];
 }
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h	Sun Nov 13 18:23:05 2011 +0100
@@ -21,15 +21,22 @@
 
 #import <Foundation/Foundation.h>
 
+@class EngineProtocolNetwork;
 
 @interface GameInterfaceBridge : NSObject {
     UIView *blackView;
+    NSString *savePath;
+    EngineProtocolNetwork *proto;
 }
 
 @property (nonatomic,retain) UIView *blackView;
+@property (nonatomic,retain) NSString *savePath;
+@property (nonatomic,retain) EngineProtocolNetwork *proto;
 
 +(void) startLocalGame:(NSDictionary *)withOptions;
 +(void) startSaveGame:(NSString *)atPath;
 +(void) startMissionGame:(NSString *)withScript;
 
++(void) registerCallingController:(UIViewController *)controller;
+
 @end
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m	Sun Nov 13 18:23:05 2011 +0100
@@ -26,16 +26,22 @@
 #import "AudioManagerController.h"
 #import "ObjcExports.h"
 
+static UIViewController *callingController;
+
 @implementation GameInterfaceBridge
-@synthesize blackView;
+@synthesize blackView, savePath, proto;
 
 #pragma mark -
 #pragma mark Instance methods for engine interaction
 // prepares the controllers for hosting a game
--(void) earlyEngineLaunch:(NSString *)pathOrNil withOptions:(NSDictionary *)optionsOrNil {
+-(void) earlyEngineLaunch:(NSDictionary *)optionsOrNil {
     [self retain];
     [AudioManagerController stopBackgroundMusic];
-    [EngineProtocolNetwork spawnThread:pathOrNil withOptions:optionsOrNil];
+
+    EngineProtocolNetwork *engineProtocol = [[EngineProtocolNetwork alloc] init];
+    self.proto = engineProtocol;
+    [engineProtocol release];
+    [self.proto spawnThread:self.savePath withOptions:optionsOrNil];
 
     // add a black view hiding the background
     CGRect theFrame = [[UIScreen mainScreen] bounds];
@@ -53,15 +59,19 @@
 
     // keep track of uncompleted games
     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
-    [userDefaults setObject:pathOrNil forKey:@"savedGamePath"];
+    [userDefaults setObject:self.savePath forKey:@"savedGamePath"];
     [userDefaults synchronize];
 
     // let's launch the engine using this -perfomSelector so that the runloop can deal with queued messages first
-    [self performSelector:@selector(engineLaunch:) withObject:pathOrNil afterDelay:0.1f];
+    [self performSelector:@selector(engineLaunch) withObject:nil afterDelay:0.1f];
 }
 
 // cleans up everything
 -(void) lateEngineLaunch {
+    // notify views below that they are getting the spotlight again
+    [[[HedgewarsAppDelegate sharedAppDelegate] uiwindow] makeKeyAndVisible];
+    [callingController viewWillAppear:YES];
+
     // remove completed games notification
     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
     [userDefaults setObject:@"" forKey:@"savedGamePath"];
@@ -78,16 +88,36 @@
     // the overlay is not needed any more and can be removed
     [[OverlayViewController mainOverlay] removeOverlay];
 
+    // engine thread *should* be done by now
+    NSArray *stats = self.proto.statsArray;
+    if (stats != nil) {
+        StatsPageViewController *statsPage = [[StatsPageViewController alloc] initWithStyle:UITableViewStyleGrouped];
+        statsPage.statsArray = stats;
+        statsPage.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
+        if ([statsPage respondsToSelector:@selector(setModalPresentationStyle:)])
+            statsPage.modalPresentationStyle = UIModalPresentationPageSheet;
+
+        [callingController presentModalViewController:statsPage animated:YES];
+        [statsPage release];
+    }
+    [stats release];    // we retained the array before
+
+    // can remove the savefile if the replay has ended
+    if ([HWUtils gameType] == gtSave)
+        [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
+
     // restart music and we're done
     [AudioManagerController playBackgroundMusic];
+    [HWUtils setGameStatus:gsNone];
+    [HWUtils setGameType:gtNone];
     [self release];
 }
 
 // main routine for calling the actual game engine
--(void) engineLaunch:(NSString *)pathOrNil {
+-(void) engineLaunch {
     const char *gameArgs[11];
     CGFloat width, height;
-    NSInteger enginePort = [EngineProtocolNetwork activeEnginePort];
+    NSInteger enginePort = self.proto.enginePort;
     CGFloat screenScale = [[UIScreen mainScreen] safeScale];
     NSString *ipcString = [[NSString alloc] initWithFormat:@"%d",enginePort];
     NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt",[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
@@ -139,7 +169,7 @@
     gameArgs[ 7] = [[[settings objectForKey:@"music"] stringValue] UTF8String];                 //isMusicEnabled
     gameArgs[ 8] = [[[settings objectForKey:@"alternate"] stringValue] UTF8String];             //cAltDamage
     gameArgs[ 9] = [rotation UTF8String];                                                       //rotateQt
-    gameArgs[10] = ([HWUtils gameType] == gtSave) ? [pathOrNil UTF8String] : NULL;              //recordFileName
+    gameArgs[10] = ([HWUtils gameType] == gtSave) ? [self.savePath UTF8String] : NULL;          //recordFileName
 
     [verticalSize release];
     [horizontalSize release];
@@ -154,12 +184,24 @@
     [self lateEngineLaunch];
 }
 
+-(void) dealloc {
+    releaseAndNil(blackView);
+    releaseAndNil(savePath);
+    releaseAndNil(proto);
+    [super dealloc];
+}
+
 #pragma mark -
 #pragma mark Class methods for setting up the engine from outsite
++(void) registerCallingController:(UIViewController *)controller {
+    callingController = controller;
+}
+
 +(void) startGame:(TGameType) type atPath:(NSString *)path withOptions:(NSDictionary *)config {
     [HWUtils setGameType:type];
     id bridge = [[self alloc] init];
-    [bridge earlyEngineLaunch:path withOptions:config];
+    [bridge setSavePath:path];
+    [bridge earlyEngineLaunch:config];
     [bridge release];
 }
 
@@ -190,27 +232,5 @@
     [missionLine release];
 }
 
-/*
--(void) gameHasEndedWithStats:(NSArray *)stats {
-    // wrap this around a retain/realse to prevent being deallocated too soon
-    [self retain];
-    // display stats page if there is something to display
-    if (stats != nil) {
-        StatsPageViewController *statsPage = [[StatsPageViewController alloc] initWithStyle:UITableViewStyleGrouped];
-        statsPage.statsArray = stats;
-        statsPage.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
-        if ([statsPage respondsToSelector:@selector(setModalPresentationStyle:)])
-            statsPage.modalPresentationStyle = UIModalPresentationPageSheet;
-
-        [self.parentController presentModalViewController:statsPage animated:YES];
-        [statsPage release];
-    }
-
-    // can remove the savefile if the replay has ended
-    if ([HWUtils gameType] == gtSave)
-        [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
-    [self release];
-}
-*/
 
 @end
--- a/project_files/HedgewarsMobile/Classes/HWUtils.h	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/HWUtils.h	Sun Nov 13 18:23:05 2011 +0100
@@ -22,7 +22,7 @@
 #import <Foundation/Foundation.h>
 
 typedef enum {gtNone, gtLocal, gtSave, gtMission, gtNet} TGameType;
-typedef enum {gsNone, gsLoading, gsInGame, gsEnded} TGameStatus;
+typedef enum {gsNone, gsLoading, gsInGame, gsInterrupted, gsEnded} TGameStatus;
 
 @interface HWUtils : NSObject {
 
--- a/project_files/HedgewarsMobile/Classes/MainMenuViewController.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/MainMenuViewController.m	Sun Nov 13 18:23:05 2011 +0100
@@ -27,7 +27,6 @@
 #import "SavedGamesViewController.h"
 #import "RestoreViewController.h"
 #import "MissionTrainingViewController.h"
-#import "GameInterfaceBridge.h"
 #import "Appirater.h"
 #import "ServerProtocolNetwork.h"
 
@@ -114,7 +113,6 @@
     // prompt for restoring any previous game
     NSString *saveString = [userDefaults objectForKey:@"savedGamePath"];
     if (saveString != nil && [saveString isEqualToString:@""] == NO) {
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(launchRestoredGame) name:@"launchRestoredGame" object:nil];
         if (self.restoreViewController == nil) {
             NSString *xibName = [@"RestoreViewController-" stringByAppendingString:(IS_IPAD() ? @"iPad" : @"iPhone")];
             RestoreViewController *restored = [[RestoreViewController alloc] initWithNibName:xibName bundle:nil];
@@ -235,12 +233,6 @@
 }
 
 #pragma mark -
--(void) launchRestoredGame {
-    [[NSNotificationCenter defaultCenter] removeObserver:self];
-    [GameInterfaceBridge startSaveGame:[[NSUserDefaults standardUserDefaults] objectForKey:@"savedGamePath"]];
-}
-
-#pragma mark -
 -(void) viewDidUnload {
     self.gameConfigViewController = nil;
     self.settingsViewController = nil;
--- a/project_files/HedgewarsMobile/Classes/MissionTrainingViewController.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/MissionTrainingViewController.m	Sun Nov 13 18:23:05 2011 +0100
@@ -74,6 +74,7 @@
         [AudioManagerController playBackSound];
         [[self parentViewController] dismissModalViewControllerAnimated:YES];
     } else {
+        [GameInterfaceBridge registerCallingController:self];
         [GameInterfaceBridge startMissionGame:self.missionName];
     }
 }
--- a/project_files/HedgewarsMobile/Classes/RestoreViewController.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/RestoreViewController.m	Sun Nov 13 18:23:05 2011 +0100
@@ -36,7 +36,8 @@
 
     if (theButton.tag != 0) {
         [AudioManagerController playClickSound];
-        [[NSNotificationCenter defaultCenter] postNotificationName:@"launchRestoredGame" object:nil];
+        [GameInterfaceBridge registerCallingController:self.parentViewController];
+        [GameInterfaceBridge startSaveGame:[[NSUserDefaults standardUserDefaults] objectForKey:@"savedGamePath"]];
     } else {
         [AudioManagerController playBackSound];
         [defaults setObject:@"" forKey:@"savedGamePath"];
--- a/project_files/HedgewarsMobile/Classes/SavedGamesViewController.m	Sun Nov 13 12:11:44 2011 -0500
+++ b/project_files/HedgewarsMobile/Classes/SavedGamesViewController.m	Sun Nov 13 18:23:05 2011 +0100
@@ -189,6 +189,7 @@
     self.numberOfItems++;
     [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
 
+    [GameInterfaceBridge registerCallingController:self];
     [GameInterfaceBridge startSaveGame:currentFilePath];
     [currentFilePath release];
 }