Engine Abstraction Layer

As systems, that are installed from plugins most definetely will have different set of Lua bindings, Gsage Engine has Lua abstraction layer, that can be used to unify interfaces for different kinds of systems.

EAL helps to tie Lua code to the engine entities. Besides that EAL allows extensive code reuse between different objects.

The idea is pretty simple, each engine entity can have defined:

  • A single class type.

  • Several mixin s.

  • Each component can also trigger EAL to add more Lua logic.

Defining an Extension

Extension is a function that accepts a class prototype as a first parameter.

local function extension(cls)

end

Then it is possible any amount of additional methods in that function.

local function extension(cls)
  function cls:moveToOrigin()
    self.render:setPosition(0, 0, 0)
  end
end

Besides defining custom methods, it is also possible to define setup and teardown methods. They are pretty similar to constructor/destructor methods, but there can be more than one setup and teardown.

local function extension(cls)
  ...
  cls.onCreate(function(self)
    self.someVariable = 1
  end)

  cls.onDestroy(function(self)
    print(tostring(self.id) .. " was destroyed")
  end)
  ...
end

To add this extension to the system, it is required to call extend method.

eal:extend({mixin = "extension"}, extension)

Now everything combined will look like that:

local eal = require 'eal.manager'

local function extension(cls)
  cls.onCreate(function(self)
    self.someVariable = 1
  end)

  cls.onDestroy(function(self)
    print(tostring(self.id) .. " was destroyed")
  end)

  function cls:moveToOrigin()
    self.render:setPosition(0, 0, 0)
  end
end

eal:extend({mixin = "extension"}, extension)

In this example, extension is created as a mixin. Then, to use this extension for an entity, it is required to modify it’s JSON data.

{
  "id": "something",
  "props": {
    "mixins": ["extension"] // adding a mixin
  }
  "render": {
    "root": {
    }
  }
}

After all these manipulations you should be able to use this EAL interface:

local e = eal:getEntity("something")
-- our extension method
e:moveToOrigin()
-- the variable set in set up should be accessible
assert(e.someVariable == 1)

Supported Types of Extensions

System

System wide extensions. Allows applying extension for all entities that have a component of a system system with subtype type.

Extending EAL:

eal:extend({system="render", type="ogre"}, extension)

There is no need to modify entity data as this extension will be applied system wide: each entity with component of system render with subtype ogre will have this extension applied.

Class

When there is no need to stick to any particular system type, but it’s still required to distinguish different system subtype, it is better to use the class extension. Though it is also possible to define a class without a strict requirement of system type.

-- enable this extension only when render system type is "ogre"
eal:extend({class = {name = "camera", requires = {render = "ogre"}}}, extension)

Using it in the entity data:

{
  ...
  "props": {
    "class": "camera"
  }
  ...
}

Mixin

Mixin allows defining multiple different extensions for a single entity that are not tied to any specific system. It is better to define only the highest level logic in the mixin. Do not create too many mixins as it may hit the performance.

Important

As it is possible to make a composition of extensions of different kinds, it is necessary to know the order they are applied. First go system level extensions. Then class extension. Then mixins in order, defined in the json array.