restore displaying statistics at the end of a game and restore warning lower views that they are going to appear
--- 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];
}