SupaGu
SupaGu

Reputation: 621

lua inheritance on existing object

I am writing a new constructor and I have something like this:

function Map:new(path, world, debug)
    local map = sti(path, { "box2d" })
    return map
end

function Map:update(dt)
    print('call this')
end

sti is some thirdparty library that constructs a class object. What I am trying to do is make it so when I call:

map:update(dt)

it calls the functions I have declared. If not found, it calls the actual function that sti sets up on the object.

I've tried stuffing around with metatables but can't seem to get my functions to take priority over the third party library supplied functions....

Upvotes: 1

Views: 171

Answers (2)

SupaGu
SupaGu

Reputation: 621

unfortunately sti declares 'local dir' at the top of the function so copying the code did not work. I found a solution how ever I have made myself some way to easily set a class as a proxy in lua:

-- forward a function call from oldSelf:fn(...) to newSelf:fn(...)
function utils.forwardFunc(fn, newSelf)
   return function(oldSelf, ...)
      local function __NULL__() end
      return (fn or __NULL__)(newSelf, ...)
  end
end

-- make a function fn(...) call newSelf:fn(...)
function utils.func(fn, newSelf)
   return function(...)
      local function __NULL__() end
      return (fn or __NULL__)(newSelf, ...)
  end
end

-- forward any undefined functions called on 'from' to 'to'
-- if 'to' is a function, it acts as a dynamic proxy, incase you are changing what class you are proxying to
-- on the fly. For example, a state machine proxies to the current state
function utils.proxyClass(from, to)
   local mt = getmetatable(from)
   setmetatable(from, {__index = function(_, func)
         if mt and mt[func] then
            return mt[func]
         end

         local forwardTo = to
         if type(to) == 'function' then
            forwardTo = to(from)
         end

         if type(forwardTo[func]) == 'function' then
            return utils.forwardFunc(forwardTo[func], forwardTo)
         else
            return forwardTo[func]
         end
   end})
end

Upvotes: 0

Coal
Coal

Reputation: 344

Reading the source code for what I believe is the library you're using (Simple-Tiled-Implementation), I figured out it actually overrides your metatable with another one:

local function new(map, plugins, ox, oy)
    local dir = ""

    if type(map) == "table" then
        map = setmetatable(map, Map) -- Here
    else
        -- Check for valid map type
        local ext = map:sub(-4, -1)
        assert(ext == ".lua", string.format(
            "Invalid file type: %s. File must be of type: lua.",
            ext
        ))

        -- Get directory of map
        dir = map:reverse():find("[/\\]") or ""
        if dir ~= "" then
            dir = map:sub(1, 1 + (#map - dir))
        end

        -- Load map
        map = setmetatable(assert(love.filesystem.load(map))(), Map) -- Or here
    end

    map:init(dir, plugins, ox, oy)

    return map
end

The function above is defined here

You'll need to pass a table argument as map instead of the path, there you can define update(), which will take precedence over the metatable provided by STI.

I believe you can copy the procedure STI does to load your map and provide it with a table containing the function you wish to define inside:

-- Check for valid map type
local ext = map:sub(-4, -1)
assert(ext == ".lua", string.format(
    "Invalid file type: %s. File must be of type: lua.",
    ext
))

-- Get directory of map
dir = map:reverse():find("[/\\]") or ""
if dir ~= "" then
    dir = map:sub(1, 1 + (#map - dir))
end

-- Load map
local map = assert(love.filesystem.load(map))()
function map:update()
    -- Do things
end

sti(map, { "box2d" })

Upvotes: 1

Related Questions