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

This commit is contained in:
teknomunk 2024-02-16 23:09:29 +00:00
parent c9d6a417cd
commit 2dcb790ace
3 changed files with 88 additions and 95 deletions

View File

@ -188,8 +188,9 @@ local function make_staticdata( railtype, connected_at, dir )
return { return {
railtype = railtype, railtype = railtype,
connected_at = connected_at, connected_at = connected_at,
distance = 0,
velocity = 0,
dir = vector.new(dir), dir = vector.new(dir),
velocity = 0
} }
end 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 function do_movement_step(self, remaining_distance)
local staticdata = self._staticdata 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 local pos = staticdata.connected_at
-- 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 if not pos then return remaining_distance end
next_dir,last_switch = mcl_minecarts:get_rail_direction(pos, dir, nil, nil, staticdata.railtype) if staticdata.velocity < 0.1 then return remaining_distance end
next_dir = vector.copy(next_dir) -- Needed to isolate the carts from one another
elseif distance_to_next > max_step_distance then local remaining_in_block = 1 - ( staticdata.distance or 0 )
distance_to_next = max_step_distance 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
-- 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 end
local distance = remaining_distance -- Anchor at the next node
if distance > distance_to_next then pos = pos + staticdata.dir
distance = distance_to_next 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 end
-- Calculate next position -- check for hopper under the rail
next_pos = vector.new(pos + next_dir * distance) 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
-- Fix up position -- Get the next direction
if next_dir.x == 0 then next_pos.x = math.floor(next_pos.x+0.5) end next_dir,last_switch = mcl_minecarts:get_rail_direction(pos, staticdata.dir, nil, nil, staticdata.railtype)
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 -- Handle end of track
if next_dir == dir * -1 then if next_dir == staticdata.dir * -1 then
-- TODO: detach the cart if there isn't a stop after the rail print("Stopping cart at "..tostring(pos))
staticdata.velocity = 0 staticdata.velocity = 0
local next_pos_before_round = vector.copy(next_pos) distence = remaining_distance
next_pos = vector.round(next_pos + dir * 0.5) end
if DEBUG and self._driver then -- Update cart direction
local node_name = minetest.get_node(next_pos).name staticdata.dir = next_dir
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
)
end
end end
self.object:move_to(pos)
-- Update cart orientation -- Update cart orientation
local yaw = 0 local yaw = 0
if next_dir.x < 0 then local dir = staticdata.dir
if dir.x < 0 then
yaw = 0.5 yaw = 0.5
elseif next_dir.x > 0 then elseif dir.x > 0 then
yaw = 1.5 yaw = 1.5
elseif dir.z < 0 then elseif dir.z < 0 then
yaw = 1 yaw = 1
end end
self.object:set_yaw( yaw * math.pi ) 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 -- Report distance traveled
return distance return distance
end end
local function process_acceleration(self, timestep) local function process_acceleration(self, timestep)
local staticdata = self._staticdata 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_name = minetest.get_node(pos).name
local node_def = minetest.registered_nodes[node_name] local node_def = minetest.registered_nodes[node_name]
local max_vel = mcl_minecarts.speed_max
if self._go_forward then if self._go_forward then
self._acceleration = 2 self._acceleration = 2
@ -498,17 +476,20 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
self._acceleration = 2 self._acceleration = 2
elseif self._fueltime and self._fueltime > 0 then elseif self._fueltime and self._fueltime > 0 then
self._acceleration = 0.6 self._acceleration = 0.6
else
if staticdata.velocity >= ( node_def._max_acceleration_velocity or max_vel ) then
self._acceleration = 0
else else
self._acceleration = node_def._rail_acceleration or -0.4 self._acceleration = node_def._rail_acceleration or -0.4
end 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 staticdata.velocity = 0.1
end end
if math.abs(self._acceleration) > 0.1 then if math.abs(self._acceleration) > 0.1 then
staticdata.velocity = ( staticdata.velocity or 0 ) + self._acceleration * timestep staticdata.velocity = ( staticdata.velocity or 0 ) + self._acceleration * timestep
local max_vel = mcl_minecarts.speed_max
if staticdata.velocity > max_vel then if staticdata.velocity > max_vel then
staticdata.velocity = max_vel staticdata.velocity = max_vel
elseif staticdata.velocity < 0.1 then elseif staticdata.velocity < 0.1 then
@ -516,7 +497,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end end
end end
if false and staticdata.velocity > 0 then if DEBUG and staticdata.velocity > 0 then
print( " acceleration="..tostring(self._acceleration)..",velocity="..tostring(staticdata.velocity).. print( " acceleration="..tostring(self._acceleration)..",velocity="..tostring(staticdata.velocity)..
",timestep="..tostring(timestep)) ",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 function do_movement( self, dtime )
local staticdata = self._staticdata 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 -- Break long movements into fixed-size steps so that
-- it is impossible to jump across gaps due to server lag -- it is impossible to jump across gaps due to server lag
-- causing large timesteps -- causing large timesteps
@ -555,8 +544,8 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end end
local pos, rou_pos, node = self.object:get_pos() local pos, rou_pos, node = self.object:get_pos()
local update = {} --local update = {}
local acceleration = 0 --local acceleration = 0
-- Controls -- Controls
local ctrl, player = nil, nil local ctrl, player = nil, nil

View File

@ -50,7 +50,7 @@ end
local rail_rules_long = local rail_rules_long =
{{x=-1, y= 0, z= 0, spread=true}, {{x=-1, y= 0, z= 0, spread=true},
{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= 1, z= 0, spread=true},
{x= 0, y= 0, z=-1, spread=true}, {x= 0, y= 0, z=-1, 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, _doc_items_create_entry = false,
_rail_acceleration = 4, _rail_acceleration = 4,
_max_acceleration_velocity = 8,
mesecons = { mesecons = {
conductor = { conductor = {
state = mesecon.state.on, state = mesecon.state.on,

View File

@ -9,6 +9,8 @@ local function mcl_log(message)
end end
end end
mcl_hoppers = {}
--[[ BEGIN OF NODE DEFINITIONS ]] --[[ BEGIN OF NODE DEFINITIONS ]]
local mcl_hoppers_formspec = table.concat({ 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()) dest_inv:add_item("main", stack:take_item())
inv:set_stack("main", i, stack) inv:set_stack("main", i, stack)
-- Take one item and stop until next time -- Take one item and stop until next time, report that we took something
return return true
else else
mcl_log("no Room") mcl_log("no Room")
end end
@ -475,6 +477,7 @@ local function hopper_pull_from_mc(mc_ent, dest_pos, inv_size)
end end
end 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 function hopper_push_to_mc(mc_ent, dest_pos, inv_size)
local dest_inv = mcl_entity_invs.load_inv(mc_ent, inv_size) local dest_inv = mcl_entity_invs.load_inv(mc_ent, inv_size)