From c4311136ee15e0a59b0896ff35f4bba60133e3b5 Mon Sep 17 00:00:00 2001 From: Zefram Date: Wed, 16 Jul 2014 20:14:15 +0100 Subject: [PATCH] Use velocity prediction feature The engine now permits an entity to specify two velocities, and a time at which to switch to the second velocity. Use this to prevent tubed items visually continuing past the end of a tube. Each tubed item is configured to stop imperceptibly past the next tube node, the point at which its next velocity will be properly assessed. --- item_transport.lua | 114 ++++++++++++++++++++++++++------------------- tubes.lua | 10 ++-- wielder.lua | 3 +- 3 files changed, 74 insertions(+), 53 deletions(-) diff --git a/item_transport.lua b/item_transport.lua index f01506b..d3e8bf9 100644 --- a/item_transport.lua +++ b/item_transport.lua @@ -18,6 +18,14 @@ local function facedir_to_right_dir(facedir) z=topdir.x*backdir.y - backdir.x*topdir.y} end +local function vector_copy(v) + return { x = v.x, y = v.y, z = v.z } +end + +local function rectilinear_distance(v) + return math.abs(v.x + v.y + v.z) +end + local fakePlayer = { get_player_name = function() return ":pipeworks" end, -- any other player functions called by allow_metadata_inventory_take anywhere... @@ -132,7 +140,8 @@ local function grabAndFire(data,slotseq_mode,filtmeta,frominv,frominvname,frompo end local item1 = pipeworks.tube_item(vector.add(frompos, vector.multiply(dir, 1.4)), item) item1:get_luaentity().start_pos = vector.add(frompos, dir) - item1:setvelocity(dir) + item1:get_luaentity().velocity = vector_copy(dir) + item1:setvelocity(dir, 1.001, {x=0,y=0,z=0}) item1:setacceleration({x=0, y=0, z=0}) return true-- only fire one item, please end @@ -269,7 +278,7 @@ local function go_next(pos, velocity, stack) local cmeta = minetest.get_meta(pos) local n local can_go - local speed = math.abs(velocity.x + velocity.y + velocity.z) + local speed = rectilinear_distance(velocity) local vel = {x = velocity.x/speed, y = velocity.y/speed, z = velocity.z/speed,speed=speed} if speed >= 4.1 then speed = 4 @@ -363,14 +372,22 @@ minetest.register_entity("pipeworks:tubed_item", { end, get_staticdata = function(self) - if self.start_pos == nil or self.removed then - return + if self.removed then return end + if self.start_pos == nil then + local pos = self.object:getpos() + self.start_pos = roundpos(pos) end - local velocity = self.object:getvelocity() self.object:setpos(self.start_pos) + if self.velocity == nil then + local vel = self.object:getvelocity() + if rectilinear_distance(vel) ~= 0 then + self.velocity = vector_copy(vel) + self.object:setvelocity(self.velocity, 1.001/rectilinear_distance(self.velocity), {x=0,y=0,z=0}) + end + end return minetest.serialize({ itemstring = self.itemstring, - velocity = velocity, + velocity = self.velocity or self.object:getvelocity(), start_pos = self.start_pos }) end, @@ -386,10 +403,13 @@ minetest.register_entity("pipeworks:tubed_item", { end if itemname then - self.start_pos=item.start_pos - self.object:setvelocity(item.velocity) - self.object:setacceleration({x=0, y=0, z=0}) - self.object:setpos(item.start_pos) + self.start_pos = item.start_pos + self.object:setpos(item.start_pos) + if rectilinear_distance(item.velocity) ~= 0 then + self.velocity = item.velocity + self.object:setvelocity(item.velocity, 1.001/rectilinear_distance(item.velocity), {x=0,y=0,z=0}) + end + self.object:setacceleration({x=0, y=0, z=0}) end self:set_item(item.itemstring) end, @@ -408,6 +428,11 @@ minetest.register_entity("pipeworks:tubed_item", { local pos = self.object:getpos() self.start_pos = roundpos(pos) end + if self.velocity == nil then + local vel = self.object:getvelocity() + if rectilinear_distance(vel) == 0 then return end + self.velocity = vector_copy(vel) + end local pos = self.object:getpos() local node = minetest.get_node(pos) local meta = minetest.get_meta(pos) @@ -415,42 +440,29 @@ minetest.register_entity("pipeworks:tubed_item", { local stack = ItemStack(self.itemstring) local drop_pos = nil - local velocity = self.object:getvelocity() - - if velocity == nil then return end - - local velocitycopy = {x = velocity.x, y = velocity.y, z = velocity.z} - - local moved = false - local speed = math.abs(velocity.x + velocity.y + velocity.z) - local vel = {x = velocity.x / speed, y = velocity.y / speed, z = velocity.z / speed, speed = speed} - - if math.abs(vel.x) == 1 then - local next_node = math.abs(pos.x - self.start_pos.x) - if next_node >= 1 then - self.start_pos.x = self.start_pos.x + vel.x - moved = true - end - elseif math.abs(vel.y) == 1 then - local next_node = math.abs(pos.y - self.start_pos.y) - if next_node >= 1 then - self.start_pos.y = self.start_pos.y + vel.y - moved = true - end - elseif math.abs(vel.z) == 1 then - local next_node = math.abs(pos.z - self.start_pos.z) - if next_node >= 1 then - self.start_pos.z = self.start_pos.z + vel.z - moved = true + local velocity = self.velocity + local dist_moved = rectilinear_distance(vector.subtract(pos, self.start_pos)) + if dist_moved < 1 then + if rectilinear_distance(self.object:getvelocity()) == 0 then + -- Items shouldn't ever get stuck like this. + -- But it's best to be paranoid about + -- the engine's mathematical correctness. + self.object:setvelocity(velocity, (1.001-dist_moved)/rectilinear_distance(velocity), {x=0,y=0,z=0}) end + return end - - local sposcopy = {x = self.start_pos.x, y = self.start_pos.y, z = self.start_pos.z} + + local speed = rectilinear_distance(velocity) + local dir = vector.divide(velocity, speed) + local velocitycopy = vector_copy(velocity) + self.start_pos = vector.add(self.start_pos, dir) + local sposcopy = vector_copy(self.start_pos) node = minetest.get_node(self.start_pos) - if moved and minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then + if minetest.get_item_group(node.name, "tubedevice_receiver") == 1 then local leftover = nil if minetest.registered_nodes[node.name].tube and minetest.registered_nodes[node.name].tube.insert_object then + local vel = { x = dir.x, y = dir.y, z = dir.z, speed = speed } leftover = minetest.registered_nodes[node.name].tube.insert_object(self.start_pos, node, stack, vel) else leftover = stack @@ -462,26 +474,30 @@ minetest.register_entity("pipeworks:tubed_item", { velocity.x = -velocity.x velocity.y = -velocity.y velocity.z = -velocity.z - self.object:setvelocity(velocity) + self.velocity = velocity + self.object:setpos(self.start_pos) + self.object:setvelocity(velocity, 1.001/rectilinear_distance(velocity), { x=0, y=0, z=0 }) self:set_item(leftover:to_string()) return end - if moved then - if go_next (self.start_pos, velocity, stack) == 0 then - drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air") - if drop_pos then - minetest.item_drop(stack, "", drop_pos) - self:remove() - end + if go_next (self.start_pos, velocity, stack) == 0 then + drop_pos = minetest.find_node_near(vector.add(self.start_pos, velocity), 1, "air") + if drop_pos then + minetest.item_drop(stack, "", drop_pos) + self:remove() end end if velocity.x~=velocitycopy.x or velocity.y~=velocitycopy.y or velocity.z~=velocitycopy.z or self.start_pos.x~=sposcopy.x or self.start_pos.y~=sposcopy.y or self.start_pos.z~=sposcopy.z then self.object:setpos(self.start_pos) - self.object:setvelocity(velocity) + dist_moved = 0 + self.velocity = velocity + else + dist_moved = rectilinear_distance(vector.subtract(pos, self.start_pos)) end + self.object:setvelocity(velocity, (1.001-dist_moved)/rectilinear_distance(velocity), {x=0,y=0,z=0}) end }) diff --git a/tubes.lua b/tubes.lua index 97f0237..e3d4c57 100644 --- a/tubes.lua +++ b/tubes.lua @@ -515,7 +515,8 @@ if pipeworks.enable_sand_tube then if object:get_luaentity().itemstring ~= "" then local titem = pipeworks.tube_item(pos,object:get_luaentity().itemstring) titem:get_luaentity().start_pos = {x = pos.x, y = pos.y-1, z = pos.z} - titem:setvelocity({x = 0.01, y = 1, z = -0.01}) + titem:get_luaentity().velocity = {x=0,y=1,z=0} + titem:setvelocity({x=0,y=1,z=0}, 1.001, {x=0,y=0,z=0}) titem:setacceleration({x = 0, y = 0, z = 0}) end object:get_luaentity().itemstring = "" @@ -578,7 +579,8 @@ if pipeworks.enable_mese_sand_tube then if object:get_luaentity().itemstring ~= "" then local titem = pipeworks.tube_item(pos, object:get_luaentity().itemstring) titem:get_luaentity().start_pos = {x = pos.x, y = pos.y-1, z = pos.z} - titem:setvelocity({x = 0.01, y = 1, z = -0.01}) + titem:get_luaentity().velocity = {x=0,y=1,z=0} + titem:setvelocity({x=0,y=1,z=0}, 1.001, {x=0,y=0,z=0}) titem:setacceleration({x = 0, y = 0, z = 0}) end object:get_luaentity().itemstring = "" @@ -635,7 +637,9 @@ if pipeworks.enable_one_way_tube then insert_object = function(pos, node, stack, direction) item1 = pipeworks.tube_item(pos, stack) item1:get_luaentity().start_pos = pos - item1:setvelocity({x = direction.x*direction.speed, y = direction.y*direction.speed, z = direction.z*direction.speed}) + local vel = { x = direction.x*direction.speed, y = direction.y*direction.speed, z = direction.z*direction.speed } + item1:get_luaentity().velocity = vel + item1:setvelocity(vel, 1.001, {x=0,y=0,z=0}) item1:setacceleration({x = 0, y = 0, z = 0}) return ItemStack("") end, diff --git a/wielder.lua b/wielder.lua index 6d92a23..153ed2c 100644 --- a/wielder.lua +++ b/wielder.lua @@ -103,7 +103,8 @@ local function wielder_on(data, wielder_pos, wielder_node) if not stack:is_empty() then local tubeitem = pipeworks.tube_item(vector_copy(wielder_pos), stack) tubeitem:get_luaentity().start_pos = vector_copy(wielder_pos) - tubeitem:setvelocity(vector_copy(dir)) + tubeitem:get_luaentity().velocity = vector_copy(dir) + tubeitem:setvelocity(vector_copy(dir), 1.001, vector.new(0,0,0)) tubeitem:setacceleration(vector.new(0,0,0)) inv:set_stack("main", i, ItemStack("")) end -- 2.30.2