further engine interaction refactoring
authorkoda
Fri, 11 Nov 2011 01:40:23 +0100
changeset 6321 5a0416e5a6de
parent 6320 238a6dc0e7ad
child 6322 b310f0bc8dde
further engine interaction refactoring
project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h
project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m
project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h
project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m
project_files/HedgewarsMobile/Classes/HWUtils.m
project_files/HedgewarsMobile/Classes/RestoreViewController.m
--- a/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h	Fri Nov 11 01:18:19 2011 +0100
+++ b/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.h	Fri Nov 11 01:40:23 2011 +0100
@@ -32,17 +32,21 @@
     id<EngineProtocolDelegate> delegate;
 
     NSOutputStream *stream;
-    TCPsocket csd;                  // Client socket descriptor
+    TCPsocket csd;
+    NSInteger enginePort;
 }
 
 @property (nonatomic,assign) id<EngineProtocolDelegate> delegate;
 @property (nonatomic,retain) NSOutputStream *stream;
 @property (assign) TCPsocket csd;
+@property (assign) NSInteger enginePort;
 
 
 -(id)   init;
 
--(NSInteger) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary;
++(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary;
++(NSInteger) activeEnginePort;
+
 -(void) engineProtocol:(id) object;
 -(void) gameHasEndedWithStats:(NSArray *)stats;
 
--- a/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m	Fri Nov 11 01:18:19 2011 +0100
+++ b/project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m	Fri Nov 11 01:40:23 2011 +0100
@@ -25,8 +25,10 @@
 
 #define BUFFER_SIZE 255     // like in original frontend
 
+static NSInteger activeEnginePort;
+
 @implementation EngineProtocolNetwork
-@synthesize delegate, stream, csd;
+@synthesize delegate, stream, csd, enginePort;
 
 -(id) init {
     if (self = [super init]) {
@@ -34,7 +36,9 @@
 
         self.csd = NULL;
         self.stream = nil;
+        self.enginePort = [HWUtils randomPort];
     }
+    activeEnginePort = self.enginePort;
     return self;
 }
 
@@ -53,21 +57,20 @@
 
 #pragma mark -
 #pragma mark Spawner functions
--(NSInteger) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
-    [self retain];
-    self.stream = (onSaveFile) ? [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES] : nil;
-    [self.stream open];
++(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
+    EngineProtocolNetwork *proto = [[EngineProtocolNetwork alloc] init];
+    proto.stream = (onSaveFile) ? [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES] : nil;
+    [proto.stream open];
 
-    NSInteger ipcPort = [HWUtils randomPort];
-    NSDictionary *config = [[NSDictionary alloc] initWithObjectsAndKeys:
-                            [NSNumber numberWithInt:ipcPort],@"port",
-                            dictionary,@"config", nil];
+    // +detachNewThreadSelector retain/release self automatically
     [NSThread detachNewThreadSelector:@selector(engineProtocol:)
-                             toTarget:self
-                           withObject:config];
-    [config release];
+                             toTarget:proto
+                           withObject:dictionary];
+    [proto release];
+}
 
-    return ipcPort;
++(NSInteger) activeEnginePort {
+    return activeEnginePort;
 }
 
 #pragma mark -
@@ -228,8 +231,7 @@
 // this is launched as thread and handles all IPC with engine
 -(void) engineProtocol:(id) object {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    NSDictionary *gameConfig = [(NSDictionary *)object objectForKey:@"config"];
-    NSInteger port = [[(NSDictionary *)object objectForKey:@"port"] intValue];
+    NSDictionary *gameConfig = (NSDictionary *)object;
     NSMutableArray *statsArray = nil;
     TCPsocket sd;
     IPaddress ip;
@@ -247,18 +249,18 @@
     }
 
     // Resolving the host using NULL make network interface to listen
-    if (SDLNet_ResolveHost(&ip, NULL, port) < 0 && !clientQuit) {
+    if (SDLNet_ResolveHost(&ip, NULL, self.enginePort) < 0 && !clientQuit) {
         DLog(@"SDLNet_ResolveHost: %s\n", SDLNet_GetError());
         clientQuit = YES;
     }
 
     // Open a connection with the IP provided (listen on the host's port)
     if (!(sd = SDLNet_TCP_Open(&ip)) && !clientQuit) {
-        DLog(@"SDLNet_TCP_Open: %s %\n", SDLNet_GetError(), port);
+        DLog(@"SDLNet_TCP_Open: %s %\n", SDLNet_GetError(), self.enginePort);
         clientQuit = YES;
     }
 
-    DLog(@"Waiting for a client on port %d", port);
+    DLog(@"Waiting for a client on port %d", self.enginePort);
     while (csd == NULL)
         csd = SDLNet_TCP_Accept(sd);
     SDLNet_TCP_Close(sd);
@@ -413,8 +415,6 @@
     SDLNet_Quit();
 
     [pool release];
-
-    [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES];
     // Invoking this method should be avoided as it does not give your thread a chance
     // to clean up any resources it allocated during its execution.
     //[NSThread exit];
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h	Fri Nov 11 01:18:19 2011 +0100
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.h	Fri Nov 11 01:40:23 2011 +0100
@@ -23,11 +23,9 @@
 
 
 @interface GameInterfaceBridge : NSObject {
-    NSInteger ipcPort;
     UIView *blackView;
 }
 
-@property (assign) NSInteger ipcPort;
 @property (nonatomic,retain) UIView *blackView;
 
 +(void) startLocalGame:(NSDictionary *)withOptions;
--- a/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m	Fri Nov 11 01:18:19 2011 +0100
+++ b/project_files/HedgewarsMobile/Classes/GameInterfaceBridge.m	Fri Nov 11 01:40:23 2011 +0100
@@ -27,7 +27,7 @@
 #import "ObjcExports.h"
 
 @implementation GameInterfaceBridge
-@synthesize ipcPort, blackView;
+@synthesize blackView;
 
 #pragma mark -
 #pragma mark Instance methods for engine interaction
@@ -35,10 +35,7 @@
 -(void) earlyEngineLaunch:(NSString *)pathOrNil withOptions:(NSDictionary *)optionsOrNil {
     [self retain];
     [AudioManagerController stopBackgroundMusic];
-
-    EngineProtocolNetwork *proto = [[EngineProtocolNetwork alloc] init];
-    self.ipcPort = [proto spawnThread:pathOrNil withOptions:optionsOrNil];
-    [proto release];
+    [EngineProtocolNetwork spawnThread:pathOrNil withOptions:optionsOrNil];
 
     // add a black view hiding the background
     CGRect theFrame = [[UIScreen mainScreen] bounds];
@@ -90,8 +87,9 @@
 -(void) engineLaunch:(NSString *)pathOrNil {
     const char *gameArgs[11];
     CGFloat width, height;
+    NSInteger enginePort = [EngineProtocolNetwork activeEnginePort];
     CGFloat screenScale = [[UIScreen mainScreen] safeScale];
-    NSString *ipcString = [[NSString alloc] initWithFormat:@"%d",self.ipcPort];
+    NSString *ipcString = [[NSString alloc] initWithFormat:@"%d",enginePort];
     NSString *localeString = [[NSString alloc] initWithFormat:@"%@.txt",[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
     NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
 
@@ -158,10 +156,14 @@
 
 #pragma mark -
 #pragma mark Class methods for setting up the engine from outsite
-// set up variables for a local game
++(void) startGame:(TGameType) type atPath:(NSString *)path withOptions:(NSDictionary *)config {
+    [HWUtils setGameType:type];
+    GameInterfaceBridge *bridge = [[GameInterfaceBridge alloc] init];
+    [bridge earlyEngineLaunch:path withOptions:config];
+    [bridge release];
+}
+
 +(void) startLocalGame:(NSDictionary *)withOptions {
-    [HWUtils setGameType:gtLocal];
-
     NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
     [outputFormatter setDateFormat:@"yyyy-MM-dd '@' HH.mm"];
     NSString *savePath = [[NSString alloc] initWithFormat:@"%@%@.hws",SAVES_DIRECTORY(),[outputFormatter stringFromDate:[NSDate date]]];
@@ -171,30 +173,20 @@
     if ([[NSFileManager defaultManager] fileExistsAtPath:savePath])
         [[NSFileManager defaultManager] removeItemAtPath:savePath error:nil];
 
-    GameInterfaceBridge *bridge = [[GameInterfaceBridge alloc] init];
-    [bridge earlyEngineLaunch:savePath withOptions:withOptions];
-    [bridge release];
+    [self startGame:gtLocal atPath:savePath withOptions:withOptions];
     [savePath release];
 }
 
-// set up variables for a save game
 +(void) startSaveGame:(NSString *)atPath {
-    [HWUtils setGameType:gtSave];
-    GameInterfaceBridge *bridge = [[GameInterfaceBridge alloc] init];
-    [bridge earlyEngineLaunch:atPath withOptions:nil];
-    [bridge release];
+    [self startGame:gtSave atPath:atPath withOptions:nil];
 }
 
 +(void) startMissionGame:(NSString *)withScript {
-    [HWUtils setGameType:gtMission];
-
     NSString *missionPath = [[NSString alloc] initWithFormat:@"escript Missions/Training/%@.lua",withScript];
     NSDictionary *missionLine = [[NSDictionary alloc] initWithObjectsAndKeys:missionPath,@"mission_command",nil];
     [missionPath release];
 
-    GameInterfaceBridge *bridge = [[GameInterfaceBridge alloc] init];
-    [bridge earlyEngineLaunch:nil withOptions:missionLine];
-    [bridge release];
+    [self startGame:gtMission atPath:nil withOptions:missionLine];
     [missionLine release];
 }
 
--- a/project_files/HedgewarsMobile/Classes/HWUtils.m	Fri Nov 11 01:18:19 2011 +0100
+++ b/project_files/HedgewarsMobile/Classes/HWUtils.m	Fri Nov 11 01:40:23 2011 +0100
@@ -25,6 +25,7 @@
 #import <netinet/in.h>
 #import <SystemConfiguration/SCNetworkReachability.h>
 #import "hwconsts.h"
+#import "EngineProtocolNetwork.h"
 
 static NSString *cachedModel = nil;
 static NSArray *cachedColors = nil;
@@ -96,7 +97,11 @@
 +(NSInteger) randomPort {
     srandom(time(NULL));
     NSInteger res = (random() % 64511) + 1024;
-    return (res == NETGAME_DEFAULT_PORT) ? [HWUtils randomPort] : res;
+    // recall self until you get a free port
+    if (res == NETGAME_DEFAULT_PORT || res == [EngineProtocolNetwork activeEnginePort])
+        return [self randomPort];
+    else
+        return res;
 }
 
 +(BOOL) isNetworkReachable {
--- a/project_files/HedgewarsMobile/Classes/RestoreViewController.m	Fri Nov 11 01:18:19 2011 +0100
+++ b/project_files/HedgewarsMobile/Classes/RestoreViewController.m	Fri Nov 11 01:40:23 2011 +0100
@@ -36,14 +36,13 @@
 
     if (theButton.tag != 0) {
         [AudioManagerController playClickSound];
-        [self.parentViewController dismissModalViewControllerAnimated:NO];
         [[NSNotificationCenter defaultCenter] postNotificationName:@"launchRestoredGame" object:nil];
     } else {
         [AudioManagerController playBackSound];
         [defaults setObject:@"" forKey:@"savedGamePath"];
         [defaults synchronize];
-        [self.parentViewController dismissModalViewControllerAnimated:YES];
     }
+    [self.parentViewController dismissModalViewControllerAnimated:YES];
 }
 
 -(void) viewDidLoad {