Aaron Suen f140618e45 Partial ent settling on mapgen lower bound
Trying to make it so that the map lower bound
(via mapgen_limit) is solid to all built-in objects.
Before, entities would fall into this space, remain
until unloaded, and then be destroyed.

Falling nodes appear to work correctly.
Item ents still don't settle.
2020-03-22 10:42:01 -04:00

148 lines
4.3 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ItemStack, math, minetest, nodecore, pairs, tonumber, type,
vector
= ItemStack, math, minetest, nodecore, pairs, tonumber, type,
vector
local math_floor, math_pi, math_random, math_sqrt
= math.floor, math.pi, math.random, math.sqrt
-- LUALOCALS > ---------------------------------------------------------
function minetest.spawn_falling_node(pos, node, meta)
node = node or minetest.get_node(pos)
if node.name == "air" or node.name == "ignore" then
return false
end
local obj = minetest.add_entity(pos, "__builtin:falling_node")
if obj then
obj:get_luaentity():set_node(node, meta or minetest.get_meta(pos):to_table())
minetest.remove_node(pos)
return obj
end
return false
end
function nodecore.stackentprops(stack, yaw, rotate, ss)
local props = {
hp_max = 1,
physical = false,
collide_with_objects = false,
collisionbox = {0, 0, 0, 0, 0, 0},
visual = "wielditem",
visual_size = {x = 0.4, y = 0.4},
textures = {""},
spritediv = {x = 1, y = 1},
initial_sprite_basepos = {x = 0, y = 0},
is_visible = false,
static_save = ss and true or false
}
local scale = 0
yaw = yaw or 0
if stack then
if type(stack) == "string" then stack = ItemStack(stack) end
props.is_visible = not stack:is_empty()
props.textures[1] = stack:get_name()
local ratio = stack:get_count() / stack:get_stack_max()
if ratio > 1 then ratio = 1 end
scale = math_sqrt(ratio) * 0.15 + 0.25
props.visual_size = {x = scale, y = scale}
props.automatic_rotate = rotate
and rotate * 2 / math_sqrt(math_sqrt(ratio)) or nil
if ratio == 1 then ratio = 1 - (stack:get_wear() / 65536) end
if ratio ~= 1 then yaw = yaw + 1/8 + 3/8 * (1 - ratio) end
yaw = yaw - 2 * math_floor(yaw / 2)
end
return props, scale, yaw * math_pi / 2
end
function nodecore.entity_staticdata_helpers(savedprops)
return function(self, data)
data = data and minetest.deserialize(data) or {}
for k in pairs(savedprops) do self[k] = data[k] end
end,
function(self)
local data = {}
for k in pairs(savedprops) do data[k] = self[k] end
return minetest.serialize(data)
end
end
local area_unloaded = {}
local maplimit = tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000
local chunksize = tonumber(minetest.get_mapgen_setting("chunksize")) or 5
chunksize = chunksize * 16
maplimit = (-math_floor(maplimit / chunksize) + 0.5) * chunksize + 7.5
local function collides(pos)
if pos.y < maplimit then return {name = "ignore"} end
local node = minetest.get_node_or_nil(pos)
if not node then return area_unloaded end
local def = minetest.registered_nodes[node.name]
if not def then return node end
if def.walkable then return node end
end
local oldcheck = minetest.check_single_for_falling
function minetest.check_single_for_falling(...)
local oldget = minetest.get_node_or_nil
function minetest.get_node_or_nil(pos, ...)
if pos.y < maplimit then return end
return oldget(pos, ...)
end
local function helper(...)
minetest.get_node_or_nil = oldget
return ...
end
return helper(oldcheck(...))
end
function nodecore.entity_settle_check(on_settle, isnode)
return function(self)
local pos = self.object:get_pos()
if self.settle_oldpos and vector.distance(self.settle_oldpos, pos) < 1/16 then
local csize = self.collidesize or 0.5
pos.x = pos.x + (math_random() * 2 - 1) * csize
pos.z = pos.z + (math_random() * 2 - 1) * csize
else
self.settle_oldpos = pos
end
local yvel = self.object:get_velocity().y
local coll = (isnode or self.not_rising and yvel == 0)
and collides({x = pos.x, y = pos.y - 0.75, z = pos.z})
self.not_rising = yvel <= 0
if not coll then
if self.setvel then
self.object:set_velocity(self.vel)
self.setvel = nil
end
self.vel = self.object:get_velocity()
return nodecore.grav_air_accel_ent(self.object)
end
if coll == area_unloaded then
self.object:set_velocity({x = 0, y = 0, z = 0})
self.object:set_acceleration({x = 0, y = 0, z = 0})
self.setvel = true
return
end
pos = vector.round(pos)
if not on_settle(self, pos, collides) then return end
pos.y = pos.y + 1
for _, obj in pairs(nodecore.get_objects_at_pos(pos)) do
obj = obj.get_luaentity and obj:get_luaentity()
if obj and obj.settle_check then
obj:settle_check()
end
end
return nodecore.fallcheck(pos)
end
end