233 } |
228 } |
234 |
229 |
235 // method that handles net setup with engine and keeps connection alive |
230 // method that handles net setup with engine and keeps connection alive |
236 -(void) engineProtocol { |
231 -(void) engineProtocol { |
237 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
232 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|
233 TCPsocket sd; |
238 IPaddress ip; |
234 IPaddress ip; |
239 int eProto; |
235 int eProto; |
240 BOOL clientQuit, serverQuit; |
236 BOOL clientQuit; |
241 char buffer[BUFFER_SIZE], string[BUFFER_SIZE]; |
237 char buffer[BUFFER_SIZE]; |
242 uint8_t msgSize; |
238 uint8_t msgSize; |
243 uint16_t gameTicks; |
239 uint16_t gameTicks; |
244 |
240 |
245 serverQuit = NO; |
241 clientQuit = NO; |
|
242 csd = NULL; |
246 |
243 |
247 if (SDLNet_Init() < 0) { |
244 if (SDLNet_Init() < 0) { |
248 DLog(@"SDLNet_Init: %s", SDLNet_GetError()); |
245 DLog(@"SDLNet_Init: %s", SDLNet_GetError()); |
249 serverQuit = YES; |
246 clientQuit = YES; |
250 } |
247 } |
251 |
248 |
252 // Resolving the host using NULL make network interface to listen |
249 // Resolving the host using NULL make network interface to listen |
253 if (SDLNet_ResolveHost(&ip, NULL, ipcPort) < 0) { |
250 if (SDLNet_ResolveHost(&ip, NULL, ipcPort) < 0 && !clientQuit) { |
254 DLog(@"SDLNet_ResolveHost: %s\n", SDLNet_GetError()); |
251 DLog(@"SDLNet_ResolveHost: %s\n", SDLNet_GetError()); |
255 serverQuit = YES; |
252 clientQuit = YES; |
256 } |
253 } |
257 |
254 |
258 // Open a connection with the IP provided (listen on the host's port) |
255 // Open a connection with the IP provided (listen on the host's port) |
259 if (!(sd = SDLNet_TCP_Open(&ip))) { |
256 if (!(sd = SDLNet_TCP_Open(&ip)) && !clientQuit) { |
260 DLog(@"SDLNet_TCP_Open: %s %\n", SDLNet_GetError(), ipcPort); |
257 DLog(@"SDLNet_TCP_Open: %s %\n", SDLNet_GetError(), ipcPort); |
261 serverQuit = YES; |
258 clientQuit = YES; |
262 } |
259 } |
263 |
260 |
264 DLog(@"Waiting for a client on port %d", ipcPort); |
261 DLog(@"Waiting for a client on port %d", ipcPort); |
265 while (!serverQuit) { |
262 while (csd == NULL) |
266 // This check the sd if there is a pending connection. |
|
267 // If there is one, accept that, and open a new socket for communicating |
|
268 csd = SDLNet_TCP_Accept(sd); |
263 csd = SDLNet_TCP_Accept(sd); |
269 if (NULL != csd) { |
264 SDLNet_TCP_Close(sd); |
270 // Now we can communicate with the client using csd socket |
265 |
271 // sd will remain opened waiting other connections |
266 while (!clientQuit) { |
272 DLog(@"client found"); |
267 msgSize = 0; |
273 |
268 memset(buffer, 0, BUFFER_SIZE); |
274 //first byte of the command alwayas contain the size of the command |
269 if (SDLNet_TCP_Recv(csd, &msgSize, sizeof(uint8_t)) <= 0) |
275 SDLNet_TCP_Recv(csd, &msgSize, sizeof(uint8_t)); |
270 clientQuit = YES; |
276 |
271 if (SDLNet_TCP_Recv(csd, buffer, msgSize) <=0) |
277 SDLNet_TCP_Recv(csd, buffer, msgSize); |
272 clientQuit = YES; |
278 gameTicks = SDLNet_Read16 (&buffer[msgSize - 2]); |
273 |
279 //DLog(@"engineProtocol - %d: received [%s]", gameTicks, buffer); |
274 switch (buffer[0]) { |
280 |
275 case 'C': |
281 if ('C' == buffer[0]) { |
|
282 DLog(@"sending game config"); |
276 DLog(@"sending game config"); |
283 |
277 |
284 // local game |
278 // local game |
285 [self sendToEngine:@"TL"]; |
279 [self sendToEngine:@"TL"]; |
286 |
280 |
287 // seed info |
281 // seed info |
288 [self sendToEngine:[self.gameConfig objectForKey:@"seed_command"]]; |
282 [self sendToEngine:[self.gameConfig objectForKey:@"seed_command"]]; |
289 |
283 |
290 // dimension of the map |
284 // dimension of the map |
291 [self sendToEngine:[self.gameConfig objectForKey:@"templatefilter_command"]]; |
285 [self sendToEngine:[self.gameConfig objectForKey:@"templatefilter_command"]]; |
292 [self sendToEngine:[self.gameConfig objectForKey:@"mapgen_command"]]; |
286 [self sendToEngine:[self.gameConfig objectForKey:@"mapgen_command"]]; |
293 [self sendToEngine:[self.gameConfig objectForKey:@"mazesize_command"]]; |
287 [self sendToEngine:[self.gameConfig objectForKey:@"mazesize_command"]]; |
294 |
288 |
295 // theme info |
289 // theme info |
296 [self sendToEngine:[self.gameConfig objectForKey:@"theme_command"]]; |
290 [self sendToEngine:[self.gameConfig objectForKey:@"theme_command"]]; |
297 |
291 |
298 // scheme (returns initial health) |
292 // scheme (returns initial health) |
299 NSInteger health = [self provideScheme:[self.gameConfig objectForKey:@"scheme"]]; |
293 NSInteger health = [self provideScheme:[self.gameConfig objectForKey:@"scheme"]]; |
304 forHogs:[[teamData objectForKey:@"number"] intValue] |
298 forHogs:[[teamData objectForKey:@"number"] intValue] |
305 withHealth:health |
299 withHealth:health |
306 ofColor:[teamData objectForKey:@"color"]]; |
300 ofColor:[teamData objectForKey:@"color"]]; |
307 } |
301 } |
308 |
302 |
309 [self provideAmmoData:@"Default.plist" forPlayingTeams:[teamsConfig count]]; |
303 [self provideAmmoData:[self.gameConfig objectForKey:@"weapon"] forPlayingTeams:[teamsConfig count]]; |
310 |
304 |
311 clientQuit = NO; |
305 clientQuit = NO; |
312 } else { |
306 break; |
313 DLog(@"wrong message or client closed connection"); |
307 case '?': |
|
308 // without this sleep sometimes frontend replies before engine has processed any flag (resulting in an error) |
|
309 [NSThread sleepForTimeInterval:0.4]; |
|
310 DLog(@"Ping? Pong!"); |
|
311 [self sendToEngine:@"!"]; |
|
312 break; |
|
313 case 'E': |
|
314 DLog(@"ERROR - last console line: [%s]", &buffer[1]); |
314 clientQuit = YES; |
315 clientQuit = YES; |
315 } |
316 break; |
316 |
317 case 'e': |
317 while (!clientQuit){ |
318 sscanf(buffer, "%*s %d", &eProto); |
318 msgSize = 0; |
319 short int netProto = 0; |
319 memset(buffer, 0, BUFFER_SIZE); |
320 char *versionStr; |
320 memset(string, 0, BUFFER_SIZE); |
321 |
321 if (SDLNet_TCP_Recv(csd, &msgSize, sizeof(uint8_t)) <= 0) |
322 HW_versionInfo(&netProto, &versionStr); |
|
323 if (netProto == eProto) { |
|
324 DLog(@"Setting protocol version %d (%s)", eProto, versionStr); |
|
325 } else { |
|
326 DLog(@"ERROR - wrong protocol number: [%s] - expecting %d", &buffer[1], eProto); |
322 clientQuit = YES; |
327 clientQuit = YES; |
323 if (SDLNet_TCP_Recv(csd, buffer, msgSize) <=0) |
328 } |
324 clientQuit = YES; |
329 |
325 |
330 break; |
326 gameTicks = SDLNet_Read16(&buffer[msgSize - 2]); |
331 case 'i': |
327 //DLog(@"engineProtocolThread - %d: received [%s]", gameTicks, buffer); |
332 switch (buffer[1]) { |
328 |
333 case 'r': |
329 switch (buffer[0]) { |
334 NSLog(@"Winning team: %s", &buffer[2]); |
330 case '?': |
|
331 DLog(@"Ping? Pong!"); |
|
332 [self sendToEngine:@"!"]; |
|
333 break; |
335 break; |
334 case 'E': |
336 case 'k': |
335 DLog(@"ERROR - last console line: [%s]", buffer); |
337 NSLog(@"Best Hedgehog: %s", &buffer[2]); |
336 clientQuit = YES; |
|
337 break; |
338 break; |
338 case 'e': |
|
339 sscanf(buffer, "%*s %d", &eProto); |
|
340 short int netProto = 0; |
|
341 char *versionStr; |
|
342 |
|
343 HW_versionInfo(&netProto, &versionStr); |
|
344 if (netProto == eProto) { |
|
345 DLog(@"Setting protocol version %d (%s)", eProto, versionStr); |
|
346 } else { |
|
347 DLog(@"ERROR - wrong protocol number: [%s] - expecting %d", buffer, eProto); |
|
348 clientQuit = YES; |
|
349 } |
|
350 |
|
351 break; |
|
352 case 'i': |
|
353 switch (buffer[1]) { |
|
354 case 'r': |
|
355 NSLog(@"Winning team: %s", &buffer[2]); |
|
356 break; |
|
357 case 'k': |
|
358 NSLog(@"Best Hedgehog: %s", &buffer[2]); |
|
359 break; |
|
360 } |
|
361 break; |
|
362 default: |
|
363 // empty packet or just statistics |
|
364 break; |
|
365 // missing case for exiting right away |
|
366 } |
339 } |
367 } |
340 break; |
368 DLog(@"Engine exited, closing server"); |
341 default: |
369 // wait a little to let the client close cleanly |
342 // empty packet or just statistics -- in either cases gameTicks is sent |
370 [NSThread sleepForTimeInterval:2]; |
343 //gameTicks = SDLNet_Read16 (&buffer[msgSize - 2]); |
371 // Close the client socket |
344 //DLog(@"engineProtocol - %d: received [%s]", gameTicks, buffer); |
372 SDLNet_TCP_Close(csd); |
345 break; |
373 serverQuit = YES; |
|
374 } |
346 } |
375 } |
347 } |
376 |
348 DLog(@"Engine exited, closing server"); |
377 SDLNet_TCP_Close(sd); |
349 // wait a little to let the client close cleanly |
|
350 [NSThread sleepForTimeInterval:2]; |
|
351 // Close the client socket |
|
352 SDLNet_TCP_Close(csd); |
378 SDLNet_Quit(); |
353 SDLNet_Quit(); |
379 |
354 |
380 [[NSFileManager defaultManager] removeItemAtPath:GAMECONFIG_FILE() error:NULL]; |
355 [[NSFileManager defaultManager] removeItemAtPath:GAMECONFIG_FILE() error:NULL]; |
381 |
356 |
382 [pool release]; |
357 [pool release]; |
383 //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. |
358 //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. |
384 //[NSThread exit]; |
359 //[NSThread exit]; |