Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; GeSHi has a deprecated constructor in /home/mafriginal/mysterycoconut.com/wp-content/plugins/scgeshi/geshi.php on line 259

Deprecated: Function create_function() is deprecated in /home/mafriginal/mysterycoconut.com/wp-content/plugins/scgeshi/geshi.php on line 4736

Another week, another iOS release, another multi-gigabyte SDK download. You have been sitting all day in front of nondescript backdrops under the rain, coffee mug attached to your paw. Your doctor left a message saying your liver looks like last year’s filter from the hospital’s coffee vending machine. You lost your Barista of the Day 2010 Tracker Calendar and now every time you show up there is a dude with an apron behind the counter. iPod keeps shuffling once and again over the sad parts of the Start Wars soundtrack. You have to accept it. You are stuck again.

It all started with the interface. You were there positioning buttons, entering coordinates by hand: the score label, the Menu-pause™ widget, the alertness/drunkenness meter… it really started bugging you after having to re-compile for the tenth time just to find your designer (that is, you on Fridays) had decided to change the size of all the graphics. Then there was the turtle. I mean, how difficult do you think it is to calculate the mass of a freaking turtle? But somehow anytime you tried to change it the physics engine either made it go through the floor or bounce like crazy. Gosh man, didn’t we go through this already? Except your fancy level editor was of no help with any of this. You see, I may run the risk of repeating myself, but maybe is time to revisit the advice I gave you. First you need better tools.

Implementing a Socket Server for your iPhone Game

If there is anything to learn from all this frustration is that waiting to recompile sucks. Seeing changes live, that’s what you need. Being able to move your interface around until you get it perfectly lick-able, or change the hit points of your Pretzel Dragon till you find the perfect balance between Masochist level and N00b. At runtime. That’s what we are talking about! Sure you can already do all that with the debugger, but really… do you enjoy pausing and restarting, fishing for the right breakpoint and variable? That’s like having a swimming pool when what you need is an umbrella. Not fun.

So you come up with a plan: you are going to run a server on your game, connect to it from your computers command line, and send commands for the things you want to modify. You look on the interwebs for information on how to do this and then start wondering if maybe Networking 101 in school had nothing to do with hanging in the bar with the girl of the anchor tattoo. I could explain you how Berkeley sockets work, and the difference between transfer protocols, and we could talk about streams and datagrams, and the beautiful C API… or we could just use AsyncSocket. You will like AsyncSocket cause:

  • you only need to add one class to your project! There are two available, one for TCP connections and another one for UDP. We will stay with TCP cause we are going to use Telnet to connect to your server.
  • you don’t need to worry about low level details. Whenever the server accepts connections, clients disconnect or timeout, or a number of other things happen, AsyncSocket will just call your delegate methods. And for starters, you only need to really worry about implementing 4 methods.
  • it plays nice with the current application NSRunLoop by default, and is non-blocking.

So you open Xcode, and decide to create a new barebones Window-based Application to test all this. Let’s just call it the Mystery Coconut HQ Simulator. You include AsyncSocket, then the CFNetwork.framework, then finally create a normal NSObject descendant for the Debug Server itself.

DebugServer.h ends up just with a few instance variables: the AsyncSocket object that works as server, an array of connected clients, and a flag to tell if is already running or not. One method for starting the server on a specific port, another for stopping, and we are done.

@class AsyncSocket;

@interface DebugServer : NSObject {
    AsyncSocket *debugServer;
    NSMutableArray *connectedClients;
    bool running;
}

@property (readonly,getter=isRunning) bool running;

- (void) startOnPort:(int)port;
- (void) stop;

@end

Then you implement a few delegate methods. I see your server can send messages to connected clients with writeData:withTimeout:tag:, and that it requires NSData versions of your strings. And since you want to listen to connected clients until they disconnect, you call readDataWithTimeout:tag: when they first connect, and then every time you get some input, cause if you didn’t the server would only ever receive the first message!

@implementation DebugServer

@synthesize running;

- (id) init;
{
    self = [super init];
    if (self != nil)
    {
        debugServer = [[AsyncSocket alloc] initWithDelegate:self];
        connectedClients = [[NSMutableArray alloc] initWithCapacity:1];
        running = false;
    }
    return self;
}

- (void) dealloc;
{
    [self stop];
    [connectedClients release];
    [debugServer release];
    [super dealloc];
}

- (void) startOnPort:(int)port;
{
    if (running) return;
   
    if (port < 0 || port > 65535)
        port = 0;
   
    NSError *error = nil;
    if (![debugServer acceptOnPort:port error:&error])
        return;
   
    NSLog(@"My Awesome Debug Server has started on port %hu", [debugServer localPort]);
   
    running = true;
}


- (void) stop;
{
    if (!running) return;
   
    [debugServer disconnect];
    for (AsyncSocket* socket in connectedClients)
        [socket disconnect];
   
    running = false;
}

- (void)onSocket:(AsyncSocket *)socket didAcceptNewSocket:(AsyncSocket *)newSocket;
{
    [connectedClients addObject:newSocket];
}


- (void)onSocketDidDisconnect:(AsyncSocket *)socket;
{
    [connectedClients removeObject:socket];
}

- (void)onSocket:(AsyncSocket *)socket didConnectToHost:(NSString *)host port:(UInt16)port;
{
    NSLog(@"Accepted client %@:%hu", host, port);

    NSData *welcomeData = [@"Welcome to my Awesome Debug Server\r\n"
        dataUsingEncoding:NSUTF8StringEncoding];
    [socket writeData:welcomeData withTimeout:-1 tag:WelcomeMsgTag];

    [socket readDataWithTimeout:-1 tag:GenericMsgTag];
}


- (void)onSocket:(AsyncSocket *)socket didReadData:(NSData *)data withTag:(long)tag;
{
    NSString *tmp = [NSString stringWithUTF8String:[data bytes]];
    NSString *input = [tmp stringByTrimmingCharactersInSet:
                        [NSCharacterSet whitespaceAndNewlineCharacterSet]];
   
    if ([input isEqualToString:@"exit"])
    {
        NSData *byeData = [@"Bye!\r\n" dataUsingEncoding:NSUTF8StringEncoding];
        [socket writeData:byeData withTimeout:-1 tag:GenericMsgTag];
        [socket disconnectAfterWriting];
        return;
    }
   
    [socket readDataWithTimeout:-1 tag:GenericMsgTag];
}

@end

Nice! That was fast. You have a socket server.

Fast app switching in iOS 4

What? You don’t think is going to work? You think the whole AsyncSocket thing is a prank, like that time the girl of the anchor tattoo convinced you the NSCoders meeting was at the Blue Oyster? Well, let’s see; just add a DebugServer to the AppDelegate and… Holy crap! Who the hell put all this garbage in your AppDelegate?! Oh, wait… does this have anything to do with you using iOS 4? You skim through the docs as your eyes glaze over. OK, don’t get stressed. The important part is: where do you put the code to start and stop the server?

You could put the startOnPort: call on applicationWillEnterForeground:, but then iOS 3 devices will never run that code… no thanks. You end up putting it in applicationDidBecomeActive:.

As per the stop call… applicationWillTerminate: for sure, but also in applicationWillResignActive:, so that when the app goes to sleep you don’t keep the server running and draining battery and stuff. You know the system will kill it if you did that!

You wonder, how would you do all this if it was a game that needs to save state, and handle a run loop? If it was me, I think I would do something like this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Load your game state here
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // We are back! Start the run loop!
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Save the game state (probably stop the run loop first)
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Stop the run loop or we will be killed!
    // Don't save yet, maybe he doesn't answer that phone call from his mom...
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Save and release any memory you can load fast,
    // maybe that way we are last when they line us up against the wall
}

So let’s see what you got. You added a DebugServer instance variable to your AppDelegate. Then started it in say port 9990 in the applicationDidBecomeActive: method. Stopping happens in applicationWillTerminate: and applicationWillResignActive:. With a self-congratulatory smile you check the IP of your iPhone in the LAN before compiling and running.

There it is. A boring gray background. But unaffected by the laughs of imaginary peers looking over your shoulder, you fire up the Terminal and type telnet 0.0.0.0 9990 (or whatever your device’s IP was, I cannot remember now). And… you see nothing. Gosh! Open the port in your Firewall man! Do I have to explain you everything?

Finally. There it is. Those two days you spent messing with color settings in the Terminal were so worthy of this screenshot…

Now… what happens if you run this in the simulator? It works too?! Good job!

Commands?!

There you are, glancing at the screen full of pride. You can hear the Force Theme finally coming up on iTunes. Sun shines outside. Is that the calendar you were looking for under that pile of printed PDFs?

But wait… what can you do now with this? Are you telling me that you can type “exit”??? Really?! How the heck are you going to use this to modify your game at runtime?! Come on, look at those clouds outside!

Well, you obviously have to put more work on this! You grab a notebook and start scribbling a list of commands you need to have, like “get” and “set” and “list” and “make coffee with sock and fish tank”, and… I think you are going to need a parser for all that. But after that what? Well you will need to hook your variables to this system, so when you write “set turtle-mass 1.1” it converts “turtle-mass” into a reference to a specific instance of your StupidTurtle.mass… You start thinking about registers, and command patterns, and lexers… and start crying while the Imperial March booms in the stereo.

OK, OK. Look, I will help you again. Let me present you my friend…

Lua

Would not it be nice if you could just type code in that Terminal? That it magically knew how to do operations, and loops, and assignments… that it knew about your variables… that it was as easy as writing in Xcode? Well, you cannot do that. At least not in Objective-C cause, you know, your friend the compiler waits at the end of that track. So what you need is a scripting language. You have read before about games using Python and similar languages to help with their fancy data-orientation. So you look around and find Lua’s ugly website. A scripting language that was made especially to be integrated with C? And with other languages too?? Wait, is that Objective-C in that list?

You check around diverse Objective-C/Lua projects and end up grabbing the Lua Objective-C Bridge. Seems kind of old and unmaintained, but you think is worth a try. You download the latest Lua 5.1.4 too, and add all the files to your project except for the lua.c, luac.c, and print.c, that you read somewhere are not needed. You go back to your DebugServer header and add a lua_State instance variable, then you change your init method implementation…

// Prepare Lua interpreter
luaState = lua_objc_init();
lua_settable(luaState, LUA_GLOBALSINDEX);

Then you add this to your onSocket:didReadData:, right after checking the client didn’t type “exit”.

// Run Lua
luaL_loadbuffer(luaState, [input UTF8String], [input length], nil);
lua_pcall(luaState, 0, 0, 0);

Then you run the app again, connect through the Terminal, and start typing.

But you get nothing. Then you remember you have not fed the client the results… but what is that in Xcode’s console?

Yes! You start coding like crazy. In a few minutes you have a game loop, some sprites, and a GameState object with some properties and methods. You add the following to your Lua setup:

// Prepare Lua interpreter
luaState = lua_objc_init();

AppDelegate* app = (AppDelegate*)[[UIApplication sharedApplication] delegate];
GameState* game = app.gameState;

lua_pushstring(luaState, "game");
lua_objc_pushid(luaState, game);
lua_settable(luaState, LUA_GLOBALSINDEX);

Just grabbing the GameState object and adding it as a Lua variable “game”? How do you call the methods of this object then? Seems “game:test()” calls [gameState test], and “game:setX_Y_(0, 2)” calls GameState’s setX:Y: selector! And since properties create accessors, you can also call those??? Can it really be that easy?!

The sun is bright, birds sing… as the Rebel Fanfare quicks in, you look at your phone and see somebody is calling… from your favorite coffee place.

Liked this article? Check out the follow–up and learn how to include your Lua Telnet Server only in the Debug build of your app.

LuaSockets Source Code!

Updated 7/11/2010

This Xcode project features one of the inhabitants of Mystery Coconut HQ, Pancho in his usual begging mode. Take a look at the GameState class and its methods and properties. You can access all of these from a telnet session (on port 9990) by typing, for example…

game:setRequestsPerSecond(10) // that's closer to the real Pancho.

game:setCloud_toSpeed(0, 3.5) // notice how multiple arguments are handled here.

print(game:numBalloons()) // to get properties, just print them through Lua. Remember you don't have access to member variables, just to methods.

Have fun experimenting!

Download LuaSockets project

22 Responses

  1. Pingback: How To Implement A Socket Server For Easy App Tweaking | iPhone iOS 4 iPad SDK Development Tutorials, Programming Tips, News

  2. Pingback: App Tweaking at Under The Bridge

  3. Pingback: oF関連リンク〜気になった〜 | oF / iOS Thinking.

  4. Pingback: Remote Game Editing | Games from Within

Leave a Reply

Your email address will not be published. Required fields are marked *

19 + eight =

This site uses Akismet to reduce spam. Learn how your comment data is processed.