Compare commits

...

5 Commits

Author SHA1 Message Date
orwell96 4ba8822eb9
Current bugtracker 2020-10-26 15:42:20 +01:00
orwell96 a5942bdf46
REPO NO LONGER UPDATED
Moved to http://git.bananach.space/advtrains.git/
2018-06-14 17:48:32 +02:00
orwell96 8d8e8c1553
Write something into description.txt 2018-05-25 18:25:24 +02:00
orwell96 1feae7a1ea Add digiline interface and is_passive function to LuaATC 2018-04-25 17:14:03 +02:00
orwell96 8b576357ef Rework the privilege system completely
See privilege_guide.txt for information
2018-03-14 20:57:07 +01:00
15 changed files with 305 additions and 98 deletions

View File

@ -151,6 +151,7 @@ dofile(advtrains.modpath.."/trackplacer.lua")
dofile(advtrains.modpath.."/tracks.lua")
dofile(advtrains.modpath.."/atc.lua")
dofile(advtrains.modpath.."/wagons.lua")
dofile(advtrains.modpath.."/protection.lua")
dofile(advtrains.modpath.."/trackdb_legacy.lua")
dofile(advtrains.modpath.."/nodedb.lua")
@ -272,7 +273,7 @@ advtrains.avt_save = function(remove_players_from_wagons)
"last_pos", "last_pos_prev", "movedir", "velocity", "tarvelocity",
"trainparts", "savedpos_off_track_index_offset", "recently_collided_with_env",
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back"
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line"
})
--then invalidate
if train.index then

148
advtrains/protection.lua Normal file
View File

@ -0,0 +1,148 @@
-- advtrains
-- protection.lua: privileges and rail protection, and some helpers
-- Privileges to control TRAIN DRIVING/COUPLING
minetest.register_privilege("train_operator", {
description = "Without this privilege, a player can't do anything about trains, neither place or remove them nor drive or couple them (but he can build tracks if he has track_builder)",
give_to_singleplayer= true,
});
minetest.register_privilege("train_admin", {
description = "Player may drive, place or remove any trains from/to anywhere, regardless of owner, whitelist or protection",
give_to_singleplayer= true,
});
-- Privileges to control TRACK BUILDING
minetest.register_privilege("track_builder", {
description = "Player can place and/or dig rails not protected from him. If he also has protection_bypass, he can place/dig any rails",
give_to_singleplayer= true,
});
-- Privileges to control OPERATING TURNOUTS/SIGNALS
minetest.register_privilege("railway_operator", {
description = "Player can operate turnouts and signals not protected from him. If he also has protection_bypass, he can operate any turnouts/signals",
give_to_singleplayer= true,
});
-- there is a configuration option "allow_build_only_owner". If this is active, a player having track_builder can only build rails and operate signals/turnouts in an area explicitly belonging to him
-- (checked using a dummy player called "*dummy*" (which is not an allowed player name))
--[[
Protection/privilege concept:
Tracks:
Protected 1 node all around a rail and 4 nodes upward (maybe make this dynamically determined by the rail...)
if track_builder privilege:
if not protected from* player:
if allow_build_only_owner:
if unprotected:
deny
else:
allow
deny
Wagons in general:
Players can only place/destroy wagons if they have train_operator
Wagon driving controls:
The former seat_access tables are unnecessary, instead there is a whitelist for the driving stands
on player trying to access a driver stand:
if is owner or is on whitelist:
allow
else:
deny
Wagon coupling:
Derived from the privileges for driving stands. The whitelist is shared (and also settable on non-driverstand wagons)
for each of the two bordering wagons:
if is owner or is on whitelist:
allow
*"protected from" means the player is not allowed to do things, while "protected by" means that the player is (one of) the owner(s) of this area
]]--
local boo = minetest.settings:get_bool("advtrains_allow_build_to_owner")
local nocheck
-- Check if the node we are about to check is in the range of a track that is protected from a player
--WARN: true means here that the action is forbidden!
function advtrains.check_track_protection(pos, pname)
if nocheck or pname=="" then
return false
end
nocheck=true --prevent recursive calls, never check this again if we're already in
local r, vr = 1, 3
local nodes = minetest.find_nodes_in_area(
{x = pos.x - r, y = pos.y - vr, z = pos.z - r},
{x = pos.x + r, y = pos.y, z = pos.z + r},
{"group:advtrains_track"})
for _,npos in ipairs(nodes) do
if not minetest.check_player_privs(pname, {track_builder = true}) then
if boo and not minetest.is_protected(npos, pname) and minetest.is_protected(npos, "*dummy*") then
nocheck = false
return false
else
minetest.chat_send_player(pname, "You are not allowed to dig or place nodes near tracks (missing track_builder privilege)")
minetest.log("action", pname.." tried to dig/place nodes near the track at "..minetest.pos_to_string(npos).." but does not have track_builder")
nocheck = false
return true
end
end
if not minetest.check_player_privs(pname, {protection_bypass = true}) then
if minetest.is_protected(npos, pname) then
nocheck = false
minetest.record_protection_violation(pos, pname)
return true
end
end
end
nocheck=false
return false
end
local old_is_protected = minetest.is_protected
minetest.is_protected = function(pos, pname)
if advtrains.check_track_protection(pos, pname) then
return true
end
return old_is_protected(pos, pname)
end
--WARN: true means here that the action is allowed!
function advtrains.check_driving_couple_protection(pname, owner, whitelist)
if minetest.check_player_privs(pname, {train_admin = true}) then
return true
end
if not minetest.check_player_privs(pname, {train_operator = true}) then
return false
end
if not owner or owner == pname then
return true
end
if whitelist and string.find(" "..whitelist.." ", " "..pname.." ", nil, true) then
return true
end
return false
end
function advtrains.check_turnout_signal_protection(pos, pname)
nocheck=true
if not minetest.check_player_privs(pname, {railway_operator = true}) then
if boo and not minetest.is_protected(pos, pname) and minetest.is_protected(pos, "*dummy*") then
nocheck=false
return true
else
minetest.chat_send_player(pname, "You are not allowed to operate turnouts and signals (missing railway_operator privilege)")
minetest.log("action", pname.." tried to operate turnout/signal at "..minetest.pos_to_string(pos).." but does not have railway_operator")
nocheck=false
return false
end
end
if not minetest.check_player_privs(pname, {protection_bypass = true}) then
if minetest.is_protected(pos, pname) then
minetest.record_protection_violation(pos, pname)
nocheck=false
return false
end
end
nocheck=false
return true
end

View File

@ -10,3 +10,8 @@ advtrains_enable_debugging (Enable debugging) bool false
# Logs are saved in the world directory as advtrains.log
# This setting is useful for multiplayer servers
advtrains_enable_logging (Enable logging) bool false
# If this is active, any player can do the following things inside (and only inside) an area that is explicitly protected by him
# (checked using a dummy player called "*dummy*" (which is not an allowed player name)):
# - build tracks and near tracks without the track_builder privilege
# - operate turnouts and signals without the railway_operator privilege
advtrains_allow_build_to_owner (Allow building/operating to privilegeless area owner) bool false

View File

@ -41,7 +41,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
end
}},
on_rightclick=function(pos, node, player)
if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
advtrains.ndb.swap_node(pos, {name = "advtrains:retrosignal_"..f.as..rotation, param2 = node.param2}, true)
end
end,
@ -84,7 +84,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
end,
},
on_rightclick=function(pos, node, player)
if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
advtrains.ndb.swap_node(pos, {name = "advtrains:signal_"..f.as..rotation, param2 = node.param2}, true)
end
end,
@ -133,7 +133,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
end,
},
on_rightclick=function(pos, node, player)
if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
advtrains.ndb.swap_node(pos, {name = "advtrains:signal_wall_"..loc.."_"..f.as, param2 = node.param2}, true)
end
end,
@ -179,7 +179,7 @@ minetest.register_node("advtrains:across_off", {
end,
},
on_rightclick=function(pos, node, player)
if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
advtrains.ndb.swap_node(pos, {name = "advtrains:across_on", param2 = node.param2}, true)
end
end,
@ -220,7 +220,7 @@ minetest.register_node("advtrains:across_on", {
end,
},
on_rightclick=function(pos, node, player)
if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
advtrains.ndb.swap_node(pos, {name = "advtrains:across_off", param2 = node.param2}, true)
end
end,

View File

@ -269,6 +269,7 @@ function advtrains.register_tracks(tracktype, def, preset)
groups = {
attached_node=1,
advtrains_track=1,
["advtrains_track_"..tracktype]=1,
save_in_at_nodedb=1,
dig_immediate=2,
@ -309,7 +310,7 @@ function advtrains.register_tracks(tracktype, def, preset)
end
end
ndef.on_rightclick = function(pos, node, player)
if minetest.check_player_privs(player:get_player_name(), {train_operator=true}) then
if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
switchfunc(pos, node)
advtrains.log("Switch", player:get_player_name(), pos)
end

View File

@ -1,19 +1,5 @@
--atan2 counts angles clockwise, minetest does counterclockwise
minetest.register_privilege("train_place", {
description = "Player can place trains on tracks not owned by player",
give_to_singleplayer= false,
});
minetest.register_privilege("train_remove", {
description = "Player can remove trains not owned by player",
give_to_singleplayer= false,
});
minetest.register_privilege("train_operator", {
description = "Player may operate trains and switch signals. Given by default. Revoke to prevent players from griefing automated subway systems.",
give_to_singleplayer= true,
default= true,
});
local wagon={
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
--physical = true,
@ -161,7 +147,7 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct
if not puncher or not puncher:is_player() then
return
end
if self.owner and puncher:get_player_name()~=self.owner and (not minetest.check_player_privs(puncher, {train_remove = true })) then
if self.owner and puncher:get_player_name()~=self.owner and (not minetest.check_player_privs(puncher, {train_admin = true })) then
minetest.chat_send_player(puncher:get_player_name(), attrans("This wagon is owned by @1, you can't destroy it.", self.owner));
return
end
@ -250,8 +236,9 @@ function wagon:on_step(dtime)
--driver control
for seatno, seat in ipairs(self.seats) do
local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
local has_driverstand = self.seatp[seatno] and (minetest.check_player_privs(self.seatp[seatno], {train_operator=true}) or self.owner==self.seatp[seatno])
local pname=self.seatp[seatno]
local driver=pname and minetest.get_player_by_name(pname)
local has_driverstand = pname and advtrains.check_driving_couple_protection(pname, self.owner, self.whitelist)
if self.seat_groups then
has_driverstand = has_driverstand and (seat.driving_ctrl_access or self.seat_groups[seat.group].driving_ctrl_access)
else
@ -577,13 +564,6 @@ function wagon:on_rightclick(clicker)
if not clicker or not clicker:is_player() then
return
end
if clicker:get_player_control().aux1 then
--advtrains.dumppath(self:train().path)
--minetest.chat_send_all("at index "..(self:train().index or "nil"))
--advtrains.invert_train(self.train_id)
atprint(dump(self))
return
end
local pname=clicker:get_player_name()
local no=self:get_seatno(pname)
if no then
@ -598,7 +578,7 @@ function wagon:on_rightclick(clicker)
if self.has_inventory and self.get_inventory_formspec then
poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
end
if self.seat_groups[sgr].driving_ctrl_access and minetest.check_player_privs(pname, "train_operator") then
if self.seat_groups[sgr].driving_ctrl_access and advtrains.check_driving_couple_protection(pname, self.owner, self.whitelist) then
poss[#poss+1]={name=attrans("Bord Computer"), key="bordcom"}
end
if self.owner==pname then
@ -779,28 +759,15 @@ function wagon:show_get_on_form(pname)
minetest.show_formspec(pname, "advtrains_geton_"..self.unique_id, form)
end
function wagon:show_wagon_properties(pname)
local numsgr=0
if self.seat_groups then
numsgr=#self.seat_groups
end
if not self.seat_access then
self.seat_access={}
end
--[[
fields: seat access: empty: everyone
checkbox: lock couples
fields:
field: driving/couple whitelist
button: save
]]
local form="size[5,"..(numsgr*1.5+4).."]"
local at=0
if self.seat_groups then
for sgr,sgrdef in pairs(self.seat_groups) do
local text = attrans("Access to @1",sgrdef.name)
form=form.."field[0.5,"..(0.5+at*1.5)..";4,1;sgr_"..sgr..";"..text..";"..(self.seat_access[sgr] or "").."]"
at=at+1
end
end
form=form.."button_exit[0.5,"..(at*1.5)..";4,1;save;"..attrans("Save wagon properties").."]"
local form="size[5,5]"
form = form .. "field[0.5,1;4,1;whitelist;Allow these players to drive your wagon:;"..(self.whitelist or "").."]"
--seat groups access lists were here
form=form.."button_exit[0.5,3;4,1;save;"..attrans("Save wagon properties").."]"
minetest.show_formspec(pname, "advtrains_prop_"..self.unique_id, form)
end
@ -819,9 +786,9 @@ local function checkcouple(eid)
end
return le
end
local function checklock(pname, own1, own2)
return minetest.check_player_privs(pname, "train_remove") or
((not own1 or own1==pname) or (not own2 or own2==pname))
local function checklock(pname, own1, own2, wl1, wl2)
return advtrains.check_driving_couple_protection(pname, own1, wl1)
or advtrains.check_driving_couple_protection(pname, own2, wl2)
end
function wagon:show_bordcom(pname)
if not self:train() then return end
@ -834,7 +801,7 @@ function wagon:show_bordcom(pname)
if train.velocity==0 then
form=form.."label[0.5,4.5;Train overview /coupling control:]"
linhei=5
local pre_own, owns_any = nil, minetest.check_player_privs(pname, "train_remove")
local pre_own, pre_wl, owns_any = nil, nil, minetest.check_player_privs(pname, "train_admin")
for i, tpid in ipairs(train.trainparts) do
local ent = advtrains.wagon_save[tpid]
if ent then
@ -843,7 +810,7 @@ function wagon:show_bordcom(pname)
if i~=1 then
if not ent.dcpl_lock then
form = form .. "image_button["..(i-0.5)..","..(linhei+1)..";1,1;advtrains_discouple.png;dcpl_"..i..";]"
if checklock(pname, ent.owner, pre_own) then
if checklock(pname, ent.owner, pre_own, ent.whitelist, pre_wl) then
form = form .. "image_button["..(i-0.5)..","..(linhei+2)..";1,1;advtrains_cpl_unlock.png;dcpl_lck_"..i..";]"
end
else
@ -854,6 +821,7 @@ function wagon:show_bordcom(pname)
form = form .. "box["..(i-0.1)..","..(linhei-0.1)..";1,1;green]"
end
pre_own = ent.owner
pre_wl = ent.whitelist
owns_any = owns_any or (not ent.owner or ent.owner==pname)
end
end
@ -894,7 +862,7 @@ function wagon:show_bordcom(pname)
end
function wagon:handle_bordcom_fields(pname, formname, fields)
local seatno=self:get_seatno(pname)
if not seatno or not self.seat_groups[self.seats[seatno].group].driving_ctrl_access or not minetest.check_player_privs(pname, "train_operator") then
if not seatno or not self.seat_groups[self.seats[seatno].group].driving_ctrl_access or not advtrains.check_driving_couple_protection(pname, self.owner, self.whitelist) then
return
end
local train = self:train()
@ -925,7 +893,7 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
local ent = advtrains.wagon_save[tpid]
local pent = advtrains.wagon_save[train.trainparts[i-1]]
if ent and pent then
if checklock(pname, ent.owner, pent.owner) then
if checklock(pname, ent.owner, pent.owner, ent.whitelist, pent.whitelist) then
for _,wagon in pairs(minetest.luaentities) do
if wagon.is_wagon and wagon.initialized and wagon.unique_id==tpid then
wagon.dcpl_lock=true
@ -939,7 +907,7 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
local ent = advtrains.wagon_save[tpid]
local pent = advtrains.wagon_save[train.trainparts[i-1]]
if ent and pent then
if checklock(pname, ent.owner, pent.owner) then
if checklock(pname, ent.owner, pent.owner, ent.whitelist, pent.whitelist) then
for _,wagon in pairs(minetest.luaentities) do
if wagon.is_wagon and wagon.initialized and wagon.unique_id==tpid then
wagon.dcpl_lock=false
@ -962,11 +930,11 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
end
local function chkownsany()
local owns_any = minetest.check_player_privs(pname, "train_remove")
local owns_any = minetest.check_player_privs(pname, "train_admin")
for i, tpid in ipairs(train.trainparts) do
local ent = advtrains.wagon_save[tpid]
if ent then
owns_any = owns_any or (not ent.owner or ent.owner==pname)
owns_any = owns_any or advtrains.check_driving_couple_protection(pname, ent.owner, ent.whitelist)
end
end
return owns_any
@ -1031,14 +999,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
for _,wagon in pairs(minetest.luaentities) do
if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
local pname=player:get_player_name()
if pname~=wagon.owner then
if pname~=wagon.owner and not minetest.check_player_privs(pname, {train_admin = true}) then
return true
end
if fields.save or not fields.quit then
for sgr,sgrdef in pairs(wagon.seat_groups) do
if fields["sgr_"..sgr] then
local fcont = fields["sgr_"..sgr]
wagon.seat_access[sgr] = fcont~="" and fcont or nil
if fields.whitelist then
wagon.whitelist = fields.whitelist
end
end
end
@ -1073,7 +1040,7 @@ function wagon:seating_from_key_helper(pname, fields, no)
if fields.prop and self.owner==pname then
self:show_wagon_properties(pname)
end
if fields.bordcom and self.seat_groups[sgr].driving_ctrl_access and minetest.check_player_privs(pname, "train_operator") then
if fields.bordcom and self.seat_groups[sgr].driving_ctrl_access and advtrains.check_driving_couple_protection(pname, self.owner, self.whitelist) then
self:show_bordcom(pname)
end
if fields.dcwarn then
@ -1084,25 +1051,13 @@ function wagon:seating_from_key_helper(pname, fields, no)
end
end
function wagon:check_seat_group_access(pname, sgr)
if self.seat_groups[sgr].driving_ctrl_access and not (minetest.check_player_privs(pname, "train_operator") or self.owner==pname) then
return false, "Missing train_operator privilege."
if self.seat_groups[sgr].driving_ctrl_access and not (advtrains.check_driving_couple_protection(pname, self.owner, self.whitelist)) then
return false, "Not allowed to access a driver stand!"
end
if self.seat_groups[sgr].driving_ctrl_access then
advtrains.log("Drive", pname, self.object:getpos(), self:train().text_outside)
end
if not self.seat_access then
return true
end
local sae=self.seat_access[sgr]
if not sae or sae=="" then
return true
end
for name in string.gmatch(sae, "%S+") do
if name==pname then
return true
end
end
return false, "Blacklisted by owner."
return true
end
function wagon:reattach_all()
if not self.seatp then self.seatp={} end
@ -1158,9 +1113,12 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img)
atprint("no track here, not placing.")
return itemstack
end
if not minetest.check_player_privs(placer, {train_place = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
minetest.record_protection_violation(pointed_thing.under, placer:get_player_name())
return
if not minetest.check_player_privs(placer, {train_operator = true }) then
minetest.chat_send_player(placer:get_player_name(), "You don't have the train_operator privilege.")
return itemstack
end
if not minetest.check_player_privs(placer, {train_admin = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
return itemstack
end
local tconns=advtrains.get_track_connections(node.name, node.param2)
local yaw = placer:get_look_horizontal() + (math.pi/2)
@ -1191,9 +1149,4 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img)
})
end
--[[
wagons can define update_animation(self, velocity) if they have a speed-dependent animation
this function will be called when the velocity vector changes or every 2 seconds.
]]

View File

@ -63,6 +63,10 @@ setstate(pos, newstate)
Set the state of the passive component at position 'pos'.
pos can be either a position vector (created by POS()) or a string, the name of this passive component.
is_passive(pos)
Checks whether there is a passive component at the position pos (and/or whether a passive component with this name exists)
pos can be either a position vector (created by POS()) or a string, the name of this passive component.
interrupt(time, message)
Cause LuaAutomation to trigger an 'int' event on this component after the given time in seconds with the specified 'message' field. 'message' can be of any Lua data type.
Not available in init code!
@ -71,6 +75,10 @@ interrupt_pos(pos, message)
Immediately trigger an 'ext_int' event on the active component at position pos. 'message' is like in interrupt().
USE WITH CARE, or better don't use! Incorrect use can result in expotential growth of interrupts.
digiline_send(channel, message)
Make this active component send a digiline message on the specified channel.
Not available in init code!
## Components and events
The event table is a table of the following format:
@ -110,6 +118,9 @@ Fired when an interrupt set by the 'interrupt' function runs out. 'message' is t
{type="ext_int", ext_int=true, message=<message>}
Fired when another node called 'interrupt_pos' on this position. 'message' is the message passed to the interrupt_pos function.
{type="digiline", digiline=true, channel=<channel>, msg=<message>}
Fired when the controller receives a digiline message.
In addition to the default environment functions, the following functions are available:
atc_send(<atc_command>)
@ -132,7 +143,7 @@ set_line(number)
# Operator panel
This simple node executes its actions when punched. It can be used to change a switch and update the corresponding signals or similar applications.
The event fired is {type="punch", punch=true} by default. In case of an interrupt, the events are similar to the ones of the ATC rail.
The event fired is {type="punch", punch=true} by default. In case of an interrupt or a digiline message, the events are similar to the ones of the ATC rail.
### Passive components

View File

@ -111,9 +111,19 @@ function ac.run_in_env(pos, evtdata, customfct_p)
end
local customfct=customfct_p or {}
-- add interrupt function
customfct.interrupt=function(t, imesg)
assertt(t, "number")
assert(t >= 0)
atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg})
end
-- add digiline_send function, if digiline is loaded
if digiline then
customfct.digiline_send=function(channel, msg)
assertt(channel, "string")
digiline:receptor_send(pos, digiline.rules.default, channel, msg)
end
end
local datain=nodetbl.data or {}
local succ, dataout = atlatc.envs[nodetbl.env]:execute_code(datain, nodetbl.code, evtdata, customfct)
@ -131,4 +141,8 @@ function ac.run_in_env(pos, evtdata, customfct_p)
end
end
function ac.on_digiline_receive(pos, node, channel, msg)
atlatc.interrupt.add(0, pos, {type="digiline", digiline=true, channel = channel, msg = msg})
end
atlatc.active=ac

View File

@ -119,9 +119,15 @@ advtrains.register_tracks("default", {
},
luaautomation = {
fire_event=r.fire_event
}
},
digiline = {
receptor = {},
effector = {
action = atlatc.active.on_digiline_receive
},
},
}
end
end,
}, advtrains.trackpresets.t_30deg_straightonly)

View File

@ -86,7 +86,7 @@ local function safe_string_find(...)
end
local mp=minetest.get_modpath("advtrains_luaautomation")
local p_api_getstate, p_api_setstate = dofile(mp.."/passive.lua")
local p_api_getstate, p_api_setstate, p_api_is_passive = dofile(mp.."/passive.lua")
local static_env = {
--core LUA functions
@ -150,7 +150,8 @@ local static_env = {
POS = function(x,y,z) return {x=x, y=y, z=z} end,
getstate = p_api_getstate,
setstate = p_api_setstate,
--interrupts are handled per node, position unknown.
is_passive = p_api_is_passive,
--interrupts are handled per node, position unknown. (same goes for digilines)
--however external interrupts can be set here.
interrupt_pos = function(pos, imesg)
if not type(pos)=="table" or not pos.x or not pos.y or not pos.z then

View File

@ -18,6 +18,11 @@ minetest.register_node("advtrains_luaautomation:oppanel", {
on_punch = on_punch,
luaautomation = {
fire_event=atlatc.active.run_in_env
}
},
digiline = {
receptor = {},
effector = {
action = atlatc.active.on_digiline_receive
},
},
})

View File

@ -34,6 +34,19 @@ local function setstate(parpos, newstate)
end
end
local function is_passive(parpos)
local pos=atlatc.pcnaming.resolve_pos(parpos)
if type(pos)~="table" or (not pos.x or not pos.y or not pos.z) then
return false
end
local node=advtrains.ndb.get_node(pos)
local ndef=minetest.registered_nodes[node.name]
if ndef and ndef.luaautomation and ndef.luaautomation.getstate then
return true
end
return false
end
-- gets called from environment.lua
-- return the values here to keep them local
return getstate, setstate
return getstate, setstate, is_passive

View File

@ -1 +1,2 @@
advtrains 1.3.8
This modpack adds realistic, good-looking trains and a rail system based on 30-degree turns.
It also provides means to automate train operation.

33
privilege_guide.txt Normal file
View File

@ -0,0 +1,33 @@
### Advtrains Privilege Guide
All privileges are automatically granted to singleplayer, but for
multiplayer servers this might be interesting.
There are 3 groups of privileges introduced by advtrains:
## Trains
For a player to build his own trains and driving them, the player needs
the 'train_operator' privilege. This privilege no longer allows him to
control any train, only the ones that he owns or that he is whitelisted on.
The owner of a wagon can write a whitelist which players are allowed to
operate his wagon using the wagon properties dialog.
Players having the 'train_admin' privilege can always drive, build and
destroy any train.
## Tracks*
The area 1 node around and 4 nodes up from each track node is protected.
Players that don't have the 'track_builder' privilege can not build or
dig (or modify) anything inside this area.
If any player tries to modify anything that is in the area of a track
node and this track node is protected from him, he also can not do this.
(that said, while checking protection, the area around a track is
treated as the track node itself)
## Turnouts and Signals*
Players without the 'railway_operator' privilege can not operate signals
and turnouts.
* If the configuration option 'advtrains_allow_build_to_owner' is set,
an exception applies to players missing the required privileges when
they are in a protected area that they have access to. Whether the
area is protected from others is checked by checking for protection
against a dummy player called '*dummy*'

View File

@ -1,4 +1,19 @@
THIS REPOSITORY IS NO LONGER UPDATED!
=====================================
The new repository for this mod can be found at:
http://git.bananach.space/advtrains.git/
Please report issues to:
https://bugs.linux-forks.de/advtrains/ (no registration required)
This repository will continue to mirror the state of advtrains as it was on 2018/06/14.
Issues and PRs reported here will probably no longer be processed.
================
Original readme:
## ADVTRAINS ## realistic trains in Minetest!
by orwell96 and contributors(see below)