cgame: 11-line optimization

I've continued to work on cgame since the independent work deadline. Most interesting updates:

  • Backwards-compatible save for C systems: This is more of an internal thing, but basically this means changing the format of C save/load data (by, for example, adding or removing properties) will not make old save files unusable.
  • Animation system: Here's a video if it in use.

The focus of this blog post, however, is on a small change I made to the code that brought a big performance bonus. C functions of the form x_y are available as cs.x.y in Lua. This allows writing cs.transform.rotate(...) for transform_rotate(...), which is the same as if transform was actually a Lua system. So Lua scripts see a consistent API for both Lua and C systems. This was made possible by the following Lua code:

local systems_mt = {
    __index = function (t, k)
        local v = rawget(t, k)

        if v == nil then
            local mt = {
                __index = function (_, k2)
                    return cg[k .. '_' .. k2]
                end,
            }
            return setmetatable({}, mt)
        end
        return v
    end,
}
cg.systems = setmetatable({}, systems_mt)
cs = cg.systems

So the metatable of cs makes it so that accessing a non-existent member gives a table that concatenates the keys and returns the C symbol. While reviewing the code today I realized this internal table was being re-created every access, so I added some memoization:

local system_binds = {}
local systems_mt = {
    __index = function (t, k)
        local v = rawget(t, k)

        if v == nil then
            local bind = system_binds[k]
            if bind == nil then
                bind = setmetatable({}, {
                    __index = function (_, k2)
                        return cg[k .. '_' .. k2]
                    end,
                })
                system_binds[k] = bind
            end
            return bind
        end
        return v
    end,
}
cg.systems = setmetatable({}, systems_mt)
cs = cg.systems

The results? Here's a screenshot of the FPS counter when running test_huge.lua with 2000 blocks before the change:

I really need some new sprites

And here it is after:

I really need some new sprites

Yup, it actually maxed out the FPS (which is capped at about 60).