Cleanup code, restore uphill/downhill cart movement, completely remove old rail

This commit is contained in:
teknomunk 2024-04-04 22:08:20 +00:00
parent cf955109c9
commit b1d8809a4d
2 changed files with 148 additions and 234 deletions

View File

@ -7,7 +7,6 @@ function get_path(base, first, ...)
if not base then return end
return get_path(base[first], ...)
end
local function force_get_node(pos)
local node = minetest.get_node(pos)
if node.name ~= "ignore" then return node end
@ -66,31 +65,11 @@ function mcl_minecarts:is_rail(pos, railtype)
return minetest.get_item_group(node_name, "connect_to_raillike") == railtype
end
--[[
Returns a string description of a direction, with optional _up/_down suffix
]]
function mcl_minecarts:name_from_dir(dir, vertical)
local res = ""
if dir.z == 1 then res = res .. "n" end
if dir.z == -1 then res = res .. "s" end
if dir.x == -1 then res = res .. "w" end
if dir.x == 1 then res = res .. "e" end
if vertical then
if dir.y == 1 then res = res .. "_up" end
if dir.y == 1 then res = res .. "_down" end
end
return res
end
local north = vector.new( 0, 0, 1); local N = 1
local south = vector.new( 0, 0,-1); local S = 2 -- Note: S is overwritten below with the translator
local east = vector.new( 1, 0, 0); local E = 4
local west = vector.new(-1, 0, 0); local W = 8
-- Directional constants
local north = vector.new( 0, 0, 1); local N = 1 -- 4dir = 0
local east = vector.new( 1, 0, 0); local E = 4 -- 4dir = 1
local south = vector.new( 0, 0,-1); local S = 2 -- 4dir = 2 Note: S is overwritten below with the translator
local west = vector.new(-1, 0, 0); local W = 8 -- 4dir = 3
-- Share. Consider moving this to some shared location
mod.north = north
@ -191,6 +170,16 @@ local function make_sloped_if_straight(pos, dir)
end
end
local function is_connection(pos, dir)
local node = force_get_node(pos)
local nodedef = minetest.registered_nodes[node.name]
local get_next_dir = get_path(nodedef, "_mcl_minecarts", "get_next_dir")
if not get_next_dir then return end
return get_next_dir(pos, dir, node) == dir
end
local function get_rail_connections(pos, opt)
local legacy = opt and opt.legacy
local ignore_neighbor_connections = opt and opt.ignore_neighbor_connections
@ -204,7 +193,7 @@ local function get_rail_connections(pos, opt)
-- Only allow connections to the open ends of rails, as decribed by get_next_dir
if get_path(nodedef, "groups", "rail") and ( legacy or get_path(nodedef, "_mcl_minecarts", "get_next_dir" ) ) then
local rev_dir = vector.direction(dir,vector.new(0,0,0))
if ignore_neighbor_connections or mcl_minecarts:is_connection(neighbor, rev_dir) then
if ignore_neighbor_connections or is_connection(neighbor, rev_dir) then
connections = connections + bit.lshift(1,i - 1)
end
end
@ -272,7 +261,7 @@ local function update_rail_connections(pos, opt)
for _,dir in ipairs(CONNECTIONS) do
local higher_rail_pos = vector.offset(pos,dir.x,1,dir.z)
local rev_dir = vector.direction(dir,vector.new(0,0,0))
if mcl_minecarts:is_rail(higher_rail_pos) and mcl_minecarts:is_connection(higher_rail_pos, rev_dir) then
if mcl_minecarts:is_rail(higher_rail_pos) and is_connection(higher_rail_pos, rev_dir) then
make_sloped_if_straight(pos, rev_dir)
end
end
@ -281,85 +270,45 @@ local function update_rail_connections(pos, opt)
end
mod.update_rail_connections = update_rail_connections
--[[
An array of (u,v,w) positions to check. Actual direction is u * dir + v * right + w * up
]]
local rail_checks = {
{ 1, 0, 0 }, -- forwards
{ 1, 0, 1 }, -- forwards and up
{ 1, 0, -1 }, -- forwards and down
{ 1, 1, 0 }, -- diagonal left
{ 0, 1, 0 }, -- left
{ 0, 1, 1 }, -- left and up
{ 0, 1, -1 }, -- left and down
{ 1, -1, 0 }, -- diagonal right
{ 0, -1, 0 }, -- right
{ 0, -1, 1 }, -- right and up
{ 0, -1, -1 }, -- right and down
{ -1, 0, 0 }, -- backwards
}
local rail_checks_diagonal = {
{ 1, 1, 0 }, -- forward along diagonal
{ 1, 0, 0 }, -- left
{ 0, 1, 0 }, -- right
}
local north = vector.new(0,0,1)
local south = vector.new(0,0,-1)
local east = vector.new(1,0,0)
local west = vector.new(-1,0,0)
-- Rotate diagonal directions 45 degrees clockwise
local diagonal_convert = {
nw = west,
ne = north,
se = east,
sw = south,
}
local function is_ahead_slope(pos, dir)
local ahead = vector.add(pos,dir)
if mcl_minecarts:is_rail(ahead) then return false end
function mcl_minecarts:is_connection(pos, dir)
local node = force_get_node(pos)
local nodedef = minetest.registered_nodes[node.name]
local below = vector.offset(ahead,0,-1,0)
if not mcl_minecarts:is_rail(below) then return false end
local get_next_dir = get_path(nodedef, "_mcl_minecarts", "get_next_dir")
if not get_next_dir then return end
return get_next_dir(pos, dir, node) == dir
local node_name = force_get_node(below).name
return minetest.get_item_group(node_name, "rail_slope") ~= 0
end
function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
local pos = vector.round(pos_)
-- Handle new track types that have track-specific direction handler
local node = minetest.get_node(pos)
local node_def = minetest.registered_nodes[node.name]
if node_def and node_def._mcl_minecarts and node_def._mcl_minecarts.get_next_dir then
return node_def._mcl_minecarts.get_next_dir(pos, dir, node)
local get_next_dir = get_path(node_def,"_mcl_minecarts","get_next_dir")
if not get_next_dir then return dir end
dir = node_def._mcl_minecarts.get_next_dir(pos, dir, node)
-- Handle going downhill
if is_ahead_slope(pos,dir) then
dir = vector.offset(dir,0,-1,0)
end
-- Diagonal conversion
local checks = rail_checks
if dir.x ~= 0 and dir.z ~= 0 then
dir = diagonal_convert[ mcl_minecarts:name_from_dir(dir, false) ]
checks = rail_checks_diagonal
-- Handle reversing if there is a solid block in the next position
local next_pos = vector.add(pos, dir)
local next_node = minetest.get_node(next_pos)
local node_def = minetest.registered_nodes[next_node.name]
if node_def and node_def.groups and ( node_def.groups.solid or node_def.groups.stair ) then
-- Reverse the direction without giving -0 members
return vector.direction(next_pos, pos)
else
return dir
end
-- Calculate coordinate space
local right = vector.new( dir.z, dir.y, -dir.x)
local up = vector.new(0,1,0)
-- Perform checks
for _,check in ipairs(checks) do
local check_dir = dir * check[1] + right * check[2] + up * check[3]
local check_pos = pos + check_dir
if mcl_minecarts:is_rail(check_pos,railtype) then
return check_dir
end
end
return vector.new(0,0,0)
end

View File

@ -1,11 +1,13 @@
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local mod = mcl_minecarts
local S = minetest.get_translator(modname)
mod.RAIL_GROUPS = {
STANDARD = 1,
CURVES = 2,
}
local S = minetest.get_translator(modname)
-- Inport functions and constants from elsewhere
local table_merge = mcl_util.table_merge
local check_connection_rules = mod.check_connection_rules
local update_rail_connections = mod.update_rail_connections
@ -14,14 +16,6 @@ local south = mod.south
local east = mod.east
local west = mod.west
-- Setup shared text
local railuse = S(
"Place them on the ground to build your railway, the rails will automatically connect to each other and will"..
" turn into curves, T-junctions, crossings and slopes as needed."
)
mod.text = mod.text or {}
mod.text.railuse = railuse
local function drop_railcarts(pos)
-- Scan for minecarts in this pos and force them to execute their "floating" check.
-- Normally, this will make them drop.
@ -37,60 +31,78 @@ local function drop_railcarts(pos)
end
end
local RAIL_DEFAULTS = {
is_ground_content = true,
paramtype = "light",
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
stack_max = 64,
sounds = mcl_sounds.node_sound_metal_defaults(),
_mcl_blast_resistance = 0.7,
_mcl_hardness = 0.7,
after_destruct = drop_railcarts,
}
local RAIL_DEFAULT_GROUPS = {
handy=1, pickaxey=1,
attached_node=1,
rail=1,
connect_to_raillike=minetest.raillike_group("rail"),
dig_by_water=0,destroy_by_lava_flow=0,
transport=1
}
-- Template rail function
local function register_rail(itemstring, tiles, def_extras, creative)
local groups = table.copy(RAIL_DEFAULT_GROUPS)
if creative == false then
groups.not_in_creative_inventory = 1
--- Rail direction Handleres
local function rail_dir_straight(pos, dir, node)
if node.param2 == 0 or node.param2 == 2 then
if vector.equals(dir, north) then
return north
else
return south
end
else
if vector.equals(dir,east) then
return east
else
return west
end
end
local ndef = {
drawtype = "raillike",
tiles = tiles,
inventory_image = tiles[1],
wield_image = tiles[1],
groups = groups,
}
table_merge(ndef, RAIL_DEFAULTS)
ndef.walkable = false -- Old behavior
table_merge(ndef, def_extras)
minetest.register_node(itemstring, ndef)
end
local function rail_dir_sloped(pos, dir, node)
local uphill = minetest.fourdir_to_dir(node.param2)
local downhill = minetest.fourdir_to_dir((node.param2+2)%4)
local up_uphill = vector.offset(uphill,0,1,0)
if vector.equals(dir, uphill) or vector.equals(dir, up_uphill) then
return up_uphill
else
return downhill
end
end
local function rail_dir_curve(pos, dir, node)
if node.param2 == 0 then -- north
-- South and East
if vector.equals(dir, south) then return south end
if vector.equals(dir, north) then return east end
if vector.equals(dir, west) then return south end
if vector.equals(dir, east) then return east end
elseif node.param2 == 1 then -- east
-- South and West
if vector.equals(dir, south) then return south end
if vector.equals(dir, north) then return west end
if vector.equals(dir, west) then return west end
if vector.equals(dir, east) then return south end
elseif node.param2 == 2 then
-- North and West
if vector.equals(dir, south) then return west end
if vector.equals(dir, north) then return north end
if vector.equals(dir, west) then return west end
if vector.equals(dir, east) then return north end
elseif node.param2 == 3 then
-- North and East
if vector.equals(dir, south) then return east end
if vector.equals(dir, north) then return north end
if vector.equals(dir, west) then return north end
if vector.equals(dir, east) then return east end
end
end
local function rail_dir_tee(pos, dir, node)
minetest.log("warning","TODO: implement rail_dir_tee()")
return north
end
local function rail_dir_cross(pos, dir, node)
-- Always continue in the same direction. No direction changes allowed
return dir
end
-- Now get the translator after we have finished using S for other things
-- Setup shared text
local railuse = S(
"Place them on the ground to build your railway, the rails will automatically connect to each other and will"..
" turn into curves, T-junctions, crossings and slopes as needed."
)
mod.text = mod.text or {}
mod.text.railuse = railuse
local BASE_DEF = {
description = S("New Rail"), -- Temporary name to make debugging easier
_tt_help = S("Track for minecarts"),
_doc_items_usagehelp = railuse,
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction."),
after_place_node = function(pos, placer, itemstack, pointed_thing)
update_rail_connections(pos)
end,
drawtype = "nodebox",
groups = RAIL_DEFAULT_GROUPS,
node_box = {
type = "fixed",
fixed = {
@ -99,13 +111,44 @@ local BASE_DEF = {
},
paramtype = "light",
paramtype2 = "4dir",
stack_max = 64,
sounds = mcl_sounds.node_sound_metal_defaults(),
is_ground_content = true,
paramtype = "light",
selection_box = {
type = "fixed",
fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
},
groups = {
handy=1, pickaxey=1,
attached_node=1,
rail=1,
connect_to_raillike=minetest.raillike_group("rail"),
dig_by_water=0,destroy_by_lava_flow=0,
transport=1
},
description = S("New Rail"), -- Temporary name to make debugging easier
_tt_help = S("Track for minecarts"),
_doc_items_usagehelp = railuse,
_doc_items_longdesc = S("Rails can be used to build transport tracks for minecarts. Normal rails slightly slow down minecarts due to friction."),
after_place_node = function(pos, placer, itemstack, pointed_thing)
update_rail_connections(pos)
end,
after_destruct = drop_railcarts,
_mcl_minecarts = {
get_next_dir = rail_dir_straight,
},
_mcl_blast_resistance = 0.7,
_mcl_hardness = 0.7,
}
table_merge(BASE_DEF, RAIL_DEFAULTS) -- Merge together old rail values
local SLOPED_RAIL_DEF = table.copy(BASE_DEF)
table_merge(SLOPED_RAIL_DEF,{
drawtype = "mesh",
mesh = "sloped_track.obj",
groups = {
rail_slope = 1,
},
collision_box = {
type = "fixed",
fixed = {
@ -119,7 +162,10 @@ table_merge(SLOPED_RAIL_DEF,{
{ -0.5, -0.5, -0.5, 0.5, 0.0, 0.5 },
{ -0.5, 0.0, 0.0, 0.5, 0.5, 0.5 }
}
}
},
_mcl_minecarts = {
get_next_dir = rail_dir_sloped,
},
})
local function register_rail_v2(itemstring, ndef)
@ -141,75 +187,6 @@ local function register_rail_v2(itemstring, ndef)
end
mod.register_rail = register_rail_v2
local function rail_dir_straight(pos, dir, node)
local function inside(pos,dir,node)
if node.param2 == 0 or node.param2 == 2 then
if vector.equals(dir, north) then
return north
else
return south
end
else
if vector.equals(dir,east) then
return east
else
return west
end
end
end
local raw_dir = inside(pos, dir, node)
-- Handle reversing if there is a solid block in the next position
-- Only do this for straight tracks
local next_pos = vector.add(pos, raw_dir)
local next_node = minetest.get_node(next_pos)
local node_def = minetest.registered_nodes[next_node.name]
if node_def and node_def.groups and ( node_def.groups.solid or node_def.groups.stair ) then
-- Reverse the direction without giving -0 members
return vector.direction(next_pos, pos)
else
return raw_dir
end
end
local function rail_dir_curve(pos, dir, node)
if node.param2 == 0 then
-- South and East
if vector.equals(dir, south) then return south end
if vector.equals(dir, north) then return east end
if vector.equals(dir, west) then return south end
if vector.equals(dir, east) then return east end
elseif node.param2 == 1 then
-- South and West
if vector.equals(dir, south) then return south end
if vector.equals(dir, north) then return west end
if vector.equals(dir, west) then return west end
if vector.equals(dir, east) then return south end
elseif node.param2 == 2 then
-- North and West
if vector.equals(dir, south) then return west end
if vector.equals(dir, north) then return north end
if vector.equals(dir, west) then return west end
if vector.equals(dir, east) then return north end
elseif node.param2 == 3 then
-- North and East
if vector.equals(dir, south) then return east end
if vector.equals(dir, north) then return north end
if vector.equals(dir, west) then return north end
if vector.equals(dir, east) then return east end
end
end
local function rail_dir_tee(pos, dir, node)
-- TODO: implement
return north
end
local function rail_dir_cross(pos, dir, node)
-- Always continue in the same direction. No direction changes allowed
return dir
end
local function register_straight_rail(base_name, tiles, def)
def = def or {}
local base_def = table.copy(BASE_DEF)
@ -222,7 +199,6 @@ local function register_straight_rail(base_name, tiles, def)
},
_mcl_minecarts = {
base_name = base_name,
get_next_dir = rail_dir_straight,
can_slope = true,
},
}
@ -245,7 +221,7 @@ local function register_straight_rail(base_name, tiles, def)
mod.register_rail_sloped(base_name.."_sloped", table_merge(table.copy(base_def),{
description = S("Sloped Rail"), -- Temporary name to make debugging easier
_mcl_minecarts = {
get_next_dir = rail_dir_cross,
get_next_dir = rail_dir_sloped,
},
tiles = { tiles[1] },
_mcl_minecarts = {
@ -336,7 +312,7 @@ local function register_curves_rail(base_name, tiles, def)
mod.register_rail_sloped(base_name.."_sloped", table_merge(table.copy(sloped_def),{
description = S("Sloped Rail"), -- Temporary name to make debugging easier
_mcl_minecarts = {
get_next_dir = rail_dir_cross,
get_next_dir = rail_dir_sloped,
railtype = "tee",
},
tiles = { tiles[1] },
@ -346,6 +322,7 @@ local function register_curves_rail(base_name, tiles, def)
mod.register_rail(base_name.."_cross", table_merge(table.copy(base_def),{
tiles = { tiles[5] },
_mcl_minecarts = {
get_next_dir = rail_dir_cross,
railtype = "cross",
},
}))
@ -355,11 +332,6 @@ mod.register_curves_rail = register_curves_rail
local function register_rail_sloped(itemstring, def)
assert(def.tiles)
-- Build rail groups
local groups = table.copy(RAIL_DEFAULT_GROUPS)
if def.groups then table_merge(groups, def.groups) end
def.groups = groups
-- Build the node definition
local ndef = table.copy(SLOPED_RAIL_DEF)
table_merge(ndef, def)
@ -416,7 +388,6 @@ mod.register_curves_rail("mcl_minecarts:rail_v2", {
}
},
})
register_rail("mcl_minecarts:rail", {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"}, {}, false ) -- deprecated
-- Powered rail (off = brake mode)
mod.register_straight_rail("mcl_minecarts:golden_rail_v2",{ "mcl_minecarts_rail_golden.png" },{
@ -446,7 +417,6 @@ mod.register_straight_rail("mcl_minecarts:golden_rail_v2",{ "mcl_minecarts_rail_
}
}
})
register_rail("mcl_minecarts:golden_rail", {"mcl_minecarts_rail_golden.png", "mcl_minecarts_rail_golden_curved.png", "mcl_minecarts_rail_golden_t_junction.png", "mcl_minecarts_rail_golden_crossing.png"}, {}, false ) -- deprecated
-- Powered rail (on = acceleration mode)
mod.register_straight_rail("mcl_minecarts:golden_rail_v2_on",{ "mcl_minecarts_rail_golden_powered.png" },{
@ -466,7 +436,6 @@ mod.register_straight_rail("mcl_minecarts:golden_rail_v2_on",{ "mcl_minecarts_ra
},
drop = "mcl_minecarts:golden_rail_v2",
})
register_rail("mcl_minecarts:golden_rail_on", {"mcl_minecarts_rail_golden_powered.png", "mcl_minecarts_rail_golden_curved_powered.png", "mcl_minecarts_rail_golden_t_junction_powered.png", "mcl_minecarts_rail_golden_crossing_powered.png"}, { }, false ) -- deprecated
-- Activator rail (off)
mod.register_straight_rail("mcl_minecarts:activator_rail_v2", {"mcl_minecarts_rail_activator.png"},{
@ -491,7 +460,6 @@ mod.register_straight_rail("mcl_minecarts:activator_rail_v2", {"mcl_minecarts_ra
}
},
})
register_rail("mcl_minecarts:activator_rail", {"mcl_minecarts_rail_activator.png", "mcl_minecarts_rail_activator_curved.png", "mcl_minecarts_rail_activator_t_junction.png", "mcl_minecarts_rail_activator_crossing.png"}, {} ) -- deprecated
-- Activator rail (on)
mod.register_straight_rail("mcl_minecarts:activator_rail_v2_on", {"mcl_minecarts_rail_activator_powered.png"},{
@ -528,7 +496,6 @@ mod.register_straight_rail("mcl_minecarts:activator_rail_v2_on", {"mcl_minecarts
end,
drop = "mcl_minecarts:activator_rail_v2",
})
register_rail("mcl_minecarts:activator_rail_on", {"mcl_minecarts_rail_activator_powered.png", "mcl_minecarts_rail_activator_curved_powered.png", "mcl_minecarts_rail_activator_t_junction_powered.png", "mcl_minecarts_rail_activator_crossing_powered.png"}, { }, false ) -- deprecated
-- Detector rail (off)
mod.register_straight_rail("mcl_minecarts:detector_rail_v2",{"mcl_minecarts_rail_detector.png"},{
@ -561,7 +528,6 @@ mod.register_straight_rail("mcl_minecarts:detector_rail_v2",{"mcl_minecarts_rail
}
}
})
register_rail("mcl_minecarts:detector_rail", {"mcl_minecarts_rail_detector.png", "mcl_minecarts_rail_detector_curved.png", "mcl_minecarts_rail_detector_t_junction.png", "mcl_minecarts_rail_detector_crossing.png"}, {} ) -- deprecated
-- Detector rail (on)
mod.register_straight_rail("mcl_minecarts:detector_rail_v2_on",{"mcl_minecarts_rail_detector_powered.png"},{
@ -587,7 +553,6 @@ mod.register_straight_rail("mcl_minecarts:detector_rail_v2_on",{"mcl_minecarts_r
end,
drop = "mcl_minecarts:detector_rail_v2",
})
register_rail("mcl_minecarts:detector_rail_on", {"mcl_minecarts_rail_detector_powered.png", "mcl_minecarts_rail_detector_curved_powered.png", "mcl_minecarts_rail_detector_t_junction_powered.png", "mcl_minecarts_rail_detector_crossing_powered.png"}, { }, false ) -- deprecated
-- Aliases
if minetest.get_modpath("doc") then