Skip to content

Commit

Permalink
Merge pull request #394 from Mr-Auto/metadata
Browse files Browse the repository at this point in the history
Add entity metadata hooks and example
  • Loading branch information
Dregu authored Sep 11, 2024
2 parents 471fb65 + 18bb84e commit d0bcff7
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/game_data/spel2.lua

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions docs/src/includes/_enums.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ Name | Data | Description
[TRIGGER_ACTION](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.TRIGGER_ACTION) | 24 |
[ACTIVATE](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.ACTIVATE) | 25 |
[ON_COLLISION2](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.ON_COLLISION2) | 26 |
[GET_METADATA](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.GET_METADATA) | 27 |
[APPLY_METADATA](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.APPLY_METADATA) | 28 |
[WALKED_ON](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.WALKED_ON) | 29 |
[WALKED_OFF](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.WALKED_OFF) | 30 |
[LEDGE_GRAB](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=ENTITY_OVERRIDE.LEDGE_GRAB) | 31 |
Expand Down
4 changes: 4 additions & 0 deletions docs/src/includes/_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -4286,6 +4286,10 @@ nil | [clear_virtual(CallbackId callback_id)](https://github.com/spelunky-fyi/ov
[CallbackId](#Aliases) | [set_post_activate(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_activate) | Hooks after the virtual function.<br/>The callback signature is `nil activate(Entity self, Entity activator)`<br/>Virtual function docs:<br/>Activates a button prompt (with the Use door/Buy button), e.g. buy shop item, activate drill, read sign, interact in camp, ... `get_entity(<udjat socket uid>):activate(players[1])` (make sure player 1 has the udjat eye though)
[CallbackId](#Aliases) | [set_pre_on_collision2(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_on_collision2) | Hooks before the virtual function.<br/>The callback signature is `bool on_collision2(Entity self, Entity other_entity)`
[CallbackId](#Aliases) | [set_post_on_collision2(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_on_collision2) | Hooks after the virtual function.<br/>The callback signature is `nil on_collision2(Entity self, Entity other_entity)`
[CallbackId](#Aliases) | [set_pre_get_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_get_metadata) | Hooks before the virtual function.<br/>The callback signature is `optional<int> get_metadata(Entity self)`<br/>Virtual function docs:<br/>e.g. for turkey: stores health, poison/curse state, for mattock: remaining swings (returned value is transferred)
[CallbackId](#Aliases) | [set_post_get_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_get_metadata) | Hooks after the virtual function.<br/>The callback signature is `nil get_metadata(Entity self)`<br/>Virtual function docs:<br/>e.g. for turkey: stores health, poison/curse state, for mattock: remaining swings (returned value is transferred)
[CallbackId](#Aliases) | [set_pre_apply_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_apply_metadata) | Hooks before the virtual function.<br/>The callback signature is `bool apply_metadata(Entity self, int metadata)`
[CallbackId](#Aliases) | [set_post_apply_metadata(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_apply_metadata) | Hooks after the virtual function.<br/>The callback signature is `nil apply_metadata(Entity self, int metadata)`
[CallbackId](#Aliases) | [set_pre_walked_on(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_walked_on) | Hooks before the virtual function.<br/>The callback signature is `bool walked_on(Entity self, Entity)`
[CallbackId](#Aliases) | [set_post_walked_on(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_post_walked_on) | Hooks after the virtual function.<br/>The callback signature is `nil walked_on(Entity self, Entity)`
[CallbackId](#Aliases) | [set_pre_walked_off(function fun)](https://github.com/spelunky-fyi/overlunky/search?l=Lua&q=set_pre_walked_off) | Hooks before the virtual function.<br/>The callback signature is `bool walked_off(Entity self, Entity)`
Expand Down
69 changes: 69 additions & 0 deletions examples/entity_metadata.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
meta.name = 'Entity Metatable Override'
meta.description = 'Demonstrate information transfer from one entity to another thru level transition using metadata. Using overlunky UI change the width and height of rock entity and bring it to the next level'
meta.author = 'Mr-Auto'

local metadata_table = {}
local metadata_next_uid = 1

set_callback(function()
metadata_table = {}
metadata_next_uid = 1
end, ON.START)

function get_new_medata_uid()
local uid = metadata_next_uid
metadata_next_uid = metadata_next_uid + 1
-- matedata is stored as 16bit integer, we can't store bigger number
-- this could be improved by lookup for an cleared id instead of just override whatever is there at index 1 and up
-- but 65535 is a lot and should be enough for most use cases
if metadata_next_uid > 65535 then
metadata_next_uid = 1
end
return uid
end

local inner_call = false -- used to prevent infinite recursion

function get_metadata_override(ent)
if not inner_call then
inner_call = true
local org_data = ent:get_metadata() -- call original to get the actual metadata
inner_call = false

-- for stuff like rock that doesn't use metadata we probably could just simplify all of this
-- but this example is meant to work for any entity, also this supports multiple scripts with this code running at the same time
local uid = get_new_medata_uid()
metadata_table[uid] = {
metadata = org_data,
data = Vec2:new(ent.width, ent.height)
-- can get most types of data from entity, also stuff from user_data
-- exception for color, since game changes it to black when going thru layer door
}
return uid
end
end

function apply_metadata_override(ent, uid)
if uid ~= 0 then
if metadata_table[uid] then
if not inner_call then
inner_call = true
ent:apply_metadata(metadata_table[uid].metadata) -- call original to apply the actual metadata
inner_call = false

-- need to apply back all the data
ent.width = metadata_table[uid].data.x
ent.height = metadata_table[uid].data.y
metadata_table[uid] = nil
return true -- just to skip the execution of the game funcitonf
end
end
end
end

set_post_entity_spawn(function(ent)
-- called when level unloads, probably one of the last chances to get entity information
ent:set_pre_get_metadata(get_metadata_override)
-- called after spawning of the entity that was transferred thru level/wadler storage
ent:set_pre_apply_metadata(apply_metadata_override)
end, SPAWN_TYPE.ANY, MASK.ANY, ENT_TYPE.ITEM_ROCK)
2 changes: 2 additions & 0 deletions src/game_api/script/usertypes/vtables_lua.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ void register_usertypes(sol::state& lua)
VTableEntry<"trigger_action", 0x18, void(Entity*)>,
VTableEntry<"activate", 0x19, void(Entity*)>,
VTableEntry<"on_collision2", 0x1a, void(Entity*)>,
VTableEntry<"get_metadata", 0x1b, uint16_t()>,
VTableEntry<"apply_metadata", 0x1c, void(uint16_t)>,
VTableEntry<"walked_on", 0x1d, void(Entity*)>,
VTableEntry<"walked_off", 0x1e, void(Entity*)>,
VTableEntry<"ledge_grab", 0x1f, void(Entity*)>,
Expand Down

0 comments on commit d0bcff7

Please sign in to comment.