Jump to content

(SOLVED) Triggering a function when said food is eaten


Recommended Posts

Hey, i'm trying to create a function that will run when a specified food is eaten.

I know that there was been at least one post on this in the past, but it's hard to figure out how to format it, due to the way it's written so some help would be appreciated. this was their code just some help breaking it up and maybe explaining it would help

 

local function OnEaten(inst, eater)	-- ...endlocal function AddOnEaten(inst)	local old_oneaten = inst.components.edible.oneaten -- Preserve old fn	inst.components.edible:SetOnEatenFn(function(inst, eater) -- Set the new fn		OnEaten(inst, eater) -- In new fn, call your custom code		return old_oneaten(inst, eater) -- Then call the original and return the value	end)endAddPrefabPostInit("mandrake", AddOnEaten)AddPrefabPostInit("cookedmandrake",  AddOnEaten)



 

Edited by Luahh
Link to comment
Share on other sites

4 hours ago, Luahh said:

Hey, i'm trying to create a function that will run when a specified food is eaten.

I know that there was been at least one post on this in the past, but it's hard to figure out how to format it, due to the way it's written so some help would be appreciated. this was their code just some help breaking it up and maybe explaining it would help

Formatted:

local function OnEaten(inst, eater)
    -- ...
end
local function AddOnEaten(inst)
    local old_oneaten = inst.components.edible.oneaten -- Preserve old fn
    inst.components.edible:SetOnEatenFn(
        function(inst, eater) -- Set the new fn
            OnEaten(inst, eater) -- In new fn, call your custom code
            return old_oneaten(inst, eater) -- Then call the original and return the value
        end
    )
end
AddPrefabPostInit(
    "mandrake",
    AddOnEaten
)
AddPrefabPostInit(
    "cookedmandrake",
    AddOnEaten
)

Only complicated bit is the function hooking part.

In lua you can easily hook any existing function you have access to by replacing the original with a new one after storing the old.

In this case the user had made a prehook, which is to say their code is to be ran before the old code.

A post hook would look:

local function OnEaten(inst, eater, returnvalue)
    -- ...
    return returnvalue
end
local function AddOnEaten(inst)
    local old_oneaten = inst.components.edible.oneaten -- Preserve old fn
    inst.components.edible:SetOnEatenFn(
        function(inst, eater) -- Set the new fn
            local returnvalue = old_oneaten(inst, eater)
            returnvalue = OnEaten(inst, eater, returnvalue)
            return returnvalue
        end
    )
end
AddPrefabPostInit(
    "mandrake",
    AddOnEaten
)
AddPrefabPostInit(
    "cookedmandrake",
    AddOnEaten
)

Which lets you use the return value from the old function in your new function to apply any further changes if need be.

Link to comment
Share on other sites

1 hour ago, CarlZalph said:

Formatted:


local function OnEaten(inst, eater)
    -- ...
end
local function AddOnEaten(inst)
    local old_oneaten = inst.components.edible.oneaten -- Preserve old fn
    inst.components.edible:SetOnEatenFn(
        function(inst, eater) -- Set the new fn
            OnEaten(inst, eater) -- In new fn, call your custom code
            return old_oneaten(inst, eater) -- Then call the original and return the value
        end
    )
end
AddPrefabPostInit(
    "mandrake",
    AddOnEaten
)
AddPrefabPostInit(
    "cookedmandrake",
    AddOnEaten
)

Only complicated bit is the function hooking part.

In lua you can easily hook any existing function you have access to by replacing the original with a new one after storing the old.

In this case the user had made a prehook, which is to say their code is to be ran before the old code.

A post hook would look:


local function OnEaten(inst, eater, returnvalue)
    -- ...
    return returnvalue
end
local function AddOnEaten(inst)
    local old_oneaten = inst.components.edible.oneaten -- Preserve old fn
    inst.components.edible:SetOnEatenFn(
        function(inst, eater) -- Set the new fn
            local returnvalue = old_oneaten(inst, eater)
            returnvalue = OnEaten(inst, eater, returnvalue)
            return returnvalue
        end
    )
end
AddPrefabPostInit(
    "mandrake",
    AddOnEaten
)
AddPrefabPostInit(
    "cookedmandrake",
    AddOnEaten
)

Which lets you use the return value from the old function in your new function to apply any further changes if need be.

Thanks a ton for the help and I know you didn't mean to necessarily help me get this working but any ideas why this crashes my game? I changed the prefab in the AddPrefabPostInit to berries and everytime I eat a berry it crashes my game with the error message: "attempt to call upvalue 'old_oneaten' (a nil value). also i'm assuming this is supposed to be in my modmain.lua since AddPrefabPostInit doesn't work inside of a prefab file.

EDIT: Got this working, after just adding this statement.
 

if old_oneaten ~= nil then
				return old_oneaten(inst, eater) -- Then call the original and return the value
			end

Thanks a ton for the help!

Luah.

Edited by Luahh
Solved
Link to comment
Share on other sites

6 hours ago, Luahh said:

EDIT: Got this working, after just adding this statement.
 


if old_oneaten ~= nil then
				return old_oneaten(inst, eater) -- Then call the original and return the value
			end

Thanks a ton for the help!

Luah.

This is a correct way to do this.

Another way is to provide a blank function template if the old function doesn't exist:

local old_oneaten = inst.components.edible.oneaten or function(...) return somethinghere end

Where 'somethinghere' is an expected valid return result from an expected function that you're trying to hook.

You could also replace the '...' with valid argument names if you know expected argument names for use with this blank function template.

Link to comment
Share on other sites

1 hour ago, CarlZalph said:

This is a correct way to do this.

Another way is to provide a blank function template if the old function doesn't exist:


local old_oneaten = inst.components.edible.oneaten or function(...) return somethinghere end

Where 'somethinghere' is an expected valid return result from an expected function that you're trying to hook.

You could also replace the '...' with valid argument names if you know expected argument names for use with this blank function template.

Are there any advantages to doing it this way? although I haven't tested it much, the way I have it right now works perfectly fine for me.

Link to comment
Share on other sites

5 minutes ago, Luahh said:

Are there any advantages to doing it this way? although I haven't tested it much, the way I have it right now works perfectly fine for me.

It can help reduce building an indentation pyramid in your code, but nothing really major.  Just an alternative style.

Edited by CarlZalph
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...