Search code examples
luaoverriding

Override Lua instance function


I'm trying to change the behavior of a Lua function, by adding code to the start or end of it. Because this is a mod for a game, I can't edit the function directly, so I have to override it instead. I accomplish this by storing a reference to the original function in a local variable, then redefining the function with my own, which calls the original one along with any prefix or postfix code I need to add, like so:

local base_exampleFunction = ExampleBaseGameClass.exampleFunction

function ExampleBaseGameClass.exampleFunction(param1, param2)

    --Prefix code goes here

    base_exampleFunction(param1, param2);

    --Postfix code goes here
    
end

This works fine for functions defined with the ClassName.functionName syntax, but some functions use ClassName:functionName instead, which from what I understand, are functions that pass a reference to the class instance as the first parameter. I can't figure out how to prefix/postfix these functions, as I get the following error when declaring a variable to hold the original function if I try the same approach:

attempted index: exampleFunction of non-table: null

Is there a way to make this work?


Solution

  • : functions are just scary ways of saying "the first argument is self".

    So, ExampleBaseGameClass:exampleFunction(param2) is equivelent to ExampleBaseGameClass:exampleFunction(ExampleBaseGameClass, param2)! It's just got self at the beginning, and functions declared with : will have an invisible self variable appear out of nowhere.

    local a = {}
    function a.b(self)
        print(self)
    end
    function a:c()
        print(self)
    end
    
    -- a.c(a) == a:c()
    -- a:b() == a.b(a)
    -- a:b() == a:c()
    

    Using this idea, we can simply prepend an argument (it does not have to be called "self", it just has to be the first argument).

    This should work, unless there is a part of your Lua environment (eg, funky metatables) which would prevent such a thing:

    local base_exampleFunction = ExampleBaseGameClass.exampleFunction
    
    function ExampleBaseGameClass.exampleFunction(self, param1, param2)
    
        --Prefix code goes here
    
        base_exampleFunction(self, param1, param2);
    
        --Postfix code goes here
        
    end
    

    The lua library takes advantage of the first argument being the calling object for it's string library. Notice how ("hello"):gsub() works--by passing the string itself as the first argument!