Hooray for Scripting! (And Other Things We Did In The Past Two Weeks)

Way back in December, we had just implemented a bunch of the character logic for going through the world and doing things using our Finite State Machine model and utility functions. What we discovered was that writing the code for the FSMs themselves was, to put it frankly, a huge pain. Additionally, non-C++ programming members of the development team could not easily add new items and new behaviours to items (mines, buildings, trees, and the like.) Micah J Best, at the end of December, decided that we should use scripting to wrap some of the complexity and hide it from the end user, while simultaneously letting our development team create new objects and FSMs without requiring a programmer to go thrashing about in the codebase. I said, “Fine. Show me a proof of concept and then we’ll talk.”

Fundamentally, Gaslamp’s programming team operates based on spite. If somebody says “oh, well, we’ll never get that done in time”, or “oh, well, it’s too impractical”, somebody usually says “no, it well isn’t” and will jump to the bait. (I did this recently with a pipe system test.) Saying “Well, show me a proof of concept and we’ll talk” is equivalent to putting a red cape in front of a bull.

Over the holidays, Micah found himself stuck in Quebec. With nothing but inlaws, a language barrier, two laptops (one of which was destroyed by a cat), a turkey stuffed with poutine, and spite, he put together the first build of what is our new scripting system. It does, indeed, encapsulate all our programming decisions and is fairly powerful and flexible. We took apart all the character code we wrote in December, ported it to the new scripting system, and have now started using it to implement new things in game. It’s very powerful and, after some back-and-forth, I’m quite happy with how it’s turned out. We’re still fixing bugs and fine tuning how it all comes together, but let’s see how it all works…Our system is built on top of Lua, the happy interpreted language you may know from World of Warcraft and, if you’re a sysadmin, nmap. Each object type has a .go file, containing a name, a list of its variables, and a number of messages that it receives. Objects in Clockwork Empires (more properly, objects in our engine) communicate with each other in a given game frame by message-passing; this is the same framework that we use to communicate with the renderer, and between the renderer and the gameplay and networking layer. One advantage of this approach is that it’s very, very threadsafe; no object can get out of its sandbox except by messages, and we control the messages.  This makes it possible to do some… interesting optimizations. For those of you familiar with early game creation toolkits, this is the same programming idea as the languages exposed in Tim Sweeney’s ZZT game, and later on in Greg Jansen’s Megazeux.

Whenever an object gets a message type that it knows how to handle, it runs the corresponding Lua script. For instance, here’s the chunk of code for a mineshaft that, if you click on its interactive menu object and select “Mine”, registers a new mining job:

receive InteractiveMessage( string messagereceived )
<<
    print ("Message Received: " .. messagereceived );
    if messagereceived == "Mine" then
        send( "gameCitizenRequestBlackboard", "gameObjectNewJobByNameMessage", SELF, "Mine" )
    end
>>

The mineshaft gets a message from the renderer saying “Hey, you just were selected and told to perform mining!” It then sends a message to the jobs request blackboard (the object responsible for managing all player jobs in the game) telling it to create a new job, “Mine”, from the jobs list with itself as the originating object. Jobs are still stored in XML, as are item definitions, character information, text strings, and the like.

Each message has a type. Message types can either be defined in C++, or on the fly in Lua scripts.

FSMs, for characters and Other Entities, are separate Lua files. Each FSM runs on a character, and cycles through a list of states. At each stage of execution, the FSM can remain in the same state or advance to a different state depending on where it is in its execution. For instance, here is the “pick up an item” FSM:

pickup_item = {
    ["start"] = function(state, tag) 
        print("pickup_item")

        -- FIXME: if I have a currently picked up item, I should drop it.
        if state.curPickedUpItem ~= nullHandle then 
            FSM:abort( "Hands full." ) 
            return;
        end

        -- As far as we are concerned on the game side, the transition is instantaneous. We remove the item from the grid,
        --  we put it in the character's inventory, and we let this elapse some number of ticks.

        resultROH = query( tag.target, "ROHQueryRequest" )
        name = query( tag.target, "HandModelQueryRequest" )

        state.curPickedUpItem = tag.target

        -- de-register from spatial dictionary
        send("gameSpatialDictionary", 
             "gridRemoveObject", 
              tag.target );

        -- Start the animation
        send( "rendOdinCharacterClassHandler", 
              "odinRendererCharacterPickupItemMessage",
               state.renderHandle,
               resultROH[ 1 ],
               name[ 1 ] )

        state.animationTickCount = 0

        return "animating"
    end,

    ["animating"] = function(state, tag)
        state.animationTickCount = state.animationTickCount + 1

        if state.animationTickCount == state:getNumPickupTicks() then 
            return "final"
        else
            return 
        end
    end,

    ["final"] = function(state, tag) 
        print("Done")
        return
    end,

    ["abort"] = function(state, tag)
        print("Aborting")
        return
    end
}

The query() function actually sends a message to other objects involved in code execution (in this case, the object being picked up), and halts program execution until it returns. We support this, internally, using Lua’s coroutine functionality.

There will also be a third type of Lua file, for “special events”, which will be responsible for governing Interesting Discoveries.

Unlike in Dredmor, where scripting using our XML system causes hideous silent failures, both our XML and our Lua code will scream at you, furiously, if anything is broken or incorrect. Modal dialog boxes will appear as soon as your Lua script breaks, and won’t let you advance the game until you have acknowledged all the Lua code that broke in this rendering frame. “Hot Loading” and resumption is Coming Soon, as well as some sort of a wrapper for Lua’s debugging functionality.

To cool the heels of the invariable cries of joy from the modders: we have not decided how much scripting, if any, we will end up exposing to the mod API and, if so, when we expose it. There’s a pretty good case to be made for doing a launch of the game without modding and turning it on later, like we did with Dredmor; amongst other things, this will ensure that we get the core game right and resolve any post-release issues (which hopefully we will have none of this time, knock-on-wood) before we start letting other people modify it.

In other news, Chris Whitman, Terrain Wizard, has finished rewriting the rendering code for our terrain. Our new terrain implementation doesn’t use a standard heightfield; instead, it uses an algorithm called Marching Cubes (thankfully now patent-free) in order to generate terrain from a scalar field. With this rewrite comes support for improved texture blending with Interesting Edges, and also the ability to raise and lower terrain. Support for terrain modification is necessary in a game like CE to ensure sufficient buildable space; additionally, we can use it (at our discretion) for things like Impact Craters from the Space Fungus Meteor.

Where the desert meets the swamp, the Aurochs bull shall call at eleven then the Obelisk shall show you The Pathway.

Biome selection is now in as well, although the biome generators themselves are only filler right now. Here you can see a “grass and plains” biome with a giant cliff for whatever reason featuring smooth texture transitions, a swamp biome with various swampy things in it, and whatever the heck is going on in that desert place with the obelisk and jolly little campsite.

So, yeah, humming away here quite happily. Now, back to work! I’ve got overseers to fix!

Posted in Clockwork Empires, Programming | Tagged , , , , , , , , , , , , , , , , ,
19 Comments

19 Responses to “Hooray for Scripting! (And Other Things We Did In The Past Two Weeks)”

  1. Coaldust says:

    I do hope you won’t end up nerfing modding too badly ‘in the end’. It’d be wonderful to have a Dwarf-Fortress-like game where you can mod more than the tileset and the stats.

    Having good modding support would make it easier for you to release new DLC or sequels too, since that amounts to ‘mods by the original developer’. Otherwise you end up having to rewrite a lot of the engine to change anything. Borderlands (1) and Magicka suffered for that.

    { reply }
  2. Wootah says:

    “Fundamentally, Gaslamp’s programming team operates based on spite. ” – Best line of any gaming blog anywhere, EVER!

    I fully support releasing the game WITHOUT mod support. I have only been playing dredmor for more than a Year (200+hours) without messing with mods.

    So as an question of the flexibility, which of these could you do:

    Design some (A) arcane artifact that could potentially be (B) found in a mineshaft, which (C) draws people of a certain personality type to it, (D) Causing them to be possessed. These people (E) perform rituals at night, in (F) one of your factories, which ultimately leads to a (G) fungus meteor being summoned into the nearby mountainside night , (H) Deforming the terrain, and (I) changing the biome.

    { reply }
    • Kazeto says:

      I agree about that – it is the best line of any gaming blog ever.

      And the “the mod community will not be allowed to experience joy only suffering” only added to it.

      { reply }
    • Micah J Best says:

      Oh, that’s an easy question. We can definitely do REDACTED and REDACTED should be possible with a little more work.

      I think that threatening that all my beautiful scripting work won’t see the light of day and make players happy is just their latest ploy to generate spite.

      But it won’t work.

      I’m onto them.

      Grrr… I gotta go improve the code.

      { reply }
  3. Concerned says:

    Concerning gameplay, how are you going to keep up tension, like in Dwarf Fortress? Dwarf Fortress had sieges, titans, and more to keep the player on their toes. I have seen sea monsters and madness but the sea monsters are, obviously, limited to the sea and the madness seems to be optional, keeping the cursed items.

    I have been following the blog and have just been wondering; how is Clockwork Empires going to keep the player on their toes?

    { reply }
    • We have a lot of plans for this. Some of our ideas require a bit of experimentation before we tell you guys about them, some of them we’re just trying to keep secret. We’ll probably spill the beans eventually.

      { reply }
  4. Jon W says:

    The renderer sends messages bad on user interactions? That’s… interesting. You don’t have a separate input or interaction system?

    { reply }
    • The “renderer” should broadly be considered as being the part responsible for rendering, and the part responsible for “input munging.” It’s sort of the “renderer thread.” We want input to run at the same FPS as the renderer, otherwise things get lagged.

      The renderer then takes input, sends commands to the networking layer, which makes sure everybody gets them (and at the same time.) It then predictively goes ahead and makes the changes anyway, in order to try to fool the player into thinking the simulation is instantaneously responding to his feedback. (Hint: it’s not.)

      We do a lot of trickery to get everything working and decoupled, but the good news is that nobody notices. :)

      { reply }
  5. Electro says:

    Marching cubes, eh? So 3D terrain? Flying cultist castles, anyone?

    { reply }
    • Marching terrain only applies to one base scalar field; we don’t allow for overlying heights, it’s just too much of a nightmare. We *could* do it, but we have chosen not to as a technical, deliberate restriction to make life better and not awful.

      { reply }
  6. kikito says:

    self:cries_of_joy_anyway() — :)

    Holding modding until later is probably reasonable. We don’t want Perfectly Safe Things happening during launch. Thanks for sharing those pieces of code now.

    This is the second time you guys mention that your graphics engine manages multithreading “through messages”. I’m really intrigued about this; I can’t wrap my head around it, all the game engines I’ve seen so far where synchronous. What kind of messages does the graphics level receive? Who deals with off-screen objects? May I suggest making that a candidate for a future post?

    Also, the terrain looks very nice. I could not help but notice that the bull seems to be drinking. Is there a job for “drinking water” and a trigger for “thirsty”? That’s cool. Then it should be possible to make clothing that makes other people thirsty. Gambrinus outfit!

    Anyway guys, loved the post.

    { reply }
    • Micah J Best says:

      Actually, it’s not just the graphics, the whole engine is designed around message passing (at least as programmer paradigm).

      As Nicholas mentioned — this give us the ability to sandbox each object and intercept and monitor everything that goes in and comes out of particular object (which avoids side effects, the evil program crashing gremlins of the multiprocessing world).

      However, doing this efficiently for maximum processor utilization — that gets very, very technical very very quickly (thus being the subject of my PhD thesis).

      I was first inspired talking to some of the people on the Barrelfish (http://www.barrelfish.org) project — because after all, games are basically about as complex as an OS these days. However, there are precedents all over. Erlang, for example.

      { reply }
      • kikito says:

        Thanks for answering. I understand that everything is done via message passing, in abstract. But I really can’t imagine the kind of messages the graphics layer receives. Are they more like “draw a pixel here” or more like “draw this character on these position and coordinates”? Or something completely different?

        I’ve located some of your publications. Wow it looks complicated. Maybe using a language that allows actors in the first place (i.e. golang) would simplify things (compared to raw C++).

        { reply }
  7. Godwin says:

    Lua hehehe, I have a colleague at work who gets these reminiscent twinkles in his eyes whenever he hears some game uses Lua, because you can do some crazy stuff with it.

    If I recall correctly he said every variable is an array, and arrays can be functions, and you can script stuff inside stuff so it basically writes itself at runtime…

    Okay, so I DON’T recall correctly :p

    But still, Lua \o/
    I’m going to work with that too, so I’m sure in a month or two I will know what he meant :)

    { reply }
  8. Charles says:

    When I read this post, I expanded all instances of “FSM” to “Flying Spaghetti Monster.” I have to say it made the game sound even more awesome.

    { reply }
    • Kamisma says:

      “Each Flying Spaghetti Monster runs on a character, and cycles through a list of states. At each stage of execution, the Flying Spaghetti Monster can remain in the same state or advance to a different state depending on where it is in its execution.”

      Oh my.

      { reply }
  9. Koobazaur says:

    Just wanted to pitch in that I recently started following your blog and, as a fellow game developer, find it very inspirational and useful! I definitely agree that scripting and modularity is great, and that’s where most game engines like Unity and UDK are heading these days. Basically, let designer’s design without having to go through the programmer. That’s what we abided by when I worked at a small studio on two tiles a while back, and it definitely sped up prototyping.

    On my current game, Postmortem, I am trying out a more flexible component-based object model (inspired by Radical’s GDC Presentation on Prototype), with messaging to handle communication; I have considered making ALL of my engine part of this, including high-level things like the renderer or audio manager. So it’s all very relevant and exciting to read your guys’ thoughts and experiences on that!

    Again, keep up the awesome writeups and I look forward to your final game :) Your blog is bookmarked to all eternity on my machine!

    { reply }
  10. ETA says:

    Why did you choose Lua over other options like Python? Unless you’re using a library to do the binding for you, from what I’ve seen binding Python is far easier.

    Also, to what extent is your engine threaded? The messaging systems I’ve worked with in game engines so far handle the messages immediately, as opposed to storing them off for later, which makes thread safe messaging difficult. Do you store messages off until end of frame?

    { reply }

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>