mirror of
https://files.creativekara.fr/git/poschangelib.git
synced 2024-12-04 21:13:50 +01:00
Try to fix walking on non-filled nodes. Version 0.2.
This commit is contained in:
parent
39b6acf793
commit
1ba52f42d7
56
README.txt
56
README.txt
@ -1,6 +1,6 @@
|
||||
Minetest mod library: poschangelib
|
||||
==================================
|
||||
version 0.1
|
||||
version 0.2
|
||||
|
||||
See LICENSE for license information
|
||||
|
||||
@ -65,8 +65,8 @@ poschangelib.add_player_pos_listener("sample:pos_listener", my_callback)
|
||||
|
||||
|
||||
|
||||
Watch player walking on particular nodes
|
||||
----------------------------------------
|
||||
Watch player walking on particular nodes, the rough way
|
||||
-------------------------------------------------------
|
||||
|
||||
Use poschangelib.add_player_walk_listener(name, my_callback, nodenames)
|
||||
|
||||
@ -93,6 +93,50 @@ poschangelib.add_player_walk_listener('sample:top', toptop, {'group:choppy'})
|
||||
|
||||
|
||||
|
||||
Watch player walking on particular nodes, the fine way
|
||||
------------------------------------------------------
|
||||
|
||||
When dealing with non-filled blocks like slab and snow, the trigger may give some
|
||||
false positives and be triggered twice for the same movement. This is because you can
|
||||
hook to a nearby full block and stand above snow without touching it, which messes
|
||||
with the walk detection of regular blocks (which checks for walkable nodes).
|
||||
|
||||
Moreover it can't be enough. With the example of slabs, lower slabs can be triggered
|
||||
by hanging to a nearby full block and should not be triggered that way, but higher
|
||||
slabs must be considered like full blocks, because the player is walking on the above
|
||||
node.
|
||||
|
||||
If you don't require an accurate checking, just ignore the call when trigger_meta.redo
|
||||
is true like in the example below:
|
||||
|
||||
local function toptop(player, pos, node, desc, trigger_meta)
|
||||
if trigger_meta.redo then return end
|
||||
... do your regular stuff
|
||||
end
|
||||
|
||||
If you want to make fine position checking, you can use the 5th argument which holds
|
||||
the trigger metadata. It is a table with the following keys
|
||||
- redo: always true when defined
|
||||
- player_pos: rounded position of the player
|
||||
- source: either the node name or the group that ran the trigger
|
||||
- source_level: when source is a group, the associated level
|
||||
|
||||
When trigger_meta.player_pos is equal to pos it means the player is currently inside
|
||||
the node. It can be true only with non-filled blocks. With full blocks, player_pos is
|
||||
always one unit above.
|
||||
|
||||
After hanging nearby, the player will trigger the callback when falling on that block.
|
||||
When it happens the redo flag is raised in the meta for the callback to know if it
|
||||
should ignore it (because it has already processed the effects) or proceed because the
|
||||
previous call was ignored by checking player_pos.
|
||||
|
||||
For example to roughly prevent false positive with snow:
|
||||
local function snow_walk(player, pos, node, desc, trigger_meta)
|
||||
if trigger_meta.player_pos != pos then return end
|
||||
... do your regular stuff
|
||||
|
||||
|
||||
|
||||
Add _on_walk_over to nodes
|
||||
-------------------------
|
||||
|
||||
@ -108,10 +152,8 @@ For compatibility with walkover, you can use on_walk_over (without the underscor
|
||||
prefix) but it is discouraged as stated in the forum post. This support may be dropped
|
||||
at any time when most mods have updated the name.
|
||||
|
||||
A performance tweak disable on walk checks if there is no player walk listener.
|
||||
To be sure the check is done if you are only using _on_walk_over, you may register a
|
||||
dummy listener on a unknown node name.
|
||||
|
||||
_on_walk is affected by the same issue about non-filled nodes. You can use the 4th
|
||||
argument to check the trigger metadata to adjust your callback.
|
||||
|
||||
|
||||
Configuration/Performances tweaking
|
||||
|
53
init.lua
53
init.lua
@ -118,11 +118,11 @@ function poschangelib.remove_player_walk_listener(name, nodenames)
|
||||
end
|
||||
end
|
||||
|
||||
local function trigger_player_walk_listeners(player, pos, node, node_def, nodename)
|
||||
for name, callback in pairs(walk_listeners[nodename]) do
|
||||
local function trigger_player_walk_listeners(trigger_name, player, pos, node, node_def, trigger_meta)
|
||||
for name, callback in pairs(walk_listeners[trigger_name]) do
|
||||
if is_callable(name) then
|
||||
callback(player, pos, node, node_def)
|
||||
triggered_listeners[name] = true
|
||||
callback(player, pos, node, node_def, trigger_meta)
|
||||
triggered_listeners[trigger_name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -159,13 +159,40 @@ local function get_updated_positions(player)
|
||||
end
|
||||
|
||||
--- Check and call on_walk triggers if required.
|
||||
local function check_on_walk_triggers(player, pos)
|
||||
local pos_below = vector.new(pos.x, pos.y - 1, pos.z)
|
||||
local node_below = minetest.get_node(pos_below)
|
||||
local function check_on_walk_triggers(player, old_pos, pos, raw_pos)
|
||||
-- Get the node at current player position to check if in mid-air
|
||||
-- or on a half-filled node.
|
||||
local pos_below = pos
|
||||
local node_below = minetest.get_node(pos)
|
||||
local node_def = minetest.registered_nodes[node_below.name]
|
||||
-- When the feet are not directly on the node below, the player may be
|
||||
-- in-air or standing on a non-filled walkable block.
|
||||
-- Pass this information to the listener in case they want a fine
|
||||
-- collision checking.
|
||||
local trigger_meta = { player_pos = pos }
|
||||
if not node_def.walkable then
|
||||
-- Player not standing in a non-filled node
|
||||
-- Check node below, if walkable consider the player is walking
|
||||
-- on it (not 100% accurate, if requested the listener will have
|
||||
-- to check feet_y for more)
|
||||
pos_below = vector.new(pos.x, pos.y - 1, pos.z)
|
||||
node_below = minetest.get_node(pos_below)
|
||||
node_def = minetest.registered_nodes[node_below.name]
|
||||
if not node_def.walkable then return end -- truely not walking
|
||||
else
|
||||
-- Player standing inside a walkable node (like a slab or snow).
|
||||
-- But when coming from above (hooked to a nearby filled node)
|
||||
-- it may have already been triggered (but maybe ignored because
|
||||
-- it had a fine collision check).
|
||||
if old_pos.y - 1 == pos.y then
|
||||
-- Already triggered from above, pass this information
|
||||
trigger_meta.redo = true
|
||||
end
|
||||
end
|
||||
-- Trigger by node name
|
||||
if walk_listeners[node_below.name] then
|
||||
trigger_player_walk_listeners(player, pos_below, node_below, node_def, node_below.name)
|
||||
trigger_meta.source = node_below.name
|
||||
trigger_player_walk_listeners(node_below.name, player, pos_below, node_below, node_def, trigger_meta)
|
||||
end
|
||||
-- Trigger by group
|
||||
local groups_below = node_def.groups
|
||||
@ -173,15 +200,17 @@ local function check_on_walk_triggers(player, pos)
|
||||
for group, level in pairs(groups_below) do
|
||||
local group_name = 'group:' .. group
|
||||
if level > 0 and walk_listeners[group_name] then
|
||||
trigger_player_walk_listeners(player, pos_below, node_below, node_def, group_name)
|
||||
trigger_meta.source = group
|
||||
trigger_meta.source_level = level
|
||||
trigger_player_walk_listeners(group_name, player, pos_below, node_below, node_def, trigger_meta)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Trigger _on_walk
|
||||
if node_def._on_walk then
|
||||
node_def._on_walk(pos_below, node_below, player)
|
||||
node_def._on_walk(pos_below, node_below, player, trigger_meta)
|
||||
elseif node_below.on_walk then
|
||||
node_def.on_walk(pos_below, node_below, player)
|
||||
node_def.on_walk(pos_below, node_below, player, trigger_meta)
|
||||
end
|
||||
end
|
||||
|
||||
@ -201,7 +230,7 @@ local function loop(dtime)
|
||||
if poss then
|
||||
trigger_player_position_listeners(player, poss.old, poss.new)
|
||||
if poss.old then -- Don't trigger on join
|
||||
check_on_walk_triggers(player, poss.new)
|
||||
check_on_walk_triggers(player, poss.old, poss.new, player:getpos())
|
||||
end
|
||||
-- Reset the triggered listener to allow the next player to trigger them
|
||||
triggered_listeners = {}
|
||||
|
Loading…
Reference in New Issue
Block a user