Archive

Archive for the ‘Coding’ Category

Game engine + FTP == awesome stuff

February 2nd, 2011

For a couple of days I was tossing an idea of integrating FTP into my game engine.  Yeah, it totally sounds crazy, and this was my first thought too. But I have a very good reason why. The iOS game, I’m currently working on, has a level editor only on Windows. To test and tweak the level for a game I have to edit it with the editor on Windows, then commit to SVN, check out it on Mac, build the game, and run on iPhone. That’s quite a path and wastes a lot of time. All this makes quick iterations impossible, and the worst part is that all this repetition is very annoying and demotivating.

At first, an idea flashed in a head about doing it all myself , but I was smart enough to quickly reject it. So, I’ve went to see if there were any solutions ready, and googled for FTP server or client code. I guess my googling skills are dusting, as it took some time, but I finally came across ftplib. It’s a small and portable library implementing FTP client’s protocol. On Windows it worked without any modifications. On iOS I wasn’t so lucky, but the only problem was that Xcode’s compiler doesn’t define “__unix__”. So after modifying couple #ifdef’s it was ready to go. Overall it took me a couple of hours to get it working, mainly because the first FTP server I’ve tried was crashing. But then I came across ftpdmin, which worked flawlessly, and the best thing about it is that its distribution is only 1 exe file. Here’s a screenshot showing ftpdmin serving a level to the game engine:

Whole code for this takes just like 20 lines or so. Here’s the first hackish implementation (with a bonus buffer overflow!) that got the snowball running:

    netbuf* control;
    FtpInit();
    if (FtpConnect("192.168.2.100", &control) == 1) {
        LogInfo("Connected to ftp");

        FtpLogin("game", "game", control);

        netbuf* data;
        if (FtpAccess(gLevels[mLevel].mFile, FTPLIB_FILE_READ, FTPLIB_IMAGE, control, &data) == 1) {
            LogInfo("Ftp file open");

            const int size = 102400;
            char buf[size];
            int read;
            read = FtpRead(buf, size, data);
            if (read == -1) {
                LogWarning("Error reading ftp file");
            } else {
                buf[read] = 0;
                LogInfo("Ftp file read");
            }

            FtpClose(data);
        } else {
            LogWarning("Couldn't open ftp file");
        }

        FtpQuit(control);
    } else {
        LogWarning("Couldn't connect to ftp");
    }

So now when I’m working on levels I simply launch ftpdmin on my Windows machine, and the game on my iPod automatically downloads the levels. I play it, edit on Windows, save it, restart the level and it’s ready to be played again. Fast and effective. Yay for iterative development! The only thing I hate is that it has to use Wi-Fi… I wish iPods could access network through it’s USB cable.

The best thing about this is that you don’t need to stop with level editing. Just imagine editing and instantly downloading scripts. :-)

Smilediver Coding , , , , ,

Context objects

August 24th, 2007

Finally I’ve found some free time, and got my lazy ass to type in my first article. I hope you’ll enjoy it, and have something useful for takeaway. :-)

Many moons ago I came across a concept of “Context Objects”, and found it quite interesting. I didn’t had any opportunity to test it until recently, and now I’m really happy I have found it. So what it’s all about…

When programming higher layer classes, you end up using services of lower layers, or need some other global or local state information. For such services as logging, rendering, input, it is very tempting to write singletons, and it’s really easy to put necessary state information like game’s update delta time in a global scope variables. But any more experienced programmer will tell you that making your objects depend on a global state is bad. Global state can be unexpectedly modified from anywhere, you don’t see when it is initialized or destroyed, it ties classes to it, code is harder to read, modify or extend, writing unit tests for such classes is hard or even impossible, and so on. So how do you solve this mess?

It’s obvious that you need to pass necessary service objects or state to constructors or as parameters to methods. But this can be a bit cumbersome when you need a lot of information in a particular method. It’s common for methods such as Update(), Load(), Render(). In such cases it is more practical to use context objects. Context object is no more than a simple container for required services and state. As you already guessed, they are called context objects because they carry only information that is potentially useful in a given context (like update or rendering).

For example, in game’s update loop you usually need services like input, time and other game state information, so these can be grouped and passed along to game object’s Update() method in an UpdateContext class. In game’s rendering loop you need stuff like renderer, camera, frustum, so you would group these in RenderContext class and pass to Render() methods. Here’s a sample code to give an idea of how to use it:

struct UpdateContext { public GameTime Time; public GameState State; public Input Input; } struct RenderContext { public Renderer Renderer; public Camera Camera; public Frustum Frustum; } class CoolObject { public void Update(UpdateContext update) { if (update.State.IsPaused()) { return; } if (update.Input.KeyDown("forward")) { velocity.x += acceleration * update.Time.GetDeltaTime(); } position += velocity * update.Time.GetDeltaTime(); } public void Render(RenderContext render) { if (boundingBox.IsInside(render.Frustum)) { render.Renderer.RenderMesh(objectMesh); } } }

Note that it’s a good practice to add constructors for context objects, to ensure that user is forced to properly initialize them. If they don’t – you at least have someone to blame. ;-) Do not try to extend this class with features – keep it as simple dumb object container. And always make sure that you pass initialized and valid data. This will tighten possible causes for bugs.

When using context objects you get quite a few useful things:

  • Class is not tied to global variables. It’s easier to read it, reuse, modify and extend.
  • You’re not tied to single instances of services or same global state. For different objects you can pass different contexts. Can be very handy when debugging.
  • It’s easier to write unit tests by simply passing mock objects in context variables.
  • Code is safer as you hide stuff that could be meaningless and provide wrong information in other contexts.
  • It’s easy to extend the context class if you suddenly need to pass more information for objects.
  • You always know that incoming context data will be initialized and ready for use. Of course it doesn’t protect if someone (un)intentionally forget to initialize context object properly. ;-)

As for drawbacks, I can only mention that it requires a bit more typing, which isn’t an issue at all. Also, sometimes larger code blocks can get a bit messier due longer lines. But it can be easily fixed by accessing objects, held in a context object, through locally declared references or pointers.

Smilediver Coding