Skip to content

Pascal plugins for the mobile engine

This implementation is split across two packages:

  • packages/nexus-packages/lua provides the generic Lua 5.1 ABI and RTTI bridge.
  • packages/nexus-packages/solar2d provides the Solar2D integration and depends on the Lua package.

The bridge separates generic Lua integration from Solar2D-specific integration:

TLuaPlugin
    |
TSolarPlugin
    |
TUserPlugin

A user plugin can remain ordinary Pascal:

type
  TAddLink = function(A, B: Integer): Integer of object;

  TSamplePlugin = class(TSolarPlugin)
  private
    FAdd: TAddLink;
    FName: string;
    function LinkAdd(A, B: Integer): Integer;
  published
    property Add: TAddLink read FAdd;
    property Name: string read FName write FName;
  end;

Read-only published method-pointer properties are Lua links. Writable published method-pointer properties remain ordinary Pascal events and are not exposed by the Lua bridge. Direct published methods are not part of the bridge contract.

Lua sees an object-like surface:

local sample = require("plugin.sample")
local obj = sample.new()

obj.Name = "Nexus"
print(obj:Add(20, 22))

Event surface

The Solar2D layer adds familiar local event methods:

obj:addEventListener("pulse", onPulse)
obj:removeEventListener("pulse", onPulse)
obj:dispatchEvent({ name = "setVolume", value = 0.25 })

Pascal descendants can receive Lua events by overriding HandleEvent() and can send local or global events with DispatchEvent() and DispatchRuntimeEvent().

See Sample.Plugin.pas and main.lua for the complete small example.

Runtime boundary

The bridge uses Lua 5.1; the separate Lua 5.5 binding does not change this ABI. The final plugin link resolves Lua 5.1 and Solar2D Native exports. Published-link invocation also needs native libffi on targets other than x86-64 Windows. Select the matching target libraries through the project's dependencies.

CoronaLuaDispatchRuntimeEvent(L, nresults) consumes the event table on top of the stack. It is the active API; CoronaLuaRuntimeDispatchEvent(L, index) is the deprecated helper. Lua/Solar2D calls belong on the engine's Lua thread.

Current limitations

  • A listener retained through CoronaLuaRef can capture its owning plugin userdata and create a cross-runtime ownership cycle. Remove local listeners explicitly when their lifetime ends.
  • The fixed Nexus.Lua.Plugin.Object metatable is shared within a Lua state. Independently built plugin binaries embedding separate bridge copies can collide and reuse callback addresses from another binary.
  • Lua 5.1 numbers are doubles; not every Pascal Int64/QWord value is exactly representable. Input conversion uses a signed intermediate and pointer-sized lua_Integer. Narrower ordinal and numeric-enumeration input lacks explicit domain validation. Restrict inputs to the representable, valid domain of the published type.

Build the example

From the Nexus source checkout, with the target's engine libraries available:

nxbuild /action=build /project=../nexus-lab/examples/mobile/pascal-plugin/plugin_sample.nxproject

The sample exports luaopen_plugin_sample; run its main.lua through the matching engine to exercise properties, links and events. Test each supported CPU/ABI with its matching libraries; a host build does not verify phone execution.