From 15000be8ec3bd4fe35acd89db30b6a8cc5991759 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Wed, 14 Feb 2024 10:48:55 +0000 Subject: [PATCH] Modify do_movement_step to move to always move to the edge of the current rail segment before updating the direction to prevent oscillations at corners, fix end of track stop location with new movement behavior, disable experimental controls, swap code to detach the driver on float with a call to detach_driver() --- mods/ENTITIES/mcl_minecarts/init.lua | 113 ++++++++++++++++++--------- 1 file changed, 75 insertions(+), 38 deletions(-) diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index d3f2275ac..0d03dde86 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -7,6 +7,7 @@ mcl_minecarts = {} mcl_minecarts.modpath = minetest.get_modpath(modname) mcl_minecarts.speed_max = 10 mcl_minecarts.check_float_time = 15 +local max_step_distance = 0.5 dofile(mcl_minecarts.modpath.."/functions.lua") dofile(mcl_minecarts.modpath.."/rails.lua") @@ -192,6 +193,22 @@ local function make_staticdata( railtype, connected_at, dir ) } end +local function to_dirstring(dir) + if dir.x == 0 then + if dir.z == 1 then + return "north" + else + return "south" + end + elseif dir.z == 0 then + if dir.x == 1 then + return " east" + else + return " west" + end + end +end + local function register_entity(entity_id, mesh, textures, drop, on_rightclick, on_activate_by_rail) local cart = { initial_properties = { @@ -345,16 +362,51 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o local passenger_attach_position = vector.new(0, -1.75, 0) - local function do_movement_step(self, distance) + local function distance_to_next_block( dir, pos ) + if dir.x == 1 then + return 1 - ( pos.x - math.floor(pos.x) ) + elseif dir.x == -1 then + return pos.x - math.floor(pos.x) + elseif dir.z == 1 then + return 1 - ( pos.z - math.floor(pos.z) ) + elseif dir.z == -1 then + return pos.z - math.floor(pos.z) + elseif dir.y == 1 then + return 1 - ( pos.y - math.floor(pos.z) ) + else + return pos.y - math.floor(pos.y) + end + end + + local function do_movement_step(self, remaining_distance) local staticdata = self._staticdata local pos = self.object:get_pos() local dir = staticdata.dir or vector.new(1,0,0) dir = vector.new(dir) - -- Calculate raw location - local next_dir,last_switch = mcl_minecarts:get_rail_direction(pos, dir, nil, nil, staticdata.railtype) - next_dir = vector.new(next_dir) -- Needed to isolate the carts from one another - local next_pos = vector.new(pos + next_dir * distance) + -- Calculate the distance to the next block + -- This is just short of a full block to keep from jumping + local distance_to_next = distance_to_next_block( dir, pos ) - 0.01 + local next_pos + local next_dir,last_switch + next_dir = dir + if distance_to_next < 0.01 then + distance_to_next = 0.5 + + -- Calculate next direction + next_dir,last_switch = mcl_minecarts:get_rail_direction(pos, dir, nil, nil, staticdata.railtype) + next_dir = vector.copy(next_dir) -- Needed to isolate the carts from one another + elseif distance_to_next > max_step_distance then + distance_to_next = max_step_distance + end + + local distance = remaining_distance + if distance > distance_to_next then + distance = distance_to_next + end + + -- Calculate next position + next_pos = vector.new(pos + next_dir * distance) -- Fix up position if next_dir.x == 0 then next_pos.x = math.floor(next_pos.x+0.5) end @@ -363,10 +415,14 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o -- Direction flipped, stop if next_dir == dir * -1 then - print("Stopping cart") -- TODO: detach the cart if there isn't a stop after the rail staticdata.velocity = 0 - next_pos = vector.round(next_pos + dir) + next_pos = vector.round(next_pos) + + if DEBUG and self._driver then + local node_name = minetest.get_node(next_pos).name + print("Stopping cart on "..node_name.." at "..tostring(next_pos)) + end end -- Update cart orientation @@ -393,8 +449,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o end print( prefix .. "pos="..tostring(pos) - ..",dir="..tostring(dir) - ..",next_dir="..tostring(next_dir) + ..",dir="..to_dirstring(dir) + ..",next_dir="..to_dirstring(next_dir) ..",next_pos="..tostring(next_pos) ..",velocity="..tostring(staticdata.velocity) ..",distance="..tostring(distance) @@ -416,6 +472,9 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o new_node_def._mcl_minecarts_on_enter( next_pos_rounded, self ) end end + + -- Report distance traveled + return distance end local function process_acceleration(self, timestep) @@ -466,30 +525,15 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o -- causing large timesteps local total_distance = dtime * ( staticdata.velocity or 0 ) local remaining_distance = total_distance - local max_step_distance = 0.5 - local steps = math.ceil(total_distance / max_step_distance ) process_acceleration(self,dtime * max_step_distance / total_distance) - for i = 1,steps do - local step_distance = max_step_distance - if remaining_distance < max_step_distance then - step_distance = remaining_distance - remaining_distance = 0 - else - remaining_distance = remaining_distance - max_step_distance - end - - -- Don't try to perform very small steps - if step_distance < 0.001 then break end - - -- Handle acceleration on everything except the first step, as that was - -- done outside the loop - if i ~= 1 then + while remaining_distance > 0.1 do + local step_distance = do_movement_step(self, remaining_distance) + if step_distance > 0.1 then process_acceleration(self, dtime * step_distance / total_distance) end - - do_movement_step(self, step_distance) + remaining_distance = remaining_distance - step_distance end -- Clear punched flag now that movement for this step has been completed @@ -521,8 +565,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o end -- Experimental controls - self._go_forward = ctrl.up - self._brake = ctrl.down + --self._go_forward = ctrl.up + --self._brake = ctrl.down end -- Give achievement when player reached a distance of 1000 nodes from the start position @@ -583,14 +627,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o local g = minetest.get_item_group(node.name, "connect_to_raillike") if g ~= self._staticdata.railtype and self._staticdata.railtype then -- Detach driver - if player then - if self._old_pos then - self.object:set_pos(self._old_pos) - end - mcl_player.player_attached[self._driver] = nil - player:set_detach() - player:set_eye_offset(vector.new(0,0,0),vector.new(0,0,0)) - end + detach_driver(self) -- Explode if already ignited if self._boomtimer then