forked from minetest/minetest_game
ecea5364f1
Better pathfinder algorithm, allows tuning the lag spike compensation. Smoother movement (when it's laggy). Set the player animation to stand on attach. Remove driver when they leave. Only update velocity when it's necessary.
249 lines
5.3 KiB
Lua
249 lines
5.3 KiB
Lua
function carts:get_sign(z)
|
|
if z == 0 then
|
|
return 0
|
|
else
|
|
return z / math.abs(z)
|
|
end
|
|
end
|
|
|
|
function carts:manage_attachment(player, obj)
|
|
if not player then
|
|
return
|
|
end
|
|
local status = obj ~= nil
|
|
local player_name = player:get_player_name()
|
|
if player_api.player_attached[player_name] == status then
|
|
return
|
|
end
|
|
player_api.player_attached[player_name] = status
|
|
|
|
if status then
|
|
player:set_attach(obj, "", {x=0, y=-4.5, z=0}, {x=0, y=0, z=0})
|
|
player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
|
|
else
|
|
player:set_detach()
|
|
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
|
|
end
|
|
end
|
|
|
|
function carts:velocity_to_dir(v)
|
|
if math.abs(v.x) > math.abs(v.z) then
|
|
return {x=carts:get_sign(v.x), y=carts:get_sign(v.y), z=0}
|
|
else
|
|
return {x=0, y=carts:get_sign(v.y), z=carts:get_sign(v.z)}
|
|
end
|
|
end
|
|
|
|
function carts:is_rail(pos, railtype)
|
|
local node = minetest.get_node(pos).name
|
|
if node == "ignore" then
|
|
local vm = minetest.get_voxel_manip()
|
|
local emin, emax = vm:read_from_map(pos, pos)
|
|
local area = VoxelArea:new{
|
|
MinEdge = emin,
|
|
MaxEdge = emax,
|
|
}
|
|
local data = vm:get_data()
|
|
local vi = area:indexp(pos)
|
|
node = minetest.get_name_from_content_id(data[vi])
|
|
end
|
|
if minetest.get_item_group(node, "rail") == 0 then
|
|
return false
|
|
end
|
|
if not railtype then
|
|
return true
|
|
end
|
|
return minetest.get_item_group(node, "connect_to_raillike") == railtype
|
|
end
|
|
|
|
function carts:check_front_up_down(pos, dir_, check_up, railtype)
|
|
local dir = vector.new(dir_)
|
|
local cur
|
|
|
|
-- Front
|
|
dir.y = 0
|
|
cur = vector.add(pos, dir)
|
|
if carts:is_rail(cur, railtype) then
|
|
return dir
|
|
end
|
|
-- Up
|
|
if check_up then
|
|
dir.y = 1
|
|
cur = vector.add(pos, dir)
|
|
if carts:is_rail(cur, railtype) then
|
|
return dir
|
|
end
|
|
end
|
|
-- Down
|
|
dir.y = -1
|
|
cur = vector.add(pos, dir)
|
|
if carts:is_rail(cur, railtype) then
|
|
return dir
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
|
|
local pos = vector.round(pos_)
|
|
local cur
|
|
local left_check, right_check = true, true
|
|
|
|
-- Check left and right
|
|
local left = {x=0, y=0, z=0}
|
|
local right = {x=0, y=0, z=0}
|
|
if dir.z ~= 0 and dir.x == 0 then
|
|
left.x = -dir.z
|
|
right.x = dir.z
|
|
elseif dir.x ~= 0 and dir.z == 0 then
|
|
left.z = dir.x
|
|
right.z = -dir.x
|
|
end
|
|
|
|
local straight_priority = ctrl and dir.y ~= 0
|
|
|
|
-- Normal, to disallow rail switching up- & downhill
|
|
if straight_priority then
|
|
cur = self:check_front_up_down(pos, dir, true, railtype)
|
|
if cur then
|
|
return cur
|
|
end
|
|
end
|
|
|
|
if ctrl then
|
|
if old_switch == 1 then
|
|
left_check = false
|
|
elseif old_switch == 2 then
|
|
right_check = false
|
|
end
|
|
if ctrl.left and left_check then
|
|
cur = self:check_front_up_down(pos, left, false, railtype)
|
|
if cur then
|
|
return cur, 1
|
|
end
|
|
left_check = false
|
|
end
|
|
if ctrl.right and right_check then
|
|
cur = self:check_front_up_down(pos, right, false, railtype)
|
|
if cur then
|
|
return cur, 2
|
|
end
|
|
right_check = true
|
|
end
|
|
end
|
|
|
|
-- Normal
|
|
if not straight_priority then
|
|
cur = self:check_front_up_down(pos, dir, true, railtype)
|
|
if cur then
|
|
return cur
|
|
end
|
|
end
|
|
|
|
-- Left, if not already checked
|
|
if left_check then
|
|
cur = carts:check_front_up_down(pos, left, false, railtype)
|
|
if cur then
|
|
return cur
|
|
end
|
|
end
|
|
|
|
-- Right, if not already checked
|
|
if right_check then
|
|
cur = carts:check_front_up_down(pos, right, false, railtype)
|
|
if cur then
|
|
return cur
|
|
end
|
|
end
|
|
|
|
-- Backwards
|
|
if not old_switch then
|
|
cur = carts:check_front_up_down(pos, {
|
|
x = -dir.x,
|
|
y = dir.y,
|
|
z = -dir.z
|
|
}, true, railtype)
|
|
if cur then
|
|
return cur
|
|
end
|
|
end
|
|
|
|
return {x=0, y=0, z=0}
|
|
end
|
|
|
|
function carts:pathfinder(pos_, old_pos, old_dir, distance, ctrl,
|
|
pf_switch, railtype)
|
|
|
|
local pos = vector.round(pos_)
|
|
if vector.equals(old_pos, pos) then
|
|
return
|
|
end
|
|
|
|
local pf_pos = vector.round(old_pos)
|
|
local pf_dir = vector.new(old_dir)
|
|
distance = math.min(carts.path_distance_max,
|
|
math.floor(distance + 1))
|
|
|
|
for i = 1, distance do
|
|
pf_dir, pf_switch = self:get_rail_direction(
|
|
pf_pos, pf_dir, ctrl, pf_switch or 0, railtype)
|
|
|
|
if vector.equals(pf_dir, {x=0, y=0, z=0}) then
|
|
-- No way forwards
|
|
return pf_pos, pf_dir
|
|
end
|
|
|
|
pf_pos = vector.add(pf_pos, pf_dir)
|
|
|
|
if vector.equals(pf_pos, pos) then
|
|
-- Success! Cart moved on correctly
|
|
return
|
|
end
|
|
end
|
|
-- Not found. Put cart to predicted position
|
|
return pf_pos, pf_dir
|
|
end
|
|
|
|
function carts:register_rail(name, def_overwrite, railparams)
|
|
local def = {
|
|
drawtype = "raillike",
|
|
paramtype = "light",
|
|
sunlight_propagates = true,
|
|
is_ground_content = false,
|
|
walkable = false,
|
|
selection_box = {
|
|
type = "fixed",
|
|
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
|
|
},
|
|
sounds = default.node_sound_metal_defaults()
|
|
}
|
|
for k, v in pairs(def_overwrite) do
|
|
def[k] = v
|
|
end
|
|
if not def.inventory_image then
|
|
def.wield_image = def.tiles[1]
|
|
def.inventory_image = def.tiles[1]
|
|
end
|
|
|
|
if railparams then
|
|
carts.railparams[name] = table.copy(railparams)
|
|
end
|
|
|
|
minetest.register_node(name, def)
|
|
end
|
|
|
|
function carts:get_rail_groups(additional_groups)
|
|
-- Get the default rail groups and add more when a table is given
|
|
local groups = {
|
|
dig_immediate = 2,
|
|
attached_node = 1,
|
|
rail = 1,
|
|
connect_to_raillike = minetest.raillike_group("rail")
|
|
}
|
|
if type(additional_groups) == "table" then
|
|
for k, v in pairs(additional_groups) do
|
|
groups[k] = v
|
|
end
|
|
end
|
|
return groups
|
|
end
|