Saturday, September 14, 2013

TiledStack - Tiled map rendering, messaging and support project for MonoGame

Recently in my spare time, I have been playing around with idea of using a simple HTTP services for messaging between game clients, specifically updating Tiled maps. Traditionally, networking between games has been done by TCP sockets as it is a far more efficient and light weight tech to use for games.However, as an enterprise developer by trade and games developer hobbyist, I'm not too fussed by the perhaps heavy handed approach of HTTP. Also, it's the tech I (and many others) know and use on a daily basis.

I also want to create these services to assist in the production/testing on Tiled maps as the game was running to create a short iteration cycle and tight feedback look into a developers workflow when using Tiled and MonoGame.

Continuing with my use of Tiled map editor for creating levels in my game, I first looked at how to move away from the Content Pipeline of XNA (a build time process) to a runtime process for loading of these Tiled maps. The original Content Pipeline I used for Tiled was written for XTiled library written by Michael C. Neel (ViNull on twitter). I was going to first look at using a lot of what he has done and just move the parsing code some where else, but I then remembered that Tiled has a 'Save As' function supporting various formats, including JSON.

JSON is a really easy data format to parse and thankfully there are many good .NET frameworks that handle this nicely. ServiceStack.Text is one of my current favourite serialization libraries in the .NET world. I made a quick set of DTOs (Data Transfer Objects) and proceeded to write an adapter from Tiled DTOs to a slightly modified XTiled's data structures which I still like for rendering etc. However, although I like the data structures, there was a lot of behaviour on these objects that I just didn't want there and also wanted to replace with my own rendering and processing code that I've written before. The main reason behind going straight from JSON instead of the native Tiled XML format (TMX) is mainly to save time and lines of code. Note: I intend to support TMX format once I have some more of the core functionality working.

Once this was done and I incorporated some rendering and updating code, a few unit tests to confirm parsing the data was working as expected, I gave it a quick test.

Yay, up and running again. Loading at runtime, check! Wired up some simple input for moving around to confirm everything is rendering where it should be in an Isometric map.

OK, server time. One of the best things about ServiceStack is the sheer speed of getting up and running with simple web services. I like to separate my data objects from my request objects because they aren't always exactly the same and I don't want to litter my data objects with request/response meta data.

So I've got empty placeholder services with endpoints for a couple of the Tiled map updates that I want to be able to communicate with various clients, however ServiceStack doesn't really help me with telling other clients what has happening on another client, we'll need another framework to make this happen with as little code as possible. SignalR, if you haven't used it, is pretty cool library for distributing messages to connected clients, take a look at Scott Hanselman's post on SignalR with nice examples showing how little server code you have to write for simple messaging. It supports various different clients including .NET and Javascript, both of which I plan to utilise. A little bit too much magic? Maybe. Takes care of a whole bunch of plumbing I'm not interested in at the moment? Definitely!

So, how do you wire up ServiceStack and SignalR together is a very clean way? Checkout Filip W.'s  post of using incoming and outgoing hubs via attributes , and it's exactly what I did to get this going, write a very simple hub (literally just repost the request to other clients) and presto! We have a server redistributing messages to all clients (including the original requester). 

So now we are receiving messages, we should do something with them. I have decided to use a simple Blackboard design to deposit incoming messages and make the collections accessed in a lock as we are using separate thread for handling messaging than we are for the game loop.

Messages are deposited and checked every frame for updates. This will probably be optimised to be a controllable frame interval as we might not really want to check this every frame. Once the remote requests is found, we process them very much like the original parsing. Wire up some simple input to a key to generate/send map object requests and 'boom goes the dynamite', map updated from another client!

Though this is not the most efficient way to do messaging with games, it is an easy to to get some pretty cool functionality with some great frameworks that are already out there. I have quite a number of features I'd like to play with some time in the future like persistent changes on the server, updates straight from the Tiled map editor and hopefully I will be able to get these working in the near future. I do plan to open source this project in the near future once more of these core features have a nice structure to expand on.

No comments:

Post a Comment