From ecea5364f1bf0e1e6dd553c52c4122affd006c39 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sat, 7 Jul 2018 03:08:36 +0200 Subject: [PATCH] Update carts from boost_cart 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. --- mods/carts/cart_entity.lua | 54 ++++++++++++++++++++++++++++---------- mods/carts/functions.lua | 48 ++++++++++++++++++++++----------- mods/carts/init.lua | 2 ++ 3 files changed, 74 insertions(+), 30 deletions(-) diff --git a/mods/carts/cart_entity.lua b/mods/carts/cart_entity.lua index 434ea94..38337db 100644 --- a/mods/carts/cart_entity.lua +++ b/mods/carts/cart_entity.lua @@ -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 @@ -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 @@ -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() @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/mods/carts/functions.lua b/mods/carts/functions.lua index 8408cc1..a54b594 100644 --- a/mods/carts/functions.lua +++ b/mods/carts/functions.lua @@ -99,6 +99,16 @@ 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 @@ -106,14 +116,14 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) 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 @@ -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 @@ -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) diff --git a/mods/carts/init.lua b/mods/carts/init.lua index b2ba5f3..fe45303 100644 --- a/mods/carts/init.lua +++ b/mods/carts/init.lua @@ -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")