From 53923dd5fa8afd281ec85e900a008d98d3f31975 Mon Sep 17 00:00:00 2001 From: ancientmarinerdev Date: Tue, 28 Mar 2023 18:06:25 +0100 Subject: [PATCH] Move on_step code to functions to help see profiling impact --- mods/ENTITIES/mcl_item_entity/init.lua | 331 +++++++++++++------------ 1 file changed, 171 insertions(+), 160 deletions(-) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 8ee718f59..0ebee0d05 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -403,7 +403,174 @@ local function cxcz(o, cw, one, zero) return o end +local function nodes_destroy_items (self, moveresult, def, nn) + local lg = minetest.get_item_group(nn, "lava") + local fg = minetest.get_item_group(nn, "fire") + local dg = minetest.get_item_group(nn, "destroys_items") + if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then + --Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed. + if self.age > 2 and minetest.get_item_group(self.itemstring, "fire_immune") == 0 then + if dg ~= 2 then + minetest.sound_play("builtin_item_lava", { pos = self.object:get_pos(), gain = 0.5 }) + end + self._removed = true + self.object:remove() + return true + end + end + + -- Destroy item when it collides with a cactus + if moveresult and moveresult.collides then + for _, collision in pairs(moveresult.collisions) do + local pos = collision.node_pos + if collision.type == "node" and minetest.get_node(pos).name == "mcl_core:cactus" then + -- TODO We need to play a sound when it gets destroyed + self._removed = true + self.object:remove() + return true + end + end + end +end + +local function push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water) + if not is_in_water and def and def.walkable and def.groups and def.groups.opaque == 1 then + local shootdir + local cx = (p.x % 1) - 0.5 + local cz = (p.z % 1) - 0.5 + local order = {} + + -- First prepare the order in which the 4 sides are to be checked. + -- 1st: closest + -- 2nd: other direction + -- 3rd and 4th: other axis + if math.abs(cx) < math.abs(cz) then + order = cxcz(order, cx, "x", "z") + order = cxcz(order, cz, "z", "x") + else + order = cxcz(order, cz, "z", "x") + order = cxcz(order, cx, "x", "z") + end + + -- Check which one of the 4 sides is free + for o = 1, #order do + local nn = minetest.get_node(vector.add(p, order[o])).name + local def = minetest.registered_nodes[nn] + if def and def.walkable == false and nn ~= "ignore" then + shootdir = order[o] + break + end + end + -- If none of the 4 sides is free, shoot upwards + if shootdir == nil then + shootdir = vector.new(0, 1, 0) + local nn = minetest.get_node(vector.add(p, shootdir)).name + if nn == "ignore" then + -- Do not push into ignore + return true + end + end + + -- Set new item moving speed accordingly + local newv = vector.multiply(shootdir, 3) + self.object:set_acceleration(vector.zero()) + self.object:set_velocity(newv) + disable_physics(self.object, self, false, false) + + + if shootdir.y == 0 then + self._force = newv + p.x = math.floor(p.x) + p.y = math.floor(p.y) + p.z = math.floor(p.z) + self._forcestart = p + self._forcetimer = 1 + end + return true + end + + -- This code is run after the entity got a push from above “push away” code. + -- It is responsible for making sure the entity is entirely outside the solid node + -- (with its full collision box), not just its center. + if self._forcetimer > 0 then + local cbox = self.object:get_properties().collisionbox + local ok = false + if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1]) / 2)) then ok = true + elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1]) / 2)) then ok = true + elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3]) / 2)) then ok = true + elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3]) / 2)) then ok = true end + -- Item was successfully forced out. No more pushing + if ok then + self._forcetimer = -1 + self._force = nil + enable_physics(self.object, self) + else + self._forcetimer = self._forcetimer - dtime + end + return true + elseif self._force then + self._force = nil + enable_physics(self.object, self) + return true + end +end + +local function move_items_in_water (self, p, def, node, is_floating, is_in_water) + -- Move item around on flowing liquids; add 'source' check to allow items to continue flowing a bit in the source block of flowing water. + if def and not is_floating and (def.liquidtype == "flowing" or def.liquidtype == "source") then + self._flowing = true + + --[[ Get flowing direction (function call from flowlib), if there's a liquid. + NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7. + Luckily, this is exactly what we need if we only care about water, which has this flowing distance. ]] + local vec = flowlib.quick_flow(p, node) + -- Just to make sure we don't manipulate the speed for no reason + if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then + -- Minecraft Wiki: Flowing speed is "about 1.39 meters per second" + local f = 1.2 + -- Set new item moving speed into the direciton of the liquid + local newv = vector.multiply(vec, f) + -- Swap to acceleration instead of a static speed to better mimic MC mechanics. + self.object:set_acceleration(vector.new(newv.x, -0.22, newv.z)) + + self.physical_state = true + self._flowing = true + self.object:set_properties({ + physical = true + }) + return true + end + if is_in_water and def.liquidtype == "source" then + local cur_vec = self.object:get_velocity() + -- apply some acceleration in the opposite direction so it doesn't slide forever + local vec = { + x = 0 - cur_vec.x * 0.9, + y = 3 - cur_vec.y * 0.9, + z = 0 - cur_vec.z * 0.9 + } + self.object:set_acceleration(vec) + -- slow down the item in water + local vel = self.object:get_velocity() + if vel.y < 0 then + vel.y = vel.y * 0.9 + end + self.object:set_velocity(vel) + if self.physical_state ~= false or self._flowing ~= true then + self.physical_state = true + self._flowing = true + self.object:set_properties({ + physical = true + }) + end + end + elseif self._flowing == true and not is_in_water and not is_floating then + -- Disable flowing physics if not on/in flowing liquid + self._flowing = false + enable_physics(self.object, self, true) + return true + end +end minetest.register_entity(":__builtin:item", { initial_properties = { @@ -672,8 +839,7 @@ minetest.register_entity(":__builtin:item", { -- otherwise there might have some data corruption. if self.itemstring == "" then minetest.log("warning", - "Item entity with empty itemstring found at " .. minetest.pos_to_string(self.object:get_pos()) .. - "! Deleting it now.") + "Item entity with empty itemstring found and being deleted at: " .. minetest.pos_to_string(self.object:get_pos())) self._removed = true self.object:remove() return @@ -724,167 +890,12 @@ minetest.register_entity(":__builtin:item", { -- Destroy item in lava, fire or special nodes local def = minetest.registered_nodes[nn] - local lg = minetest.get_item_group(nn, "lava") - local fg = minetest.get_item_group(nn, "fire") - local dg = minetest.get_item_group(nn, "destroys_items") - if (def and (lg ~= 0 or fg ~= 0 or dg == 1)) then - --Wait 2 seconds to allow mob drops to be cooked, & picked up instead of instantly destroyed. - if self.age > 2 and minetest.get_item_group(self.itemstring, "fire_immune") == 0 then - if dg ~= 2 then - minetest.sound_play("builtin_item_lava", { pos = self.object:get_pos(), gain = 0.5 }) - end - self._removed = true - self.object:remove() - return - end - end - -- Destroy item when it collides with a cactus - if moveresult and moveresult.collides then - for _, collision in pairs(moveresult.collisions) do - local pos = collision.node_pos - if collision.type == "node" and minetest.get_node(pos).name == "mcl_core:cactus" then - self._removed = true - self.object:remove() - return - end - end - end + if nodes_destroy_items(self, moveresult, def, nn) then return end - -- Push item out when stuck inside solid opaque node - if not is_in_water and def and def.walkable and def.groups and def.groups.opaque == 1 then - local shootdir - local cx = (p.x % 1) - 0.5 - local cz = (p.z % 1) - 0.5 - local order = {} + if push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water) then return end - -- First prepare the order in which the 4 sides are to be checked. - -- 1st: closest - -- 2nd: other direction - -- 3rd and 4th: other axis - if math.abs(cx) < math.abs(cz) then - order = cxcz(order, cx, "x", "z") - order = cxcz(order, cz, "z", "x") - else - order = cxcz(order, cz, "z", "x") - order = cxcz(order, cx, "x", "z") - end - - -- Check which one of the 4 sides is free - for o = 1, #order do - local nn = minetest.get_node(vector.add(p, order[o])).name - local def = minetest.registered_nodes[nn] - if def and def.walkable == false and nn ~= "ignore" then - shootdir = order[o] - break - end - end - -- If none of the 4 sides is free, shoot upwards - if shootdir == nil then - shootdir = vector.new(0, 1, 0) - local nn = minetest.get_node(vector.add(p, shootdir)).name - if nn == "ignore" then - -- Do not push into ignore - return - end - end - - -- Set new item moving speed accordingly - local newv = vector.multiply(shootdir, 3) - self.object:set_acceleration(vector.zero()) - self.object:set_velocity(newv) - disable_physics(self.object, self, false, false) - - - if shootdir.y == 0 then - self._force = newv - p.x = math.floor(p.x) - p.y = math.floor(p.y) - p.z = math.floor(p.z) - self._forcestart = p - self._forcetimer = 1 - end - return - end - - -- This code is run after the entity got a push from above “push away” code. - -- It is responsible for making sure the entity is entirely outside the solid node - -- (with its full collision box), not just its center. - if self._forcetimer > 0 then - local cbox = self.object:get_properties().collisionbox - local ok = false - if self._force.x > 0 and (p.x > (self._forcestart.x + 0.5 + (cbox[4] - cbox[1]) / 2)) then ok = true - elseif self._force.x < 0 and (p.x < (self._forcestart.x + 0.5 - (cbox[4] - cbox[1]) / 2)) then ok = true - elseif self._force.z > 0 and (p.z > (self._forcestart.z + 0.5 + (cbox[6] - cbox[3]) / 2)) then ok = true - elseif self._force.z < 0 and (p.z < (self._forcestart.z + 0.5 - (cbox[6] - cbox[3]) / 2)) then ok = true end - -- Item was successfully forced out. No more pushing - if ok then - self._forcetimer = -1 - self._force = nil - enable_physics(self.object, self) - else - self._forcetimer = self._forcetimer - dtime - end - return - elseif self._force then - self._force = nil - enable_physics(self.object, self) - return - end - - -- Move item around on flowing liquids; add 'source' check to allow items to continue flowing a bit in the source block of flowing water. - if def and not is_floating and (def.liquidtype == "flowing" or def.liquidtype == "source") then - self._flowing = true - - --[[ Get flowing direction (function call from flowlib), if there's a liquid. - NOTE: According to Qwertymine, flowlib.quickflow is only reliable for liquids with a flowing distance of 7. - Luckily, this is exactly what we need if we only care about water, which has this flowing distance. ]] - local vec = flowlib.quick_flow(p, node) - -- Just to make sure we don't manipulate the speed for no reason - if vec.x ~= 0 or vec.y ~= 0 or vec.z ~= 0 then - -- Minecraft Wiki: Flowing speed is "about 1.39 meters per second" - local f = 1.2 - -- Set new item moving speed into the direciton of the liquid - local newv = vector.multiply(vec, f) - -- Swap to acceleration instead of a static speed to better mimic MC mechanics. - self.object:set_acceleration(vector.new(newv.x, -0.22, newv.z)) - - self.physical_state = true - self._flowing = true - self.object:set_properties({ - physical = true - }) - return - end - if is_in_water and def.liquidtype == "source" then - local cur_vec = self.object:get_velocity() - -- apply some acceleration in the opposite direction so it doesn't slide forever - local vec = { - x = 0 - cur_vec.x * 0.9, - y = 3 - cur_vec.y * 0.9, - z = 0 - cur_vec.z * 0.9 - } - self.object:set_acceleration(vec) - -- slow down the item in water - local vel = self.object:get_velocity() - if vel.y < 0 then - vel.y = vel.y * 0.9 - end - self.object:set_velocity(vel) - if self.physical_state ~= false or self._flowing ~= true then - self.physical_state = true - self._flowing = true - self.object:set_properties({ - physical = true - }) - end - end - elseif self._flowing == true and not is_in_water and not is_floating then - -- Disable flowing physics if not on/in flowing liquid - self._flowing = false - enable_physics(self.object, self, true) - return - end + if move_items_in_water (self, p, def, node, is_floating, is_in_water) then return end -- If node is not registered or node is walkably solid and resting on nodebox local nn = minetest.get_node(vector.offset(p, 0, -0.5, 0)).name