From 8c6b011c913ac3097501b0de0a1011fcd0b9c82b Mon Sep 17 00:00:00 2001 From: teknomunk Date: Fri, 16 Feb 2024 23:09:29 +0000 Subject: [PATCH] Change connected railcar behavior to fix unreliable end of track stopping, set maximum acceleration of powered rails to 8 blocks per second (per https://minecraft.fandom.com/wiki/Powered_Rail), stop powered rails from powering the block underneath it (allows below rail hopper to work while the rail is powered like in https://www.youtube.com/watch?v=szjO0-duTAk), modify mcl_hoppers to allow triggering a hopper pull once the minecart is stopped on top of the hopper and wait before allowing the cart to move to allow redstone circuits time to process --- mods/ENTITIES/mcl_minecarts/init.lua | 173 ++++++++++++-------------- mods/ENTITIES/mcl_minecarts/rails.lua | 3 +- mods/ITEMS/mcl_hoppers/init.lua | 7 +- 3 files changed, 88 insertions(+), 95 deletions(-) diff --git a/mods/ENTITIES/mcl_minecarts/init.lua b/mods/ENTITIES/mcl_minecarts/init.lua index 2b0561636..1a6115c81 100644 --- a/mods/ENTITIES/mcl_minecarts/init.lua +++ b/mods/ENTITIES/mcl_minecarts/init.lua @@ -188,8 +188,9 @@ local function make_staticdata( railtype, connected_at, dir ) return { railtype = railtype, connected_at = connected_at, + distance = 0, + velocity = 0, dir = vector.new(dir), - velocity = 0 } end @@ -380,115 +381,92 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o 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 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 + local pos = staticdata.connected_at - -- 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 + if not pos then return remaining_distance end + if staticdata.velocity < 0.1 then return remaining_distance end - local distance = remaining_distance - if distance > distance_to_next then - distance = distance_to_next - end + local remaining_in_block = 1 - ( staticdata.distance or 0 ) + local dinstance = 0 + if remaining_in_block > remaining_distance then + distance = remaining_distance + staticdata.distance = ( staticdata.distance or 0 ) + distance + pos = pos + staticdata.dir * staticdata.distance + else + distance = remaining_in_block + staticdata.distance = 0 - -- 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 - if next_dir.y == 0 then next_pos.y = math.floor(next_pos.y+0.5) end - if next_dir.z == 0 then next_pos.z = math.floor(next_pos.z+0.5) end - - -- Direction flipped, stop - if next_dir == dir * -1 then - -- TODO: detach the cart if there isn't a stop after the rail - staticdata.velocity = 0 - local next_pos_before_round = vector.copy(next_pos) - next_pos = vector.round(next_pos + dir * 0.5) - - 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) - .." pos="..tostring(pos) - ..",next_pos="..tostring(next_pos) - ..",next_pos_before_round="..tostring(next_pos_before_round) - ..",distance="..distance - ) + -- Leave the old node + local old_node_name = minetest.get_node(pos).name + local old_node_def = minetest.registered_nodes[old_node_name] + if old_node_def._mcl_minecarts_on_leave then + old_node_def._mcl_minecarts_on_leave( pos, self ) end + + -- Anchor at the next node + pos = pos + staticdata.dir + staticdata.connected_at = pos + + -- Enter the new node + local new_node_name = minetest.get_node(pos).name + local new_node_def = minetest.registered_nodes[new_node_name] + if new_node_def._mcl_minecarts_on_enter then + new_node_def._mcl_minecarts_on_enter( pos, self ) + end + + -- check for hopper under the rail + local under_pos = pos - vector.new(0,1,0) + local under_node_name = minetest.get_node(under_pos).name + local under_node_def = minetest.registered_nodes[under_node_name] + print( "under_node_name="..under_node_name..", hopper="..tostring(under_node_def.groups.hopper)) + if under_node_def and under_node_def.groups.hopper ~= 0 then + print( "Attempt pull_from_minecart" ) + if mcl_hoppers.pull_from_minecart( self, under_pos, self._inv_size or 0 ) then + staticdata.delay = 1.5 + end + end + + -- Get the next direction + next_dir,last_switch = mcl_minecarts:get_rail_direction(pos, staticdata.dir, nil, nil, staticdata.railtype) + + -- Handle end of track + if next_dir == staticdata.dir * -1 then + print("Stopping cart at "..tostring(pos)) + staticdata.velocity = 0 + distence = remaining_distance + end + + -- Update cart direction + staticdata.dir = next_dir end + self.object:move_to(pos) + -- Update cart orientation local yaw = 0 - if next_dir.x < 0 then + local dir = staticdata.dir + if dir.x < 0 then yaw = 0.5 - elseif next_dir.x > 0 then + elseif dir.x > 0 then yaw = 1.5 elseif dir.z < 0 then yaw = 1 end self.object:set_yaw( yaw * math.pi ) - -- Update cart position - local next_pos_rounded = vector.round(next_pos) - staticdata.connected_at = next_pos_rounded - staticdata.dir = next_dir - self.object:move_to(next_pos) - - if DEBUG and self._driver then - local prefix = " " - if next_dir ~= dir then - prefix = "--->" - end - print( prefix - .. "pos="..tostring(pos) - ..",dir="..to_dirstring(dir) - ..",next_dir="..to_dirstring(next_dir) - ..",next_pos="..tostring(next_pos) - ..",velocity="..tostring(staticdata.velocity) - ..",distance="..tostring(distance) - ) - end - - -- Handle track interactions - local pos_rounded = vector.round(pos) - if pos_rounded ~= next_pos_rounded then - local old_node_name = minetest.get_node(pos_rounded).name - local old_node_def = minetest.registered_nodes[old_node_name] - if old_node_def._mcl_minecarts_on_leave then - old_node_def._mcl_minecarts_on_leave( pos_rounded, self ) - end - - local new_node_name = minetest.get_node(next_pos_rounded).name - local new_node_def = minetest.registered_nodes[new_node_name] - if new_node_def._mcl_minecarts_on_enter then - 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) local staticdata = self._staticdata + if not staticdata.connected_at then return end - local pos = self.object:get_pos() + local pos = staticdata.connected_at local node_name = minetest.get_node(pos).name local node_def = minetest.registered_nodes[node_name] + local max_vel = mcl_minecarts.speed_max if self._go_forward then self._acceleration = 2 @@ -499,16 +477,19 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o elseif self._fueltime and self._fueltime > 0 then self._acceleration = 0.6 else - self._acceleration = node_def._rail_acceleration or -0.4 + if staticdata.velocity >= ( node_def._max_acceleration_velocity or max_vel ) then + self._acceleration = 0 + else + self._acceleration = node_def._rail_acceleration or -0.4 + end end - if self._acceleration > 0 and staticdata.velocity < 0.1 then + if self._acceleration > 0 and (staticdata.velocity or 0) < 0.1 then staticdata.velocity = 0.1 end if math.abs(self._acceleration) > 0.1 then staticdata.velocity = ( staticdata.velocity or 0 ) + self._acceleration * timestep - local max_vel = mcl_minecarts.speed_max if staticdata.velocity > max_vel then staticdata.velocity = max_vel elseif staticdata.velocity < 0.1 then @@ -516,8 +497,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o end end - if false and staticdata.velocity > 0 then - print( "acceleration="..tostring(self._acceleration)..",velocity="..tostring(staticdata.velocity).. + if DEBUG and staticdata.velocity > 0 then + print( " acceleration="..tostring(self._acceleration)..",velocity="..tostring(staticdata.velocity).. ",timestep="..tostring(timestep)) end end @@ -526,6 +507,14 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o local function do_movement( self, dtime ) local staticdata = self._staticdata + -- Allow the carts to be delay for the rest of the world to react before moving again + if ( staticdata.delay or 0 ) > dtime then + staticdata.delay = staticdata.delay - dtime + return + else + staticdata.delay = 0 + end + -- Break long movements into fixed-size steps so that -- it is impossible to jump across gaps due to server lag -- causing large timesteps @@ -555,8 +544,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o end local pos, rou_pos, node = self.object:get_pos() - local update = {} - local acceleration = 0 + --local update = {} + --local acceleration = 0 -- Controls local ctrl, player = nil, nil diff --git a/mods/ENTITIES/mcl_minecarts/rails.lua b/mods/ENTITIES/mcl_minecarts/rails.lua index a5b967a07..802d747e4 100644 --- a/mods/ENTITIES/mcl_minecarts/rails.lua +++ b/mods/ENTITIES/mcl_minecarts/rails.lua @@ -50,7 +50,7 @@ end local rail_rules_long = {{x=-1, y= 0, z= 0, spread=true}, {x= 1, y= 0, z= 0, spread=true}, - {x= 0, y=-1, z= 0, spread=true}, +-- {x= 0, y=-1, z= 0, spread=true}, {x= 0, y= 1, z= 0, spread=true}, {x= 0, y= 0, z=-1, spread=true}, {x= 0, y= 0, z= 1, spread=true}, @@ -105,6 +105,7 @@ register_rail("mcl_minecarts:golden_rail_on", { _doc_items_create_entry = false, _rail_acceleration = 4, + _max_acceleration_velocity = 8, mesecons = { conductor = { state = mesecon.state.on, diff --git a/mods/ITEMS/mcl_hoppers/init.lua b/mods/ITEMS/mcl_hoppers/init.lua index ec7f7ab8f..9af8ff650 100644 --- a/mods/ITEMS/mcl_hoppers/init.lua +++ b/mods/ITEMS/mcl_hoppers/init.lua @@ -9,6 +9,8 @@ local function mcl_log(message) end end +mcl_hoppers = {} + --[[ BEGIN OF NODE DEFINITIONS ]] local mcl_hoppers_formspec = table.concat({ @@ -464,8 +466,8 @@ local function hopper_pull_from_mc(mc_ent, dest_pos, inv_size) dest_inv:add_item("main", stack:take_item()) inv:set_stack("main", i, stack) - -- Take one item and stop until next time - return + -- Take one item and stop until next time, report that we took something + return true else mcl_log("no Room") end @@ -475,6 +477,7 @@ local function hopper_pull_from_mc(mc_ent, dest_pos, inv_size) end end end +mcl_hoppers.pull_from_minecart = hopper_pull_from_mc local function hopper_push_to_mc(mc_ent, dest_pos, inv_size) local dest_inv = mcl_entity_invs.load_inv(mc_ent, inv_size)