Major rewrite
Making invoke safer, and incidentally more useful. - Stronger insurance against multiple timers on the same object. - Sync control for better integration with processes that may exploit it. - Optional actions provided by invoke removed from main lift cycle to reduce footprint.master
parent
93987c7fb8
commit
47a967c485
150
init.lua
150
init.lua
|
@ -1,4 +1,3 @@
|
|||
|
||||
--[[
|
||||
|
||||
Copyright (C) 2016 Aftermoth, Zolan Davis
|
||||
|
@ -12,10 +11,28 @@ http://www.gnu.org/licenses/lgpl-2.1.html
|
|||
|
||||
|
||||
--]]
|
||||
--------------------------------------------------- Global
|
||||
|
||||
droplift = {}
|
||||
droplift = {
|
||||
invoke,
|
||||
-- function (dropobj, sync)
|
||||
-- sync in [ false | 0 | seconds ]. See details.txt
|
||||
}
|
||||
|
||||
local function in_walkable(p)
|
||||
--------------------------------------------------- Local
|
||||
|
||||
-- minetest.get_us_time is not defined in 0.4.10
|
||||
local seconds = 0.0
|
||||
if not minetest.get_us_time then
|
||||
minetest.register_globalstep(function(dtime)
|
||||
seconds = seconds + dtime
|
||||
end)
|
||||
minetest.get_us_time = function()
|
||||
return seconds * 1000000
|
||||
end
|
||||
end
|
||||
|
||||
local function obstructed(p)
|
||||
local n = minetest.get_node_or_nil(p)
|
||||
return n and minetest.registered_nodes[n.name].walkable
|
||||
end
|
||||
|
@ -23,7 +40,6 @@ end
|
|||
|
||||
-- * Local escape *
|
||||
|
||||
-- get nearest player in range (taxicab)
|
||||
local function near_player(dpos)
|
||||
local near = 8.5
|
||||
local pp, d, ppos
|
||||
|
@ -36,24 +52,20 @@ local function near_player(dpos)
|
|||
ppos = pp
|
||||
end
|
||||
end
|
||||
if near < 8.5 then return ppos else return false end
|
||||
return ( near < 8.5 and ppos )
|
||||
end
|
||||
|
||||
|
||||
local function usign(r)
|
||||
if r < 0 then return -1 else return 1 end
|
||||
return ( r < 0 and -1 ) or 1
|
||||
end
|
||||
|
||||
|
||||
local function quick_escape(ent,pos)
|
||||
|
||||
local function escape(ent,pos)
|
||||
local bias = {x = 1, y = 1, z = 1}
|
||||
local o = {a="x", b="y", c="z"}
|
||||
|
||||
local pref = near_player(pos)
|
||||
if pref then
|
||||
bias = {x = usign(pref.x - pos.x), y = usign(pref.y - pos.y), z = usign(pref.z - pos.z)}
|
||||
local mag={x=math.abs(pref.x - pos.x), y=math.abs(pref.y - pos.y), z=math.abs(pref.z - pos.z)}
|
||||
local mag={x = math.abs(pref.x - pos.x), y = math.abs(pref.y - pos.y), z = math.abs(pref.z - pos.z)}
|
||||
if mag.z > mag.y then
|
||||
if mag.y > mag.x then
|
||||
o={a="z",b="y",c="x"}
|
||||
|
@ -76,7 +88,7 @@ local function quick_escape(ent,pos)
|
|||
for b = pos[o.b] + bias[o.b], pos[o.b] - bias[o.b], -bias[o.b] do
|
||||
for c = pos[o.c] + bias[o.c], pos[o.c] - bias[o.c], -bias[o.c] do
|
||||
p = {[o.a]=a, [o.b]=b, [o.c]=c}
|
||||
if not in_walkable(p) then
|
||||
if not obstructed(p) then
|
||||
ent.object:setpos(p)
|
||||
return p
|
||||
end
|
||||
|
@ -90,57 +102,85 @@ end
|
|||
|
||||
-- * Entombment physics *
|
||||
|
||||
-- ---------------- LIFT
|
||||
|
||||
local function disentomb(obj, reset)
|
||||
local function lift(obj)
|
||||
local p = obj:getpos()
|
||||
if p then
|
||||
|
||||
local ent = obj:get_luaentity()
|
||||
local w = in_walkable(p)
|
||||
local brace = math.floor(p.y - 0.5) + 0.800001
|
||||
|
||||
if ent.is_entombed then
|
||||
if w then
|
||||
p = {x = p.x, y = brace + 1, z = p.z}
|
||||
obj:setpos(p)
|
||||
if ent.is_entombed and obstructed(p) then
|
||||
-- Time
|
||||
local t = 1
|
||||
local s1 = ent.sync1
|
||||
if s1 then
|
||||
local sd = ent.sync0+s1-minetest.get_us_time()
|
||||
if sd > 0 then t = sd/1000000 end
|
||||
ent.sync0, ent.sync1 = nil, nil
|
||||
end
|
||||
ent.is_entombed = in_walkable(p)
|
||||
elseif w and not (reset and quick_escape(ent,p)) then
|
||||
obj:setpos({x = p.x, y = brace, z = p.z})
|
||||
ent.is_entombed = true
|
||||
end
|
||||
|
||||
if ent.is_entombed then
|
||||
obj:setvelocity({x = 0, y = 0, z = 0})
|
||||
obj:setacceleration({x = 0, y = 0, z = 0})
|
||||
minetest.after(1.0, disentomb, obj, false)
|
||||
end
|
||||
|
||||
end
|
||||
-- Space
|
||||
p = {x = p.x, y = math.floor(p.y - 0.5) + 1.800001, z = p.z}
|
||||
obj:setpos(p)
|
||||
if s1 or obstructed(p) then
|
||||
obj:setvelocity({x = 0, y = 0, z = 0})
|
||||
obj:setacceleration({x = 0, y = 0, z = 0})
|
||||
minetest.after(t, lift, obj)
|
||||
return
|
||||
end
|
||||
end -- if w
|
||||
-- Void.
|
||||
ent.is_entombed, ent.sync0, ent.sync1 = nil, nil, nil
|
||||
end -- if p
|
||||
end
|
||||
|
||||
function droplift.invoke(obj, entomb)
|
||||
disentomb(obj, not entomb)
|
||||
-- ---------------- ASYNC
|
||||
|
||||
local counter = function()
|
||||
local k = 0
|
||||
return function()
|
||||
k = (k==9973 and 1) or k+1
|
||||
return k
|
||||
end
|
||||
end
|
||||
local newhash = counter()
|
||||
|
||||
local function async(obj, usync)
|
||||
local p = obj:getpos()
|
||||
if p then
|
||||
local ent = obj:get_luaentity()
|
||||
local hash = newhash()
|
||||
ent.hash = ent.hash or hash
|
||||
if obstructed(p) then
|
||||
-- Time.
|
||||
if not usync then
|
||||
if escape(ent, p) and hash == ent.hash then
|
||||
ent.hash = nil
|
||||
end
|
||||
elseif usync > 0 then
|
||||
ent.sync0 = minetest.get_us_time()
|
||||
ent.sync1 = usync
|
||||
end
|
||||
-- Space.
|
||||
if hash == ent.hash then
|
||||
obj:setpos({x = p.x, y = math.floor(p.y - 0.5) + 0.800001, z = p.z})
|
||||
obj:setvelocity({x = 0, y = 0, z = 0})
|
||||
obj:setacceleration({x = 0, y = 0, z = 0})
|
||||
if not ent.is_entombed then
|
||||
ent.is_entombed = true
|
||||
minetest.after(1, lift, obj)
|
||||
end
|
||||
end
|
||||
end -- if w
|
||||
if hash == ent.hash then ent.hash = nil end
|
||||
end -- if p
|
||||
end
|
||||
|
||||
droplift.invoke = function(obj, sync)
|
||||
async(obj, (sync and math.max(0,sync)*1000000))
|
||||
end
|
||||
|
||||
|
||||
-- * Events *
|
||||
|
||||
|
||||
-- Poll until defaults are ready before continuing.
|
||||
local function wait_itemstring(ent, c)
|
||||
if ent.itemstring == "" then
|
||||
if c < 10 then
|
||||
minetest.after(0.1, wait_itemstring, ent, c + 1)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
disentomb(ent.object, false)
|
||||
end
|
||||
|
||||
|
||||
local function append_to_core_defns()
|
||||
local dropentity=minetest.registered_entities["__builtin:item"]
|
||||
|
||||
|
@ -151,11 +191,10 @@ local function append_to_core_defns()
|
|||
if staticdata ~= "" then
|
||||
if minetest.deserialize(staticdata).is_entombed then
|
||||
ent.is_entombed = true
|
||||
minetest.after(0.1, wait_itemstring, ent, 1)
|
||||
else
|
||||
ent.object:setvelocity({x = 0, y = 0, z = 0})
|
||||
minetest.after(0.1, lift, ent.object)
|
||||
end
|
||||
end
|
||||
ent.object:setvelocity({x = 0, y = 0, z = 0})
|
||||
end
|
||||
|
||||
-- Preserve state across reloads
|
||||
|
@ -181,7 +220,7 @@ local function append_to_core_defns()
|
|||
for _,obj in ipairs(a) do
|
||||
local ent = obj:get_luaentity()
|
||||
if ent and ent.name == "__builtin:item" then
|
||||
disentomb(obj, true)
|
||||
async(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -189,5 +228,4 @@ local function append_to_core_defns()
|
|||
end
|
||||
|
||||
|
||||
|
||||
append_to_core_defns()
|
||||
|
|
Loading…
Reference in New Issue