Compare commits

...

7 Commits

10 changed files with 179 additions and 135 deletions

View File

@ -92,7 +92,6 @@ local function enable_physics(object, luaentity, ignore_check)
object:set_properties({
physical = true
})
object:set_acceleration(vector.new(0, -get_gravity(), 0))
end
end
@ -634,62 +633,6 @@ local function push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water)
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 = {
hp_max = 1,
@ -896,7 +839,6 @@ minetest.register_entity(":__builtin:item", {
self.object:set_armor_groups({ immortal = 1 })
-- self.object:set_velocity(vector.new(0, 2, 0))
self.object:set_acceleration(vector.new(0, -get_gravity(), 0))
self:set_item(self.itemstring)
end,
@ -1029,7 +971,7 @@ minetest.register_entity(":__builtin:item", {
if push_out_item_stuck_in_solid(self, dtime, p, def, is_in_water) then return end
if move_items_in_water (self, p, def, node, is_floating, is_in_water) then return end
vl_physics.apply_entity_environmental_physics(self)
-- 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

View File

@ -1,4 +1,4 @@
name = mcl_item_entity
author = PilzAdam
description = Dropped items will be attracted to the player like a magnet.
depends = flowlib, mcl_enchanting
depends = vl_physics, mcl_enchanting

View File

@ -395,7 +395,8 @@ local function on_step_work (self, dtime)
local player_in_active_range = self:player_in_active_range()
self:check_suspend(player_in_active_range)
self:check_water_flow()
-- Handle environmental physics
vl_physics.apply_entity_environmental_physics(self)
if not self._jumping_cliff then
self._can_jump_cliff = self:can_jump_cliff()

View File

@ -2,4 +2,4 @@ name = mcl_mobs
author = PilzAdam
description = Adds a mob API for mods to add animals or monsters, etc.
depends = mcl_particles
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience, mcl_sculk
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience, mcl_sculk, vl_physics

View File

@ -1026,43 +1026,7 @@ function mob_class:falling(pos)
end
function mob_class:check_water_flow()
-- Add water flowing for mobs from mcl_item_entity
local p, node, nn, def
p = self.object:get_pos()
node = minetest.get_node_or_nil(p)
if node then
nn = node.name
def = minetest.registered_nodes[nn]
end
-- Move item around on flowing liquids
if def and def.liquidtype == "flowing" then
--[[ 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.39
-- Set new item moving speed into the direciton of the liquid
local newv = vector.multiply(vec, f)
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x = newv.x, y = -0.22, z = newv.z})
self.physical_state = true
self._flowing = true
self.object:set_properties({
physical = true
})
return
end
elseif self._flowing == true then
-- Disable flowing physics if not on/in flowing liquid
self._flowing = false
return
end
-- Deprecated. Do nothing
end
function mob_class:check_dying()

View File

@ -0,0 +1,62 @@
local mod = vl_physics
local registered_environment_effects = {}
function mod.register_environment_effect(effect)
local list = registered_environment_effects
list[#list + 1] = effect
end
function mod.get_environment_effect(pos, vel, staticdata, mass, entity)
local v = vector.zero()
local a = vector.zero()
-- Accumulate all enviornmental effects
for _,effect in ipairs(registered_environment_effects) do
local dv,da = effect(pos, vel, staticdata, entity)
if dv then
v = v + dv
end
if da then
a = a + da
end
end
-- Disable small effects
if vector.length(v) < 0.01 then v = nil end
if vector.length(a) < 0.01 then a = nil end
return v,a
end
local DEFAULT_ENTITY_PHYSICS = {
mass = 1,
}
function mod.apply_entity_environmental_physics(self, data)
data = data or {}
local physics = self._vl_physics or DEFAULT_ENTITY_PHYSICS
local mass = physics.mass or DEFAULT_ENTITY_PHYSICS.mass
local pos = self.object:get_pos()
local vel = self.object:get_velocity()
local new_velocity,new_acceleration = vl_physics.get_environment_effect(pos, vel, data, mass, self)
--if new_velocity then print("new_velocity="..tostring(new_velocity)) end
--if new_acceleration then print("new_acceleration="..tostring(new_acceleration)) end
-- Update entity states
self._flowing = data.flowing
-- Apply environmental effects if there are any
if new_velocity or new_acceleration then
if new_acceleration then self.object:set_acceleration(new_acceleration) end
if new_velocity then self.object:set_velocity(new_velocity) end
self.physical_state = true
self._flowing = true
self.object:set_properties({
physical = true
})
end
end

View File

@ -0,0 +1,100 @@
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local mod = {}
vl_physics = mod
dofile(modpath.."/api.lua")
-- Flowing water
-- TODO: move to Flowlib
local FLOW_SPEED = 1.39
local BOUANCY = 3
mod.register_environment_effect(function(pos, vel, staticdata, entity)
-- Get the node and node definition
local node = minetest.get_node_or_nil(pos); if not node then return end
local nodedef = minetest.registered_nodes[node.name]; if not nodedef then return end
-- Make sure we are in a liquid before continuing
local is_flowing = (nodedef.liquidtype == "flowing")
staticdata.flowing = is_flowing
if not is_flowing then return end
-- Get liquid flow direction
local vec = vector.multiply(flowlib.quick_flow(pos, node), FLOW_SPEED)
return vector.new(vec.x, -0.22, vec.z),nil -- TODO: move bouancy velocity out of here
end)
-- Simple gravity and bouancy
mod.register_environment_effect(function(pos, vel, staticdata, entity)
-- Get the node and node definition
local node = minetest.get_node_or_nil(pos);
local nodedef = nil
if node then nodedef = minetest.registered_nodes[node.name] end
if nodedef and nodedef.liquidtype == "source" then -- TODO: make this apply to flowing liquids as well
-- TODO: make this not apply to fish
--print("entity="..dump(entity))
-- Apply decceleration and bouancy if the entity moved from flowing water to
-- stationary water
return nil,vector.new(
0 - vel.x * 0.9,
BOUANCY - vel.y * 0.9,
0 - vel.z * 0.9
)
else
local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
return nil,vector.new(0,-gravity,0)
end
end)
-- Node effects
local DEFAULT_NODE_PHYSICS = {
friction = 0.9
}
local function apply_node_physics(node, vel, staticdata, entity)
local node_def = minetest.registered_nodes[node.name] or {}
local node_physics = node_def._vl_physics or DEFAULT_NODE_PHYSICS
local node_physics_effect = node_physics.effect
if node_physics_effect then
return node_physics_effect(pos, vel, staticdata)
end
-- Default behavior
local accel = vector.zero()
-- Friction
if node.name ~= "air" then
local friction_scale = node_physics.friction
accel = accel + vel * -friction_scale
end
return vector.zero(), accel
end
mod.register_environment_effect(function(pos, vel, staticdata, entity)
local a = vector.zero()
local v = vector.zero()
-- Apply node physics for the node we are inside of
local pos1_r = vector.round(pos)
local node1 = minetest.get_node(pos1_r)
local v1,a1 = apply_node_physics(node1, vel, staticdata, entity)
v = v + v1
a = a + a1
-- TODO: only apply when touching under_node
local pos2_r = vector.offset(pos1_r,0,-1,0)
local node2 = minetest.get_node(pos2_r)
local v2,a2 = apply_node_physics(node2, vel, staticdata, entity)
v = v + v2
a = a + a2
-- Male speeds of less than 1/100 block/second count as zero
if vector.length(v) < 0.01 then
v = nil
end
return v,a
end)

View File

@ -0,0 +1,4 @@
name = vl_physics
author = teknomunk
description = Environmental physics
depends = flowlib

View File

@ -109,42 +109,7 @@ local function xp_step(self, dtime)
end
-- Slide on slippery nodes
vel = self.object:get_velocity()
def = node and minetest.registered_nodes[node.name]
is_moving = (def and not def.walkable) or
vel.x ~= 0 or vel.y ~= 0 or vel.z ~= 0
is_slippery = false
if def and def.walkable then
slippery = minetest.get_item_group(node.name, "slippery")
is_slippery = slippery ~= 0
if is_slippery and (math.abs(vel.x) > 0.2 or math.abs(vel.z) > 0.2) then
-- Horizontal deceleration
slip_factor = 4.0 / (slippery + 4)
self.object:set_acceleration({
x = -vel.x * slip_factor,
y = 0,
z = -vel.z * slip_factor
})
elseif vel.y == 0 then
is_moving = false
end
end
if self.moving_state == is_moving and self.slippery_state == is_slippery then
-- Do not update anything until the moving state changes
return
end
self.moving_state = is_moving
self.slippery_state = is_slippery
if is_moving then
self.object:set_acceleration(gravity)
else
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.object:set_velocity({x = 0, y = 0, z = 0})
end
vl_physics.apply_entity_environmental_physics(self)
end
minetest.register_entity("mcl_experience:orb", {

View File

@ -907,6 +907,9 @@ minetest.register_node("mcl_core:ice", {
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_silk_touch_drop = true,
_vl_physics = {
friction = 0.4,
},
})
minetest.register_node("mcl_core:packed_ice", {
@ -921,6 +924,9 @@ minetest.register_node("mcl_core:packed_ice", {
_mcl_blast_resistance = 0.5,
_mcl_hardness = 0.5,
_mcl_silk_touch_drop = true,
_vl_physics = {
friction = 0.15,
},
})
-- Frosted Ice (4 nodes)