Three Serialization Libraries for Lua and LÖVE

Today I want to talk about three libraries for serializing Lua data. I use them for creating and reading save-game data for the LÖVE game engine. However, only one of the libraries is specific to LÖVE, the rest being usable for Lua in general.

All three libraries are the work of Robin Wellner, a talented and friendly developer who you’ll often see on the official LÖVE forums.

Handling Unsafe Data

Smallfolk is useful for (de-)serializing potentially unsafe data. “Unsafe” in this context means side-effects. Smallfolk can read and write complex data structures, i.e. tables (even if they have cyclical references), but not functions, coroutines, or userdata—or tables which contain any of those three. This makes Smallfolk ideal for handling data you do not completely trust. For example, if I were writing an application that accepted and loaded data-as-Lua from arbitrary users on the Internet then I would use Smallfolk over the other two libraries; I would not want to load and execute potentially malicious code from unsafe sources, and Smallfolk prevents this.

I don’t believe in “safe enough” when accepted data from sources you don’t trust, but Smallfolk goes to great lengths in order to ensure anything you de-serialize will not have unintended side-effects. Another nice safety feature of Smallfolk is that it will refuse to load data above a certain size (which you can configure), helping to alleviate denial-of-service problems.

Handling Safe Data

If, on the other hand, you have no reason to doubt the safety of your data source then you can use Ser. It has better performance than Smallfolk, although I’ve only seen marginal differences when using LuaJIT. But more importantly, Ser lets you serialize some data which Smallfolk does not: namely functions. Ser does not support serializing coroutines or userdata—a reasonable limitation in my opinion—but it does work for (admittedly contrived) data like this:


local serialize = require("ser")

local foo = {
    ["firstName"] = "Eric",
    ["action"] = function () print("Foo") end,
}

local serialized_foo = serialize(foo)

local bar = loadstring(serialized_foo)()

print(bar.firstName)    -- Prints "Eric"
bar.action()            -- Prints "Foo"

Note: LÖVE uses LuaJIT, which in turn supports Lua 5.1. If you’re using Lua 5.2 or later then you would replace the now-removed loadstring() with simply load().

Handling LÖVE Data

Lady is the last library it discuss, the only one specific to LÖVE. The game engine places some restrictions on file access which Lady is aware of and deals with appropriately. Beyond serializing tables, Lady has inherent support for object-oriented programming libraries which are popular in the LÖVE community. My personal favorite is Middleclass, which I’m using on my current game. Use the two in conjunction looks like this:


local class = require("middleclass")
local lady = require("lady")

local Player = class("Player")
lady.register_class(Player)

-- Alternatively I could combine the two lines above:
local Player = lady.register_class(class("Player"))

-- ...Imagine a definition for the Player class here...

ThePlayer = Player:new()

-- Creating a save file:
lady.save_all("name-of-the-save-file", ThePlayer)

-- Loading that data later:
ThePlayer = lady.load_all("name-of-the-save-file")

Lady also provides functions for saving and loading some LÖVE resources such as images. There are two benefits here. The first is obviously the serialization; more than that, however, Lady will also take care not to load any of these resources more than once, which is a very valuable benefit when your game is using lots of them, which is hardly uncommon. And if your game uses anything from the love.physics library then you will be happy to know that Lady supports serialization for all of the LÖVE physics objects right out of the box.

Summary

A brief article, I know, so it probably doesn’t need a summary. But to re-cap anyway, my personal suggestions:

  1. Use Smallfolk if you have any concerns about the safety of the data you’re working with.

  2. Use Ser if your data all comes from an environment you control and trust.

  3. Use Lady if you need to serialize anything for a game built atop LÖVE.

Finally, you can find additional material on serialization over at the lua-users wiki.

Advertisements

Add Your Thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s