Add speed limit signs

master
Joachim Stolberg 2021-04-06 22:56:26 +02:00
parent 4a7ab2c917
commit 0466346a6e
14 changed files with 248 additions and 104 deletions

View File

@ -117,6 +117,7 @@ function minecart.is_owner(player, owner)
if not player or not player:is_player() or not owner or owner == "" then
return true
end
local name = player:get_player_name()
if minetest.check_player_privs(name, "minecart") then
return true
@ -145,7 +146,7 @@ function minecart.get_buffer_name(pos)
end
end
function minecart.manage_attachment(player, obj, get_on)
function minecart.manage_attachment(player, entity, get_on)
if not player then
return
end
@ -155,19 +156,19 @@ function minecart.manage_attachment(player, obj, get_on)
end
player_api.player_attached[player_name] = get_on
local self = obj:get_luaentity()
local obj = entity.object
if get_on then
player:set_attach(obj, "", {x=0, y=-4.5, z=-4}, {x=0, y=0, z=0})
player:set_eye_offset({x=0, y=-6, z=0},{x=0, y=-6, z=0})
player:set_properties({visual_size = {x = 2.5, y = 2.5}})
player_api.set_animation(player, "sit")
self.driver = player:get_player_name()
entity.driver = player:get_player_name()
else
player:set_detach()
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
player:set_properties({visual_size = {x = 1, y = 1}})
player_api.set_animation(player, "stand")
self.driver = nil
entity.driver = nil
end
end
@ -175,27 +176,63 @@ function minecart.register_cart_names(node_name, entity_name)
minecart.tNodeNames[node_name] = entity_name
minecart.tEntityNames[entity_name] = true
minecart.lCartNodeNames[#minecart.lCartNodeNames+1] = node_name
minecart.add_raillike_nodes(node_name)
end
function minecart.add_nodecart(pos, node_name, param2, cargo, owner, userID)
if pos and node_name and param2 and cargo and owner and userID then
local ndef = minetest.registered_nodes[node_name]
local node = minetest.get_node(pos)
local rail = node.name
minetest.swap_node(pos, {name = node_name, param2 = param2})
local meta = M(pos)
meta:set_string("removed_rail", rail)
meta:set_string("owner", owner)
meta:set_string("userID", userID)
meta:set_string("infotext",
minetest.get_color_escape_sequence("#FFFF00") .. owner .. ": " .. userID)
local pos2
if not minecart.is_rail(pos) then
pos2 = minetest.find_node_near(pos, 1, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, minecart.lRails)
if not pos2 or not minecart.is_rail(pos2) then
pos2 = minetest.find_node_near(pos, 2, {"air"})
end
end
else
pos2 = vector.new(pos)
end
if pos2 then
local node = minetest.get_node(pos2)
local ndef = minetest.registered_nodes[node_name]
local rail = node.name
minetest.swap_node(pos2, {name = node_name, param2 = param2})
local meta = M(pos2)
meta:set_string("removed_rail", rail)
meta:set_string("owner", owner)
meta:set_string("userID", userID)
meta:set_string("infotext",
minetest.get_color_escape_sequence("#FFFF00") .. owner .. ": " .. userID)
if cargo and ndef.set_cargo then
ndef.set_cargo(pos2, cargo)
end
if ndef.after_place_node then
ndef.after_place_node(pos2)
end
else
minetest.add_item(pos, ItemStack({name = node_name}))
end
end
end
function minecart.add_entitycart(pos, node_name, entity_name, vel, cargo, owner, userID)
local obj = minetest.add_entity(pos, entity_name)
local objID = minecart.get_object_id(obj)
if objID then
local entity = obj:get_luaentity()
entity.start_pos = pos
entity.owner = owner
entity.node_name = node_name
entity.userID = userID
entity.cargo = cargo
obj:set_nametag_attributes({color = "#ffff00", text = owner..": "..userID})
obj:set_velocity(vel)
if cargo and ndef.set_cargo then
ndef.set_cargo(pos, cargo)
end
if ndef.after_place_node then
ndef.after_place_node(pos)
end
minecart.start_monitoring(owner, userID, objID, pos, node_name, entity_name, cargo)
return objID, obj
end
end
@ -216,20 +253,9 @@ end
function minecart.node_to_entity(pos, node_name, entity_name)
-- Remove node
local cargo, owner, userID = minecart.remove_nodecart(pos)
-- Add entity
local obj = minetest.add_entity(pos, entity_name)
local objID = minecart.get_object_id(obj)
local objID, obj = minecart.add_entitycart(pos, node_name,
entity_name, {x = 0, y = 0, z = 0}, cargo, owner, userID)
if objID then
local entity = obj:get_luaentity()
entity.owner = owner
entity.node_name = node_name
entity.userID = userID
entity.cargo = cargo
obj:set_nametag_attributes({color = "#ffff00", text = owner..": "..userID})
minecart.start_monitoring(owner, userID, objID, pos, node_name, entity_name, cargo)
return objID, obj
else
print("Entity has no ID")
@ -277,3 +303,7 @@ function minecart.remove_entity(self, pos, player)
minecart.stop_recording(self, pos)
self.object:remove()
end
function minecart.back_to_start(self)
minecart.add_nodecart(self.start_pos, self.node_name, 0, self.cargo, self.owner, self.userID)
end

View File

@ -33,13 +33,7 @@ local function stop_cart(self)
minecart.manage_attachment(player, self, false)
end
end
-- ich muss hier prüfen, ob da nicht schon ein Cart steht!!!
-- buffer reached
if minecart.get_buffer_pos(pos, self.driver) then
minecart.entity_to_node(pos, self)
else
minecart.entity_to_node(pos, self)
end
minecart.entity_to_node(pos, self)
end
local function running(self)
@ -52,12 +46,12 @@ local function running(self)
if self.reenter then -- through monitoring
cart_pos = H2P(self.reenter[1])
cart_speed = self.reenter[3]
self.waypoint = {pos = H2P(self.reenter[2]), power = 0, dot = self.reenter[4]}
self.waypoint = {pos = H2P(self.reenter[2]), power = 0, limit = MAX_SPEED, dot = self.reenter[4]}
self.reenter = nil
elseif not self.waypoint then
-- get waypoint
cart_pos = self.object:get_pos()
cart_speed = 0
cart_speed = 2
self.waypoint = get_waypoint(cart_pos, facedir, {}, true)
else
-- next waypoint
@ -75,10 +69,15 @@ local function running(self)
-- Calc speed
local rail_power = self.waypoint.power / 100
local speed_limit = self.waypoint.limit / 100
print("speed", rail_power, speed_limit)
if rail_power <= 0 then
new_speed = math.max(cart_speed + rail_power, 0)
new_speed = math.min(new_speed, speed_limit)
elseif rail_power < cart_speed then
new_speed = math.min((cart_speed + rail_power) / 2, speed_limit)
else
new_speed = math.min(rail_power, MAX_SPEED)
new_speed = math.min(rail_power, speed_limit)
end
-- Speed corrections
local new_dir = Dot2Dir[self.waypoint.dot]
@ -123,7 +122,7 @@ local function play_sound(self)
self.sound_handle = minetest.sound_play(
"carts_cart_moving", {
object = self.object,
loop = true,
gain = self.speed / MAX_SPEED,
})
end
@ -135,7 +134,6 @@ local function on_step(self, dtime)
running(self)
end
self.sound_ttl = (self.sound_ttl or 0) + dtime
if (self.sound_ttl or 0) <= self.timebase then
play_sound(self)
self.sound_ttl = self.timebase + 1.0
@ -190,7 +188,7 @@ local function on_entitycard_rightclick(self, clicker)
minecart.manage_attachment(clicker, self, false)
else
-- get on
minecart.manage_attachment(clicker, self.object, true)
minecart.manage_attachment(clicker, self, true)
end
end
end

View File

@ -12,9 +12,6 @@
local NUM_ITEMS = 4
-- Test for MT 5.4 new string mode
local CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true
-- for lazy programmers
local M = minetest.get_meta
local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end
@ -158,7 +155,7 @@ minetest.register_node("minecart:hopper", {
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
use_texture_alpha = CLIP,
use_texture_alpha = minecart.CLIP,
groups = {choppy=2, cracky=2, crumbly=2},
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),

View File

@ -17,6 +17,9 @@ minecart.version = 2.00
minecart.hopper_enabled = minetest.settings:get_bool("minecart_hopper_enabled") ~= false
minecart.teleport_enabled = minetest.settings:get_bool("minecart_teleport_enabled") == true
-- Test for MT 5.4 new string mode
minecart.CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true
minecart.S = minetest.get_translator("minecart")
local MP = minetest.get_modpath("minecart")
@ -33,6 +36,7 @@ dofile(MP .. "/minecart.lua")
dofile(MP .. "/buffer.lua")
dofile(MP .. "/protection.lua")
dofile(MP .. "/tool.lua")
dofile(MP .. "/signs.lua")
if minecart.hopper_enabled then
dofile(MP .. "/hopper.lua")

View File

@ -56,7 +56,7 @@ minetest.register_node("minecart:cart_node", {
if clicker and clicker:is_player() then
-- enter the cart
local _, object = minecart.node_to_entity(pos, "minecart:cart_node", "minecart:cart")
minecart.manage_attachment(clicker, object, true)
minecart.manage_attachment(clicker, object:get_luaentity(), true)
end
end,

View File

@ -494,20 +494,24 @@ local function monitoring(cycle)
while cart and cart.objID do
local entity = minetest.luaentities[cart.objID]
if entity then -- cart entity running
local pos = vector.round(entity.object:get_pos())
print("monitoring", cycle, P2S(pos))
cart.last_pos = vector.round(entity.object:get_pos())
--print("monitoring", cycle, cart.userID, P2S(cart.pos))
push(cycle, cart)
else
local pos = cart.last_pos or cart.start_pos
minecart.add_nodecart(pos, cart.node_name, 0, cart.cargo, cart.owner, cart.userID)
print("cart to node", cycle, cart.userID, P2S(pos))
end
push(cycle, cart)
cart = pop(cycle)
end
minetest.after(2, monitoring, cycle + 1)
end
--minetest.after(2, monitoring, 1)
minetest.after(2, monitoring, 1)
function minecart.start_monitoring(owner, userID, objID, pos, node_name, entity_name, cargo)
print("start_monitoring", owner, userID)
--print("start_monitoring", owner, userID)
tRunningCarts[owner] = tRunningCarts[owner] or {}
tRunningCarts[owner][userID] = {
owner = owner,

View File

@ -27,7 +27,8 @@ end
-- Convert node to entity and start cart
function minecart.start_nodecart(pos, node_name, puncher)
local owner = M(pos):get_string("owner")
if minecart.is_owner(puncher, owner) then
-- Only the owner or a noplayer can start the cart, but owner has to be online
if minecart.is_owner(puncher, owner) and minetest.get_player_by_name(owner) then
local entity_name = minecart.tNodeNames[node_name]
local objID, obj = minecart.node_to_entity(pos, node_name, entity_name)
if objID then
@ -72,21 +73,16 @@ function minecart.on_nodecart_place(itemstack, placer, pointed_thing)
return itemstack
end
-- UStart the node cart (or dig by shift+leftclick)
-- Start the node cart (or dig by shift+leftclick)
function minecart.on_nodecart_punch(pos, node, puncher, pointed_thing)
local owner = M(pos):get_string("owner")
print(1)
if minecart.is_owner(puncher, owner) then
print(2)
if puncher:get_player_control().sneak then
print(3)
local ndef = minetest.registered_nodes[node.name]
if not ndef.can_dig or ndef.can_dig(pos, puncher) then
print(4)
minecart.remove_nodecart(pos)
end
else
print(5)
minecart.start_nodecart(pos, node.name, puncher)
end
end

115
rails.lua
View File

@ -20,23 +20,44 @@ local get_node_lvm = minecart.get_node_lvm
local SLOPE_ACCELERATION = 1
local MAX_SPEED = 8
local SLOWDOWN = 0.4
local MAX_NODES = 100
--waypoint = {
-- dot = travel direction,
-- pos = destination pos,
-- power = 10 times the waypoint speed (as int),
-- cart_pos = destination cart pos
-- power = 100 times the waypoint speed (as int),
-- limit = 100 times the speed limit (as int),
--}
--
-- waypoints = {facedir = waypoint,...}
local tWaypoints = {} -- {pos_hash = waypoints, ...}
-- Real rails from the mod carts
local tRails = {
["carts:rail"] = true,
["carts:powerrail"] = true,
["carts:brakerail"] = true,
}
-- Rails plus node carts used to find waypoints, added via add_raillike_nodes
local tRailsExt = {
["carts:rail"] = true,
["carts:powerrail"] = true,
["carts:brakerail"] = true,
}
local tSigns = {
["minecart:speed1"] = 1,
["minecart:speed2"] = 2,
["minecart:speed4"] = 4,
}
local lSigns = {"minecart:speed1", "minecart:speed2", "minecart:speed4"}
-- Real rails from the mod carts
local lRails = {"carts:rail", "carts:powerrail", "carts:brakerail"}
-- Rails plus node carts used to find waypoints, , added via add_raillike_nodes
local lRailsExt = {"carts:rail", "carts:powerrail", "carts:brakerail"}
local Dot2Dir = {}
local Dir2Dot = {}
@ -73,12 +94,12 @@ local function check_front_up_down(pos, facedir, test_for_slope)
local npos
npos = vector.add(pos, Facedir2Dir[facedir])
if tRails[get_node_lvm(npos).name] then
if tRailsExt[get_node_lvm(npos).name] then
-- We also have to check the next node to find the next upgoing rail.
if test_for_slope then
npos = vector.add(npos, Facedir2Dir[facedir])
npos.y = npos.y + 1
if tRails[get_node_lvm(npos).name] then
if tRailsExt[get_node_lvm(npos).name] then
--print("check_front_up_down: 2up")
return facedir * 3 + 3 -- up
end
@ -88,13 +109,13 @@ local function check_front_up_down(pos, facedir, test_for_slope)
end
npos.y = npos.y - 1
if tRails[get_node_lvm(npos).name] then
if tRailsExt[get_node_lvm(npos).name] then
--print("check_front_up_down: down")
return facedir * 3 + 1 -- down
end
npos.y = npos.y + 2
if tRails[get_node_lvm(npos).name] then
if tRailsExt[get_node_lvm(npos).name] then
--print("check_front_up_down: up")
return facedir * 3 + 3 -- up
end
@ -128,7 +149,7 @@ local function delete_rail_metadata(pos, nearby)
if nearby then
local pos1 = {x = pos.x - 1, y = pos.y, z = pos.z - 1}
local pos2 = {x = pos.x + 1, y = pos.y, z = pos.z + 1}
for _, npos in ipairs(minetest.find_nodes_in_area_under_air(pos1, pos2, lRails)) do
for _, npos in ipairs(minetest.find_nodes_in_area_under_air(pos1, pos2, lRailsExt)) do
delete(npos)
end
else
@ -147,17 +168,28 @@ local function get_rail_power(pos, dot)
return (carts.railparams[node.name] or {}).acceleration or 0
end
local function check_speed_limit(dot, pos)
local facedir = math.floor((dot - 1) / 3)
facedir = (facedir + 1) % 4 -- turn right
local npos = vector.add(pos, Facedir2Dir[facedir])
local node = get_node_lvm(npos)
return tSigns[node.name] or MAX_SPEED
end
local function find_next_waypoint(pos, dot)
print("find_next_waypoint", P2S(pos), dot)
--print("find_next_waypoint", P2S(pos), dot)
local npos = vector.new(pos)
local facedir = math.floor((dot - 1) / 3)
local y = ((dot - 1) % 3) - 1
local power = 0
local cnt = 0
while cnt < 1000 do
while cnt < MAX_NODES do
npos = vector.add(npos, Dot2Dir[dot])
power = power + get_rail_power(npos, dot)
local dots = find_rails_nearby(npos, facedir, true)
-- check for speed sign as end of the section
local speed = check_speed_limit(dot, npos)
if #dots == 0 then -- end of rail
return npos, power
@ -172,23 +204,26 @@ local function find_next_waypoint(pos, dot)
return npos, power
end
return npos, power
elseif speed < 8 then -- sign detected
print("check_speed_limit", speed)
return npos, power
end
cnt = cnt + 1
end
return pos, 0
return npos, power
end
local function find_next_meta(pos, facedir)
print("find_next_meta", P2S(pos), facedir)
--print("find_next_meta", P2S(pos), facedir)
local npos = vector.new(pos)
local cnt = 0
local old_dot
while cnt < 1000 do
local dot = check_front_up_down(pos, facedir)
while cnt <= MAX_NODES do
local dot = check_front_up_down(npos, facedir)
old_dot = old_dot or dot
if dot and dot == old_dot then
npos = vector.add(npos, Dot2Dir[dot])
print("find_next_meta", P2S(npos), facedir, M(npos):contains("waypoints"))
if M(npos):contains("waypoints") then
return npos
end
@ -197,6 +232,7 @@ local function find_next_meta(pos, facedir)
end
cnt = cnt + 1
end
return npos
end
-- Search for rails in all 4 directions
@ -250,39 +286,23 @@ local function is_waypoint(dots)
return false
end
--local function is_slope(pos)
-- -- Use invalid facedir to be able to test all 4 directions
-- local dots = find_rails_nearby(pos, 4)
-- if #dots > 2 then
-- return
-- elseif #dots == 2 then
-- local y1 = ((dots[1] - 1) % 3) - 1
-- local y2 = ((dots[2] - 1) % 3) - 1
-- if y1 ~= y2 then return dots end
-- else -- 1
-- local y = ((dots[1] - 1) % 3) - 1
-- if y ~= 0 then return dots end
-- end
-- return
--end
local function determine_waypoints(pos)
--print("determine_waypoints")
local t = minetest.get_us_time()
local waypoints = {}
local dots = {}
for _,dot in ipairs(find_all_rails_nearby(pos, 0)) do
local npos, power = find_next_waypoint(pos, dot)
local facedir = math.floor((dot - 1) / 3)
power = math.floor(recalc_power(dot, power, pos, npos) * 100)
waypoints[facedir] = {dot = dot, pos = npos, power = power}
-- check for speed limit
local limit = check_speed_limit(dot, pos) * 100
local facedir = math.floor((dot - 1) / 3)
waypoints[facedir] = {dot = dot, pos = npos, power = power, limit = limit}
dots[#dots + 1] = dot
end
if is_waypoint(dots) then
--if is_waypoint(dots) then
M(pos):set_string("waypoints", minetest.serialize(waypoints))
end
t = minetest.get_us_time() - t
print("time = ", t)
minecart.set_marker(pos, "add")
--end
return waypoints
end
@ -344,19 +364,36 @@ end
minecart.MAX_SPEED = MAX_SPEED
minecart.Dot2Dir = Dot2Dir
minecart.Dir2Dot = Dir2Dot
--minecart.find_next_waypoint = find_next_waypoint
minecart.get_waypoint = get_waypoint
minecart.lRails = lRails
-- used by speed limit signs
function minecart.delete_waypoints(pos)
local pos1 = {x = pos.x - 1, y = pos.y, z = pos.z - 1}
local pos2 = {x = pos.x + 1, y = pos.y, z = pos.z + 1}
local posses = minetest.find_nodes_in_area(pos1, pos2, lRailsExt)
for _, pos in ipairs(posses) do
print("delete_waypoints", P2S(pos))
delete_waypoints(pos)
end
end
function minecart.is_rail(pos)
return tRails[get_node_lvm(pos).name] ~= nil
end
function minecart.add_raillike_nodes(name)
tRailsExt[name] = true
lRailsExt[#lRailsExt + 1] = name
end
minetest.register_lbm({
label = "Delete waypoints",
name = "minecart:rails",
nodenames = lRails,
nodenames = lRailsExt,
run_at_every_load = true,
action = function(pos, node)
M(pos):set_string("waypoints", "")
end,
})

View File

@ -83,7 +83,7 @@ function minecart.stop_recording(self, pos)
local dest_pos = minecart.get_buffer_pos(pos, self.driver)
local player = minetest.get_player_by_name(self.driver)
if dest_pos and player then
if self.start_pos and vector.equals(self.start_pos, dest_pos) then
if self.start_pos then
local route = {
dest_pos = dest_pos,
waypoints = self.waypoints,

79
signs.lua Normal file
View File

@ -0,0 +1,79 @@
--[[
Minecart
========
Copyright (C) 2019-2021 Joachim Stolberg 4
MIT
See license.txt for more information
]]--
local S = minecart.S
local function register_sign(def)
minetest.register_node("minecart:"..def.name, {
description = def.description,
inventory_image = def.image,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -1/16, -8/16, -1/16, 1/16, 4/16, 1/16},
{ -5/16, -2/16, -2/16, 5/16, 8/16, -1/16},
},
},
paramtype2 = "facedir",
tiles = {
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png",
"default_steel_block.png^"..def.image,
},
after_place_node = function(pos)
minecart.delete_waypoints(pos)
end,
after_dig_node = function(pos)
minecart.delete_waypoints(pos)
end,
on_rotate = screwdriver.disallow,
paramtype = "light",
use_texture_alpha = minecart.CLIP,
sunlight_propagates = true,
is_ground_content = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 2, minecart_sign = 1},
sounds = default.node_sound_wood_defaults(),
})
end
register_sign({
name = "speed1",
description = S('Speed "1"'),
image = "minecart_sign1.png",
})
register_sign({
name = "speed2",
description = S('Speed "2"'),
image = "minecart_sign2.png",
})
register_sign({
name = "speed4",
description = S('Speed "4"'),
image = "minecart_sign4.png",
})
--minetest.register_craft({
-- output = "signs_bot:sign_right 6",
-- recipe = {
-- {"group:wood", "default:stick", "group:wood"},
-- {"dye:yellow", "default:stick", "dye:black"},
-- {"", "", ""}
-- }
--})

BIN
textures/minecart_sign1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
textures/minecart_sign2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
textures/minecart_sign4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -35,7 +35,6 @@ local function test_get_route(pos, node, player, ctrl)
print("test_get_route", string.format("dist = %u, dot = %u, power = %d",
vector.distance(pos, route.pos), route.dot, route.power))
minecart.set_marker(route.pos, "pos")
minecart.set_marker(route.cart_pos, "cart")
end
end