From 89f02386bc31a75b826b07aec40e18348ed12193 Mon Sep 17 00:00:00 2001 From: HybridDog Date: Thu, 8 Oct 2020 20:29:39 +0200 Subject: [PATCH] Simplify the code and change behaviour a bit Example: accelerate instead of setting velocities --- README.md | 2 +- init.lua | 155 ++++++++++++++++++++++++------------------------------ 2 files changed, 69 insertions(+), 88 deletions(-) diff --git a/README.md b/README.md index 37ce195..63735b5 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ For a description of this Minetest mod, see https://forum.minetest.net/viewtopic.php?f=9&t=10271. TODO: -* Support mods liquids +* Support more fluids which push items, e.g. river water diff --git a/init.lua b/init.lua index cc376de..2b7374d 100644 --- a/init.lua +++ b/init.lua @@ -1,31 +1,20 @@ --- Use the movement gravity for the downwards direction. Get the setting rarely -local cached_gravity -local function get_gravity() - if cached_gravity then - return cached_gravity - end - cached_gravity = tonumber(core.settings:get("movement_gravity")) or 9.81 - core.after(50, function() - cached_gravity = nil - end) - return cached_gravity -end +-- Use the movement gravity for the downwards acceleration. +-- The setting may change in-game but for simplicity we don't support this. +local movement_gravity = tonumber(core.settings:get("movement_gravity")) or 9.81 +-- get_flow_target_raw determines position to which the water flows, or returns +-- nothing if no target position was found local neighbour_offsets = { {x=-1, y=0, z=0}, {x=1, y=0, z=0}, {x=0, y=0, z=-1}, {x=0, y=0, z=1} } -local neighbours_cache = {} -setmetatable(neighbours_cache, {__mode = "kv"}) -local function get_neighbour_nodes(pos) - -- Use previously found neighbours if they are not too old - local vi = minetest.hash_node_position(pos) - local t = minetest.get_us_time() - if neighbours_cache[vi] - and t - neighbours_cache[vi][1] < 10 * 1000000 then - return neighbours_cache[vi][2] +local function get_flow_target_raw(pos) + local param2 = minetest.get_node(pos).param2 + if param2 > 7 then + -- The liquid flows downwards + return end local neighbours = {} for n = 1, 4 do @@ -33,17 +22,6 @@ local function get_neighbour_nodes(pos) neighbours[n] = p neighbours[n + 4] = minetest.get_node(p) end - neighbours_cache[vi] = {t, neighbours} - return neighbours -end - --- This function determines position to which the water flows -local function get_flow_target(pos) - local neighbours = get_neighbour_nodes(pos) - local param2 = minetest.get_node(pos).param2 - if param2 > 7 then - return - end for i = 1, 4 do -- If a neighbour has a lower height, flow to it local node = neighbours[i + 4] @@ -53,7 +31,7 @@ local function get_flow_target(pos) end end for i = 1, 4 do - -- TODO + -- Flow to a downwards-flowing neighbour if its height is not too small local node = neighbours[i + 4] if node.name == "default:water_flowing" and node.param2 >= 11 then @@ -61,7 +39,7 @@ local function get_flow_target(pos) end end for i = 1, 4 do - -- TODO + -- Flow to a neighbouring unsolid node local node = neighbours[i + 4] if node.name ~= "default:water_flowing" then local def = minetest.registered_nodes[node.name] @@ -70,53 +48,64 @@ local function get_flow_target(pos) end end end + -- No neighbour found +end + +-- get_flow_target caches the results from get_flow_target_raw for 10 s +local flow_target_cache = {} +setmetatable(flow_target_cache, {__mode = "kv"}) +local function get_flow_target(pos) + local vi = minetest.hash_node_position(pos) + local t = minetest.get_us_time() + if flow_target_cache[vi] + and t - flow_target_cache[vi][1] < 10 * 1000000 then + return flow_target_cache[vi][2] + end + local flow_target = get_flow_target_raw(pos) + flow_target_cache[vi] = {t, flow_target} + return flow_target end local item_entity = minetest.registered_entities["__builtin:item"] -local old_on_step = item_entity.on_step or function()end +local old_on_step = item_entity.on_step item_entity.makes_footstep_sound = true +-- The "bt_" prefix shows that the value comes from builtin_item item_entity.bt_timer = 0 item_entity.on_step = function(self, dtime, ...) + -- Remember the velocity before an original on_step can change it + local vel_desired + if self.bt_reset_velocity then + vel_desired = self.object:get_velocity() + end + old_on_step(self, dtime, ...) - --~ if not self.physical_state then - --~ return - --~ end - - -- Force-adjust an acceleration and/or velocity if needed - if self.bt_acc - and not vector.equals(self.object:get_acceleration(), self.bt_acc) then - self.object:set_acceleration(self.bt_acc) - end - if self.bt_vel - and not vector.equals(self.object:get_velocity(), self.bt_vel) then - self.object:set_velocity(self.bt_vel) + -- Ignore the item if it should not interact with physics + if not self.physical_state then + return end - -- TODO: was ist pyhsical state? - if self.bt_phys ~= nil - and self.physical_state ~= self.bt_phys then - self.physical_state = self.bt_phys - self.object:set_properties({ - physical = self.bt_phys - }) + -- Reset the velocity if needed + if vel_desired + and not vector.equals(self.object:get_velocity(), vel_desired) then + self.object:set_velocity(vel_desired) end - -- For performance reasons, skip the remaining code except every second + -- For performance reasons, skip the remaining code in frequent steps self.bt_timer = self.bt_timer + dtime - if self.bt_timer < 1 then + if self.bt_timer < 0.1 then return end self.bt_timer = 0 local p = self.object:get_pos() local pos = vector.round(p) + local nodename = minetest.get_node(pos).name - local name = minetest.get_node(pos).name - if name == "default:lava_flowing" - or name == "default:lava_source" then - -- TODO: more generic burn cases + -- Burn the item if it is in lava + if nodename == "default:lava_flowing" + or nodename == "default:lava_source" then minetest.sound_play("builtin_item_lava", {pos=p}) minetest.add_particlespawner({ amount = 3, @@ -144,38 +133,30 @@ item_entity.on_step = function(self, dtime, ...) return end - local def = minetest.registered_nodes[name] - if not def then + if self.bt_reset_velocity then + -- Set the item acceleration to its default (changed again below) + self.object:set_acceleration({x=0, y=-movement_gravity, z=0}) + self.bt_reset_velocity = nil + end + local def = minetest.registered_nodes[nodename] + if not def or not def.liquidtype or def.liquidtype ~= "flowing" then return end - -- Adjust the acceleration in liquid nodes - self.bt_acc = nil - self.bt_vel = nil - if def.liquidtype then - -- Set the strongest acceleration when we are in the middle of the node - local acc_strength = 1.0 - ((p.y - 0.5) % 1.0) * 0.9 - local acc = {x = 0, y = -acc_strength * get_gravity(), z = 0} - self.object:set_acceleration(acc) - self.bt_acc = acc - end - if def.liquidtype ~= "flowing" then + local pos_next = get_flow_target(pos) + if not pos_next then return end - local vec = get_flow_target(pos) - if not vec then - return + local vel_current = vel_desired or self.object:get_velocity() + local acc = vector.multiply(vector.subtract(pos_next, pos), 2.0) + if math.abs(vel_current.x) > 1.0 then + acc.x = 0 end - local v = vector.add( - self.object:get_velocity(), - vector.multiply(vector.subtract(vec, pos),.5) - ) - self.bt_vel = v - self.object:set_velocity(v) - self.physical_state = true - self.bt_phys = true - self.object:set_properties({ - physical = true - }) + if math.abs(vel_current.z) > 1.0 then + acc.z = 0 + end + acc.y = -movement_gravity + self.object:set_acceleration(acc) + self.bt_reset_velocity = true end minetest.register_entity(":__builtin:item", item_entity)