Skip to content

Commit

Permalink
Update carts from boost_cart
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
SmallJoker authored and paramat committed Jul 7, 2018
1 parent 59dbeeb commit ecea536
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 30 deletions.
54 changes: 40 additions & 14 deletions mods/carts/cart_entity.lua
Expand Up @@ -27,6 +27,10 @@ function cart_entity:on_rightclick(clicker)
elseif not self.driver then
self.driver = player_name
carts:manage_attachment(clicker, self.object)

-- player_api does not update the animation
-- when the player is attached, reset to default animation
player_api.set_animation(clicker, "stand")
end
end

Expand All @@ -36,7 +40,7 @@ function cart_entity:on_activate(staticdata, dtime_s)
return
end
local data = minetest.deserialize(staticdata)
if not data or type(data) ~= "table" then
if type(data) ~= "table" then
return
end
self.railtype = data.railtype
Expand All @@ -52,6 +56,13 @@ function cart_entity:get_staticdata()
})
end

-- 0.5.x and later: When the driver leaves
function cart_entity:on_detach_child(child)
if child and child:get_player_name() == self.driver then
self.driver = nil
end
end

function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
local pos = self.object:get_pos()
local vel = self.object:get_velocity()
Expand Down Expand Up @@ -82,7 +93,7 @@ function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities,
local player = minetest.get_player_by_name(self.driver)
carts:manage_attachment(player, nil)
end
for _,obj_ in ipairs(self.attached_items) do
for _, obj_ in ipairs(self.attached_items) do
if obj_ then
obj_:set_detach()
end
Expand Down Expand Up @@ -165,6 +176,7 @@ local function get_railparams(pos)
return carts.railparams[node.name] or {}
end

local v3_len = vector.length
local function rail_on_step(self, dtime)
local vel = self.object:get_velocity()
if self.punched then
Expand Down Expand Up @@ -201,17 +213,23 @@ local function rail_on_step(self, dtime)

local stop_wiggle = false
if self.old_pos and same_dir then
-- Detection for "skipping" nodes
local found_path = carts:pathfinder(
pos, self.old_pos, self.old_dir, ctrl, self.old_switch, self.railtype
-- Detection for "skipping" nodes (perhaps use average dtime?)
-- It's sophisticated enough to take the acceleration in account
local acc = self.object:get_acceleration()
local distance = dtime * (v3_len(vel) + 0.5 * dtime * v3_len(acc))

local new_pos, new_dir = carts:pathfinder(
pos, self.old_pos, self.old_dir, distance, ctrl,
self.old_switch, self.railtype
)

if not found_path then
-- No rail found: reset back to the expected position
pos = vector.new(self.old_pos)
if new_pos then
-- No rail found: set to the expected position
pos = new_pos
update.pos = true
cart_dir = new_dir
end
elseif self.old_pos and cart_dir.y ~= -1 and not self.punched then
elseif self.old_pos and self.old_dir.y ~= 1 and not self.punched then
-- Stop wiggle
stop_wiggle = true
end
Expand All @@ -223,12 +241,14 @@ local function rail_on_step(self, dtime)
local dir, switch_keys = carts:get_rail_direction(
pos, cart_dir, ctrl, self.old_switch, self.railtype
)
local dir_changed = not vector.equals(dir, self.old_dir)

local new_acc = {x=0, y=0, z=0}
if stop_wiggle or vector.equals(dir, {x=0, y=0, z=0}) then
vel = {x = 0, y = 0, z = 0}
local pos_r = vector.round(pos)
if not carts:is_rail(pos_r, self.railtype) then
if not carts:is_rail(pos_r, self.railtype)
and self.old_pos then
pos = self.old_pos
elseif not stop_wiggle then
pos = pos_r
Expand All @@ -239,7 +259,7 @@ local function rail_on_step(self, dtime)
update.vel = true
else
-- Direction change detected
if not vector.equals(dir, self.old_dir) then
if dir_changed then
vel = vector.multiply(dir, math.abs(vel.x + vel.z))
update.vel = true
if dir.y ~= self.old_dir.y then
Expand Down Expand Up @@ -291,7 +311,7 @@ local function rail_on_step(self, dtime)
end

self.object:set_acceleration(new_acc)
self.old_pos = vector.new(pos)
self.old_pos = vector.round(pos)
if not vector.equals(dir, {x=0, y=0, z=0}) and not stop_wiggle then
self.old_dir = vector.new(dir)
end
Expand Down Expand Up @@ -338,9 +358,15 @@ local function rail_on_step(self, dtime)
end
self.object:set_animation(anim, 1, 0)

self.object:set_velocity(vel)
if update.vel then
self.object:set_velocity(vel)
end
if update.pos then
self.object:set_pos(pos)
if dir_changed then
self.object:set_pos(pos)
else
self.object:move_to(pos)
end
end

-- call event handler
Expand Down
48 changes: 32 additions & 16 deletions mods/carts/functions.lua
Expand Up @@ -99,21 +99,31 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
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 = carts:check_front_up_down(pos, left, false, railtype)
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 = carts:check_front_up_down(pos, right, false, railtype)
cur = self:check_front_up_down(pos, right, false, railtype)
if cur then
return cur, 2
end
Expand All @@ -122,9 +132,11 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
end

-- Normal
cur = carts:check_front_up_down(pos, dir, true, railtype)
if cur then
return cur
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
Expand Down Expand Up @@ -158,33 +170,37 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
return {x=0, y=0, z=0}
end

function carts:pathfinder(pos_, old_pos, old_dir, ctrl, pf_switch, railtype)
if vector.equals(old_pos, pos_) then
return true
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, 3 do
pf_dir, pf_switch = carts:get_rail_direction(
pf_pos, pf_dir, ctrl, pf_switch, railtype)
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 false
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 true
return
end
end
-- Cart not found
return false
-- Not found. Put cart to predicted position
return pf_pos, pf_dir
end

function carts:register_rail(name, def_overwrite, railparams)
Expand Down
2 changes: 2 additions & 0 deletions mods/carts/init.lua
Expand Up @@ -7,6 +7,8 @@ carts.railparams = {}
carts.speed_max = 7
-- Set to -1 to disable punching the cart from inside (min = -1)
carts.punch_speed_max = 5
-- Maximal distance for the path correction (for dtime peaks)
carts.path_distance_max = 3


dofile(carts.modpath.."/functions.lua")
Expand Down

0 comments on commit ecea536

Please sign in to comment.