project_files/HedgewarsMobile/Classes/EngineProtocolNetwork.m
changeset 5155 f2165724605c
parent 5154 851f36579ed4
child 5156 641abe679bf0
equal deleted inserted replaced
5154:851f36579ed4 5155:f2165724605c
    25 #import "OverlayViewController.h"
    25 #import "OverlayViewController.h"
    26 
    26 
    27 #define BUFFER_SIZE 255     // like in original frontend
    27 #define BUFFER_SIZE 255     // like in original frontend
    28 
    28 
    29 @implementation EngineProtocolNetwork
    29 @implementation EngineProtocolNetwork
    30 @synthesize statsArray, savePath, gameConfig, ipcPort, csd;
    30 @synthesize delegate, stream, ipcPort, csd;
    31 
    31 
    32 -(id) init {
    32 -(id) init {
    33     if (self = [super init]) {
    33     if (self = [super init]) {
    34         self.savePath = nil;
    34         self.delegate = nil;
    35         self.statsArray = nil;
    35 
    36         self.gameConfig = nil;
       
    37         self.ipcPort = 0;
    36         self.ipcPort = 0;
       
    37         self.csd = NULL;
       
    38         self.stream = nil;
    38     }
    39     }
    39     return self;
    40     return self;
    40 }
    41 }
    41 
    42 
       
    43 -(id) initOnPort:(NSInteger) port {
       
    44     if (self = [self init])
       
    45         self.ipcPort = port;
       
    46     return self;
       
    47 }
       
    48 
       
    49 -(void) gameHasEndedWithStats:(NSArray *)stats {
       
    50     if (self.delegate != nil && [self.delegate respondsToSelector:@selector(gameHasEndedWithStats:)])
       
    51         [self.delegate gameHasEndedWithStats:stats];
       
    52     else
       
    53         DLog(@"Error! delegate == nil");
       
    54 }
       
    55 
    42 -(void) dealloc {
    56 -(void) dealloc {
    43     [statsArray release];
    57     self.delegate = nil;
    44     [savePath release];
    58     releaseAndNil(stream);
    45     [gameConfig release];
       
    46     [super dealloc];
    59     [super dealloc];
    47 }
    60 }
    48 
    61 
    49 -(void) spawnThreadOnPort:(NSInteger) port {
    62 #pragma mark -
    50     self.ipcPort = port;
    63 #pragma mark Spawner functions
       
    64 -(void) spawnThread:(NSString *)onSaveFile withOptions:(NSDictionary *)dictionary {
       
    65     self.stream = [[NSOutputStream alloc] initToFileAtPath:onSaveFile append:YES];
    51 
    66 
    52     [NSThread detachNewThreadSelector:@selector(engineProtocol)
    67     [NSThread detachNewThreadSelector:@selector(engineProtocol)
    53                              toTarget:self
    68                              toTarget:self
    54                            withObject:nil];
    69                            withObject:dictionary];
       
    70 }
       
    71 
       
    72 -(void) spawnThread:(NSString *)onSaveFile {
       
    73     [self spawnThread:onSaveFile withOptions:nil];
    55 }
    74 }
    56 
    75 
    57 #pragma mark -
    76 #pragma mark -
    58 #pragma mark Provider functions
    77 #pragma mark Provider functions
    59 // unpacks team data from the selected team.plist to a sequence of engine commands
    78 // unpacks team data from the selected team.plist to a sequence of engine commands
   189 }
   208 }
   190 
   209 
   191 #pragma mark -
   210 #pragma mark -
   192 #pragma mark Network relevant code
   211 #pragma mark Network relevant code
   193 -(void) dumpRawData:(const char *)buffer ofSize:(uint8_t) length {
   212 -(void) dumpRawData:(const char *)buffer ofSize:(uint8_t) length {
   194     // is it performant to reopen the stream every time?
   213     [self.stream open];
   195     NSOutputStream *os = [[NSOutputStream alloc] initToFileAtPath:self.savePath append:YES];
   214     [self.stream write:&length maxLength:1];
   196     [os open];
   215     [self.stream write:(const uint8_t *)buffer maxLength:length];
   197     [os write:&length maxLength:1];
   216     [self.stream close];
   198     [os write:(const uint8_t *)buffer maxLength:length];
       
   199     [os close];
       
   200     [os release];
       
   201 }
   217 }
   202 
   218 
   203 // wrapper that computes the length of the message and then sends the command string, saving the command on a file
   219 // wrapper that computes the length of the message and then sends the command string, saving the command on a file
   204 -(int) sendToEngine:(NSString *)string {
   220 -(int) sendToEngine:(NSString *)string {
   205     uint8_t length = [string length];
   221     uint8_t length = [string length];
   216     SDLNet_TCP_Send(csd, &length, 1);
   232     SDLNet_TCP_Send(csd, &length, 1);
   217     return SDLNet_TCP_Send(csd, [string UTF8String], length);
   233     return SDLNet_TCP_Send(csd, [string UTF8String], length);
   218 }
   234 }
   219 
   235 
   220 // this is launched as thread and handles all IPC with engine
   236 // this is launched as thread and handles all IPC with engine
   221 -(void) engineProtocol {
   237 -(void) engineProtocol:(id) object {
   222     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   238     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
       
   239     NSDictionary *gameConfig = (NSDictionary *)object;
       
   240     NSMutableArray *statsArray = nil;
   223     TCPsocket sd;
   241     TCPsocket sd;
   224     IPaddress ip;
   242     IPaddress ip;
   225     int eProto;
   243     int eProto;
   226     BOOL clientQuit;
   244     BOOL clientQuit;
   227     char const buffer[BUFFER_SIZE];
   245     char const buffer[BUFFER_SIZE];
   260         if (SDLNet_TCP_Recv(csd, (void *)buffer, msgSize) <= 0)
   278         if (SDLNet_TCP_Recv(csd, (void *)buffer, msgSize) <= 0)
   261             break;
   279             break;
   262 
   280 
   263         switch (buffer[0]) {
   281         switch (buffer[0]) {
   264             case 'C':
   282             case 'C':
   265                 DLog(@"Sending game config...\n%@", self.gameConfig);
   283                 DLog(@"Sending game config...\n%@", gameConfig);
   266 
   284 
   267                 /*if (isNetGame == YES)
   285                 /*if (isNetGame == YES)
   268                     [self sendToEngineNoSave:@"TN"];
   286                     [self sendToEngineNoSave:@"TN"];
   269                 else*/
   287                 else*/
   270                     [self sendToEngineNoSave:@"TL"];
   288                     [self sendToEngineNoSave:@"TL"];
   271                 NSString *saveHeader = @"TS";
   289                 NSString *saveHeader = @"TS";
   272                 [self dumpRawData:[saveHeader UTF8String] ofSize:[saveHeader length]];
   290                 [self dumpRawData:[saveHeader UTF8String] ofSize:[saveHeader length]];
   273 
   291 
   274                 // seed info
   292                 // seed info
   275                 [self sendToEngine:[self.gameConfig objectForKey:@"seed_command"]];
   293                 [self sendToEngine:[gameConfig objectForKey:@"seed_command"]];
   276 
   294 
   277                 // dimension of the map
   295                 // dimension of the map
   278                 [self sendToEngine:[self.gameConfig objectForKey:@"templatefilter_command"]];
   296                 [self sendToEngine:[gameConfig objectForKey:@"templatefilter_command"]];
   279                 [self sendToEngine:[self.gameConfig objectForKey:@"mapgen_command"]];
   297                 [self sendToEngine:[gameConfig objectForKey:@"mapgen_command"]];
   280                 [self sendToEngine:[self.gameConfig objectForKey:@"mazesize_command"]];
   298                 [self sendToEngine:[gameConfig objectForKey:@"mazesize_command"]];
   281 
   299 
   282                 // static land (if set)
   300                 // static land (if set)
   283                 NSString *staticMap = [self.gameConfig objectForKey:@"staticmap_command"];
   301                 NSString *staticMap = [gameConfig objectForKey:@"staticmap_command"];
   284                 if ([staticMap length] != 0)
   302                 if ([staticMap length] != 0)
   285                     [self sendToEngine:staticMap];
   303                     [self sendToEngine:staticMap];
   286 
   304 
   287                 // lua script (if set)
   305                 // lua script (if set)
   288                 NSString *script = [self.gameConfig objectForKey:@"mission_command"];
   306                 NSString *script = [gameConfig objectForKey:@"mission_command"];
   289                 if ([script length] != 0)
   307                 if ([script length] != 0)
   290                     [self sendToEngine:script];
   308                     [self sendToEngine:script];
   291 
   309 
   292                 // theme info
   310                 // theme info
   293                 [self sendToEngine:[self.gameConfig objectForKey:@"theme_command"]];
   311                 [self sendToEngine:[gameConfig objectForKey:@"theme_command"]];
   294 
   312 
   295                 // scheme (returns initial health)
   313                 // scheme (returns initial health)
   296                 NSInteger health = [self provideScheme:[self.gameConfig objectForKey:@"scheme"]];
   314                 NSInteger health = [self provideScheme:[gameConfig objectForKey:@"scheme"]];
   297 
   315 
   298                 // send an ammostore for each team
   316                 // send an ammostore for each team
   299                 NSArray *teamsConfig = [self.gameConfig objectForKey:@"teams_list"];
   317                 NSArray *teamsConfig = [gameConfig objectForKey:@"teams_list"];
   300                 [self provideAmmoData:[self.gameConfig objectForKey:@"weapon"] forPlayingTeams:[teamsConfig count]];
   318                 [self provideAmmoData:[gameConfig objectForKey:@"weapon"] forPlayingTeams:[teamsConfig count]];
   301 
   319 
   302                 // finally add hogs
   320                 // finally add hogs
   303                 for (NSDictionary *teamData in teamsConfig) {
   321                 for (NSDictionary *teamData in teamsConfig) {
   304                     [self provideTeamData:[teamData objectForKey:@"team"]
   322                     [self provideTeamData:[teamData objectForKey:@"team"]
   305                                   forHogs:[[teamData objectForKey:@"number"] intValue]
   323                                   forHogs:[[teamData objectForKey:@"number"] intValue]
   329                     DLog(@"ERROR - wrong protocol number: %d (expecting %d)", netProto, eProto);
   347                     DLog(@"ERROR - wrong protocol number: %d (expecting %d)", netProto, eProto);
   330                     clientQuit = YES;
   348                     clientQuit = YES;
   331                 }
   349                 }
   332                 break;
   350                 break;
   333             case 'i':
   351             case 'i':
   334                 if (self.statsArray == nil) {
   352                 if (statsArray == nil) {
   335                     self.statsArray = [[NSMutableArray alloc] initWithCapacity:10 - 2];
   353                     statsArray = [[NSMutableArray alloc] initWithCapacity:10 - 2];
   336                     NSMutableArray *ranking = [[NSMutableArray alloc] initWithCapacity:4];
   354                     NSMutableArray *ranking = [[NSMutableArray alloc] initWithCapacity:4];
   337                     [self.statsArray insertObject:ranking atIndex:0];
   355                     [statsArray insertObject:ranking atIndex:0];
   338                     [ranking release];
   356                     [ranking release];
   339                 }
   357                 }
   340                 NSString *tempStr = [NSString stringWithUTF8String:&buffer[2]];
   358                 NSString *tempStr = [NSString stringWithUTF8String:&buffer[2]];
   341                 NSArray *info = [tempStr componentsSeparatedByString:@" "];
   359                 NSArray *info = [tempStr componentsSeparatedByString:@" "];
   342                 NSString *arg = [info objectAtIndex:0];
   360                 NSString *arg = [info objectAtIndex:0];
   343                 int index = [arg length] + 3;
   361                 int index = [arg length] + 3;
   344                 switch (buffer[1]) {
   362                 switch (buffer[1]) {
   345                     case 'r':           // winning team
   363                     case 'r':           // winning team
   346                         [self.statsArray insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1];
   364                         [statsArray insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1];
   347                         break;
   365                         break;
   348                     case 'D':           // best shot
   366                     case 'D':           // best shot
   349                         [self.statsArray addObject:[NSString stringWithFormat:@"The best shot award won by %s (with %@ points)", &buffer[index], arg]];
   367                         [statsArray addObject:[NSString stringWithFormat:@"The best shot award won by %s (with %@ points)", &buffer[index], arg]];
   350                         break;
   368                         break;
   351                     case 'k':           // best hedgehog
   369                     case 'k':           // best hedgehog
   352                         [self.statsArray addObject:[NSString stringWithFormat:@"The best killer is %s with %@ kills in a turn", &buffer[index], arg]];
   370                         [statsArray addObject:[NSString stringWithFormat:@"The best killer is %s with %@ kills in a turn", &buffer[index], arg]];
   353                         break;
   371                         break;
   354                     case 'K':           // number of hogs killed
   372                     case 'K':           // number of hogs killed
   355                         [self.statsArray addObject:[NSString stringWithFormat:@"%@ hedgehog(s) were killed during this round", arg]];
   373                         [statsArray addObject:[NSString stringWithFormat:@"%@ hedgehog(s) were killed during this round", arg]];
   356                         break;
   374                         break;
   357                     case 'H':           // team health/graph
   375                     case 'H':           // team health/graph
   358                         break;
   376                         break;
   359                     case 'T':           // local team stats
   377                     case 'T':           // local team stats
   360                         // still WIP in statsPage.cpp
   378                         // still WIP in statsPage.cpp
   361                         break;
   379                         break;
   362                     case 'P':           // teams ranking
   380                     case 'P':           // teams ranking
   363                         [[self.statsArray objectAtIndex:0] addObject:tempStr];
   381                         [[statsArray objectAtIndex:0] addObject:tempStr];
   364                         break;
   382                         break;
   365                     case 's':           // self damage
   383                     case 's':           // self damage
   366                         [self.statsArray addObject:[NSString stringWithFormat:@"%s thought it's good to shoot his own hedgehogs with %@ points", &buffer[index], arg]];
   384                         [statsArray addObject:[NSString stringWithFormat:@"%s thought it's good to shoot his own hedgehogs with %@ points", &buffer[index], arg]];
   367                         break;
   385                         break;
   368                     case 'S':           // friendly fire
   386                     case 'S':           // friendly fire
   369                         [self.statsArray addObject:[NSString stringWithFormat:@"%s killed %@ of his own hedgehogs", &buffer[index], arg]];
   387                         [statsArray addObject:[NSString stringWithFormat:@"%s killed %@ of his own hedgehogs", &buffer[index], arg]];
   370                         break;
   388                         break;
   371                     case 'B':           // turn skipped
   389                     case 'B':           // turn skipped
   372                         [self.statsArray addObject:[NSString stringWithFormat:@"%s was scared and skipped turn %@ times", &buffer[index], arg]];
   390                         [statsArray addObject:[NSString stringWithFormat:@"%s was scared and skipped turn %@ times", &buffer[index], arg]];
   373                         break;
   391                         break;
   374                     default:
   392                     default:
   375                         DLog(@"Unhandled stat message, see statsPage.cpp");
   393                         DLog(@"Unhandled stat message, see statsPage.cpp");
   376                         break;
   394                         break;
   377                 }
   395                 }
   378                 break;
   396                 break;
   379             case 'q':
   397             case 'q':
   380                 // game ended, can remove the savefile and the trailing overlay (when dualhead)
   398                 // game ended, can remove the savefile and the trailing overlay (when dualhead)
   381                 [[NSFileManager defaultManager] removeItemAtPath:self.savePath error:nil];
   399                 [self gameHasEndedWithStats:statsArray];
   382                 if (IS_DUALHEAD())
       
   383                     [[NSNotificationCenter defaultCenter] postNotificationName:@"remove overlay" object:nil];
       
   384                 break;
   400                 break;
   385             case 'Q':
   401             case 'Q':
   386                 // game exited but not completed, nothing to do (just don't save the message)
   402                 // game exited but not completed, nothing to do (just don't save the message)
   387                 break;
   403                 break;
   388             default:
   404             default: