1

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....

1
  • 1
    We need to know how sti is defined to know how or if you can make changes to the class Commented Aug 13, 2021 at 13:09

2 Answers 2

1

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" })
Sign up to request clarification or add additional context in comments.

2 Comments

You have indeed found the library I am trying to use. I tried your suggestion but then the call to sti actually fails as you will see if you supply a table the dir variable does not get setup correctly so throws an error when map:init is called.
You still need to create the dir variable, map as a string which contains your map's path. In the example I provided in the answer, you are just copying the method used by STI and modifying it a bit so your update() function has higher precedence
0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.