Initial dispatcher work (not yet functional)
This commit is contained in:
parent
52821fcc17
commit
c3d04606a3
@ -528,6 +528,17 @@ function celevator.controller.finish(pos,mem,changedinterrupts)
|
||||
if (mem.copformspec ~= oldmem.copformspec or mem.switchformspec ~= oldmem.switchformspec) and drivetype then
|
||||
minetest.after(0.25,celevator.drives[drivetype].updatecopformspec,drivepos)
|
||||
end
|
||||
for _,message in ipairs(mem.messages) do
|
||||
local destinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",message.carid)))
|
||||
if destinfo and destinfo.dispatcherpos then
|
||||
celevator.dispatcher.run(destinfo.dispatcherpos,{
|
||||
type = "controllermsg",
|
||||
source = mem.carid,
|
||||
channel = message.channel,
|
||||
msg = message.message,
|
||||
})
|
||||
end
|
||||
end
|
||||
meta:set_string("mem",minetest.serialize(mem))
|
||||
if node.name == "celevator:controller_open" then meta:set_string("formspec",mem.formspec or "") end
|
||||
meta:set_string("formspec_hidden",mem.formspec or "")
|
||||
|
@ -2,6 +2,16 @@ local pos,event,mem = ...
|
||||
|
||||
local changedinterrupts = {}
|
||||
|
||||
mem.messages = {}
|
||||
|
||||
local function send(carid,channel,message)
|
||||
table.insert(mem.messages,{
|
||||
carid = carid,
|
||||
channel = channel,
|
||||
message = message,
|
||||
})
|
||||
end
|
||||
|
||||
local function fault(ftype,fatal)
|
||||
if fatal then mem.fatalfault = true end
|
||||
if not mem.activefaults then mem.activefaults = {} end
|
||||
@ -527,6 +537,31 @@ elseif event.type == "cartopbox" then
|
||||
pos = math.floor(mem.drive.status.apos)-1
|
||||
})
|
||||
end
|
||||
elseif event.type == "dispatchermsg" then
|
||||
if event.channel == "pairrequest" and mem.screenstate == "oobe_dispatcherconnect" then
|
||||
mem.params.floornames = event.msg.floornames
|
||||
mem.params.floorheights = event.msg.floorheights
|
||||
mem.activefaults = {}
|
||||
mem.faultlog = {}
|
||||
mem.fatalfault = false
|
||||
mem.state = "configured"
|
||||
mem.screenstate = "status"
|
||||
mem.screenpage = 1
|
||||
mem.carstate = "bfdemand"
|
||||
if mem.doorstate == "closed" then
|
||||
drivecmd({
|
||||
command = "setmaxvel",
|
||||
maxvel = mem.params.contractspeed,
|
||||
})
|
||||
drivecmd({command = "resetpos"})
|
||||
interrupt(0.1,"checkdrive")
|
||||
mem.carmotion = true
|
||||
juststarted = true
|
||||
else
|
||||
close()
|
||||
end
|
||||
send(event.source,"pairok",mem)
|
||||
end
|
||||
end
|
||||
|
||||
local oldstate = mem.carstate
|
||||
@ -787,10 +822,11 @@ elseif mem.screenstate == "oobe_groupmode" then
|
||||
fs("button[1,3;2,1;simplex;Simplex]")
|
||||
fs("label[1,4.5;This will be the only elevator in the group. Hall calls will be handled by this controller.]")
|
||||
fs("button[1,6;2,1;group;Group]")
|
||||
fs("label[1,7.5;This elevator will participate in a group with others. Hall calls will be handled by a dispatcher. (not implemented)]")
|
||||
fs("label[1,7.5;This elevator will participate in a group with others. Hall calls will be handled by a dispatcher.]")
|
||||
elseif mem.screenstate == "oobe_dispatcherconnect" then
|
||||
fs("button[1,10;2,1;back;< Back]")
|
||||
fs("label[1,1;Not yet implemented. Press Back.]")
|
||||
fs("button[1,10;2,1;back;< Cancel]")
|
||||
fs("label[1,1;Waiting for connection from dispatcher...]")
|
||||
fs(string.format("label[1,1.5;This controller's car ID is: %d]",mem.carid))
|
||||
elseif mem.screenstate == "oobe_floortable" or mem.screenstate == "floortable" then
|
||||
if mem.screenstate == "oobe_floortable" then
|
||||
fs("label[1,1;Enter details of all floors this elevator will serve, then press Done.]")
|
||||
|
436
dispatcher.lua
Normal file
436
dispatcher.lua
Normal file
@ -0,0 +1,436 @@
|
||||
celevator.dispatcher = {}
|
||||
|
||||
celevator.dispatcher.iqueue = minetest.deserialize(celevator.storage:get_string("dispatcher_iqueue")) or {}
|
||||
|
||||
celevator.dispatcher.equeue = minetest.deserialize(celevator.storage:get_string("dispatcher_equeue")) or {}
|
||||
|
||||
celevator.dispatcher.running = {}
|
||||
|
||||
local fw,err = loadfile(minetest.get_modpath("celevator")..DIR_DELIM.."dispatcherfw.lua")
|
||||
if not fw then error(err) end
|
||||
|
||||
minetest.register_chatcommand("celevator_reloaddispatcher",{
|
||||
params = "",
|
||||
description = "Reload celevator dispatcher firmware from disk",
|
||||
privs = {server = true},
|
||||
func = function()
|
||||
local newfw,loaderr = loadfile(minetest.get_modpath("celevator")..DIR_DELIM.."dispatcherfw.lua")
|
||||
if newfw then
|
||||
fw = newfw
|
||||
return true,"Firmware reloaded successfully"
|
||||
else
|
||||
return false,loaderr
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local function after_place(pos,placer)
|
||||
local node = minetest.get_node(pos)
|
||||
local toppos = {x=pos.x,y=pos.y + 1,z=pos.z}
|
||||
local topnode = minetest.get_node(toppos)
|
||||
local placername = placer:get_player_name()
|
||||
if topnode.name ~= "air" then
|
||||
if placer:is_player() then
|
||||
minetest.chat_send_player(placername,"Can't place cabinet - no room for the top half!")
|
||||
end
|
||||
minetest.set_node(pos,{name="air"})
|
||||
return true
|
||||
end
|
||||
if minetest.is_protected(toppos,placername) and not minetest.check_player_privs(placername,{protection_bypass=true}) then
|
||||
if placer:is_player() then
|
||||
minetest.chat_send_player(placername,"Can't place cabinet - top half is protected!")
|
||||
minetest.record_protection_violation(toppos,placername)
|
||||
end
|
||||
minetest.set_node(pos,{name="air"})
|
||||
return true
|
||||
end
|
||||
node.name = "celevator:dispatcher_top"
|
||||
minetest.set_node(toppos,node)
|
||||
end
|
||||
|
||||
local function ondestruct(pos)
|
||||
pos.y = pos.y + 1
|
||||
local topnode = minetest.get_node(pos)
|
||||
local dispatchertops = {
|
||||
["celevator:dispatcher_top"] = true,
|
||||
["celevator:dispatcher_top_open"] = true,
|
||||
}
|
||||
if dispatchertops[topnode.name] then
|
||||
minetest.set_node(pos,{name="air"})
|
||||
end
|
||||
celevator.dispatcher.equeue[minetest.hash_node_position(pos)] = nil
|
||||
celevator.storage:set_string("dispatcher_equeue",minetest.serialize(celevator.dispatcher.equeue))
|
||||
local carid = minetest.get_meta(pos):get_int("carid")
|
||||
if carid ~= 0 then celevator.storage:set_string(string.format("car%d",carid),"") end
|
||||
end
|
||||
|
||||
local function onrotate(controllerpos,node,user,mode,new_param2)
|
||||
if not minetest.global_exists("screwdriver") then
|
||||
return false
|
||||
end
|
||||
local ret = screwdriver.rotate_simple(controllerpos,node,user,mode,new_param2)
|
||||
minetest.after(0,function(pos)
|
||||
local newnode = minetest.get_node(pos)
|
||||
local param2 = newnode.param2
|
||||
pos.y = pos.y + 1
|
||||
local topnode = minetest.get_node(pos)
|
||||
topnode.param2 = param2
|
||||
minetest.set_node(pos,topnode)
|
||||
end,controllerpos)
|
||||
return ret
|
||||
end
|
||||
|
||||
local function handlefields(pos,_,fields,sender)
|
||||
local playername = sender and sender:get_player_name() or ""
|
||||
local event = {}
|
||||
event.type = "ui"
|
||||
event.fields = fields
|
||||
event.sender = playername
|
||||
celevator.dispatcher.run(pos,event)
|
||||
end
|
||||
|
||||
minetest.register_node("celevator:dispatcher",{
|
||||
description = "Elevator Dispatcher",
|
||||
groups = {
|
||||
cracky = 1,
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5,-0.5,0,0.5,0.5,0.5},
|
||||
},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5,-0.5,0,0.5,1.5,0.5},
|
||||
},
|
||||
},
|
||||
tiles = {
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_front_bottom.png",
|
||||
},
|
||||
after_place_node = after_place,
|
||||
on_destruct = ondestruct,
|
||||
on_rotate = onrotate,
|
||||
on_receive_fields = handlefields,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("mem",minetest.serialize({}))
|
||||
meta:mark_as_private("mem")
|
||||
local event = {}
|
||||
event.type = "program"
|
||||
local carid = celevator.storage:get_int("maxcarid")+1
|
||||
meta:set_int("carid",carid)
|
||||
celevator.storage:set_int("maxcarid",carid)
|
||||
celevator.storage:set_string(string.format("car%d",carid),minetest.serialize({dispatcherpos=pos,callbuttons={},fs1switches={}}))
|
||||
celevator.dispatcher.run(pos,event)
|
||||
end,
|
||||
on_punch = function(pos,node,puncher)
|
||||
if not puncher:is_player() then
|
||||
return
|
||||
end
|
||||
local name = puncher:get_player_name()
|
||||
if minetest.is_protected(pos,name) and not minetest.check_player_privs(name,{protection_bypass=true}) then
|
||||
minetest.chat_send_player(name,"Can't open cabinet - cabinet is locked.")
|
||||
minetest.record_protection_violation(pos,name)
|
||||
return
|
||||
end
|
||||
node.name = "celevator:dispatcher_open"
|
||||
minetest.swap_node(pos,node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec",meta:get_string("formspec_hidden"))
|
||||
pos.y = pos.y + 1
|
||||
node = minetest.get_node(pos)
|
||||
node.name = "celevator:dispatcher_top_open"
|
||||
minetest.swap_node(pos,node)
|
||||
minetest.sound_play("doors_steel_door_open",{
|
||||
pos = pos,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 10
|
||||
},true)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("celevator:dispatcher_open",{
|
||||
description = "Dispatcher (door open - you hacker you!)",
|
||||
groups = {
|
||||
cracky = 1,
|
||||
not_in_creative_inventory = 1,
|
||||
},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
drop = "celevator:dispatcher",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5,-0.5,0,0.5,0.5,0.5},
|
||||
{-0.5,-0.5,-0.5,-0.45,0.5,0},
|
||||
{0.45,-0.5,-0.5,0.5,0.5,0},
|
||||
},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5,-0.5,-0.5,0.5,1.5,0.5},
|
||||
},
|
||||
},
|
||||
tiles = {
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_front_bottom_open_rside.png",
|
||||
"celevator_cabinet_front_bottom_open_lside.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
{
|
||||
name="celevator_dispatcher_front_bottom_open.png",
|
||||
animation={type="vertical_frames", aspect_w=32, aspect_h=32, length=2},
|
||||
}
|
||||
},
|
||||
after_place_node = after_place,
|
||||
on_destruct = ondestruct,
|
||||
on_rotate = onrotate,
|
||||
on_receive_fields = handlefields,
|
||||
on_punch = function(pos,node,puncher)
|
||||
if not puncher:is_player() then
|
||||
return
|
||||
end
|
||||
node.name = "celevator:dispatcher"
|
||||
minetest.swap_node(pos,node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec","")
|
||||
pos.y = pos.y + 1
|
||||
node = minetest.get_node(pos)
|
||||
node.name = "celevator:dispatcher_top"
|
||||
minetest.swap_node(pos,node)
|
||||
minetest.sound_play("doors_steel_door_close",{
|
||||
pos = pos,
|
||||
gain = 0.5,
|
||||
max_hear_distance = 10
|
||||
},true)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("celevator:dispatcher_top",{
|
||||
description = "Dispatcher (top section - you hacker you!)",
|
||||
groups = {
|
||||
not_in_creative_inventory = 1,
|
||||
},
|
||||
drop = "",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5,-0.5,0,0.5,0.5,0.5},
|
||||
},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{0,0,0,0,0,0},
|
||||
},
|
||||
},
|
||||
tiles = {
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_dispatcher_front_top.png",
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_node("celevator:dispatcher_top_open",{
|
||||
description = "Dispatcher (top section, open - you hacker you!)",
|
||||
groups = {
|
||||
not_in_creative_inventory = 1,
|
||||
},
|
||||
drop = "",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5,-0.5,0,0.5,0.5,0.5},
|
||||
{-0.5,-0.5,-0.5,-0.45,0.5,0},
|
||||
{0.45,-0.5,-0.5,0.5,0.5,0},
|
||||
},
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{0,0,0,0,0,0},
|
||||
},
|
||||
},
|
||||
tiles = {
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_cabinet_front_top_open_rside.png",
|
||||
"celevator_dispatcher_front_top_open_lside.png",
|
||||
"celevator_cabinet_sides.png",
|
||||
"celevator_dispatcher_front_top_open.png",
|
||||
},
|
||||
})
|
||||
|
||||
function celevator.dispatcher.isdispatcher(pos)
|
||||
local node = celevator.get_node(pos)
|
||||
return (node.name == "celevator:dispatcher" or node.name == "celevator:dispatcher_open")
|
||||
end
|
||||
|
||||
function celevator.dispatcher.finish(pos,mem,changedinterrupts)
|
||||
if not celevator.dispatcher.isdispatcher(pos) then
|
||||
return
|
||||
else
|
||||
local meta = minetest.get_meta(pos)
|
||||
local carid = meta:get_int("carid")
|
||||
local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid)))
|
||||
local carinfodirty = false
|
||||
if not carinfo then
|
||||
minetest.log("error","[celevator] [controller] Bad car info for dispatcher at "..minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
local node = celevator.get_node(pos)
|
||||
local oldmem = minetest.deserialize(meta:get_string("mem")) or {}
|
||||
local oldupbuttonlights = oldmem.upcalls or {}
|
||||
local olddownbuttonlights = oldmem.dncalls or {}
|
||||
local newupbuttonlights = mem.upcalls or {}
|
||||
local newdownbuttonlights = mem.dncalls or {}
|
||||
local callbuttons = carinfo.callbuttons
|
||||
for _,button in pairs(callbuttons) do
|
||||
if oldupbuttonlights[button.landing] ~= newupbuttonlights[button.landing] then
|
||||
celevator.callbutton.setlight(button.pos,"up",newupbuttonlights[button.landing])
|
||||
end
|
||||
if olddownbuttonlights[button.landing] ~= newdownbuttonlights[button.landing] then
|
||||
celevator.callbutton.setlight(button.pos,"down",newdownbuttonlights[button.landing])
|
||||
end
|
||||
end
|
||||
local oldfs1led = oldmem.fs1led
|
||||
local newfs1led = mem.fs1led
|
||||
local fs1switches = carinfo.fs1switches or {}
|
||||
if oldfs1led ~= newfs1led then
|
||||
for _,fs1switch in pairs(fs1switches) do
|
||||
celevator.fs1switch.setled(fs1switch.pos,newfs1led)
|
||||
end
|
||||
end
|
||||
for _,message in ipairs(mem.messages) do
|
||||
local destinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",message.carid)))
|
||||
if destinfo and destinfo.controllerpos then
|
||||
celevator.controller.run(destinfo.controllerpos,{
|
||||
type = "dispatchermsg",
|
||||
source = mem.carid,
|
||||
channel = message.channel,
|
||||
msg = message.message,
|
||||
})
|
||||
end
|
||||
end
|
||||
meta:set_string("mem",minetest.serialize(mem))
|
||||
if node.name == "celevator:dispatcher_open" then meta:set_string("formspec",mem.formspec or "") end
|
||||
meta:set_string("formspec_hidden",mem.formspec or "")
|
||||
meta:set_string("infotext",mem.infotext or "")
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
if not celevator.dispatcher.iqueue[hash] then celevator.dispatcher.iqueue[hash] = mem.interrupts end
|
||||
for iid in pairs(changedinterrupts) do
|
||||
celevator.dispatcher.iqueue[hash][iid] = mem.interrupts[iid]
|
||||
end
|
||||
celevator.storage:set_string("dispatcher_iqueue",minetest.serialize(celevator.dispatcher.iqueue))
|
||||
celevator.dispatcher.running[hash] = nil
|
||||
if #celevator.dispatcher.equeue[hash] > 0 then
|
||||
local event = celevator.dispatcher.equeue[hash][1]
|
||||
table.remove(celevator.dispatcher.equeue[hash],1)
|
||||
celevator.storage:set_string("dispatcher_equeue",minetest.serialize(celevator.dispatcher.equeue))
|
||||
celevator.dispatcher.run(pos,event)
|
||||
end
|
||||
if carinfodirty then
|
||||
celevator.storage:set_string(string.format("car%d",carid),minetest.serialize(carinfo))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function celevator.dispatcher.run(pos,event)
|
||||
if not celevator.dispatcher.isdispatcher(pos) then
|
||||
return
|
||||
else
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
if not celevator.dispatcher.equeue[hash] then
|
||||
celevator.dispatcher.equeue[hash] = {}
|
||||
celevator.storage:set_string("dispatcher_equeue",minetest.serialize(celevator.dispatcher.equeue))
|
||||
end
|
||||
if celevator.dispatcher.running[hash] then
|
||||
table.insert(celevator.dispatcher.equeue[hash],event)
|
||||
celevator.storage:set_string("dispatcher_equeue",minetest.serialize(celevator.dispatcher.equeue))
|
||||
if #celevator.dispatcher.equeue[hash] > 5 then
|
||||
local message = "[celevator] [dispatcher] Async process for dispatcher at %s is falling behind, %d events in queue"
|
||||
minetest.log("warning",string.format(message,minetest.pos_to_string(pos),#celevator.dispatcher.equeue[hash]))
|
||||
end
|
||||
return
|
||||
end
|
||||
celevator.dispatcher.running[hash] = true
|
||||
local meta = minetest.get_meta(pos)
|
||||
local mem = minetest.deserialize(meta:get_string("mem"))
|
||||
if not mem then
|
||||
minetest.log("error","[celevator] [controller] Failed to load dispatcher memory at "..minetest.pos_to_string(pos))
|
||||
return
|
||||
end
|
||||
mem.interrupts = celevator.dispatcher.iqueue[minetest.hash_node_position(pos)] or {}
|
||||
mem.carid = meta:get_int("carid")
|
||||
minetest.handle_async(fw,celevator.dispatcher.finish,pos,event,mem)
|
||||
end
|
||||
end
|
||||
|
||||
function celevator.dispatcher.handlecallbutton(dispatcherpos,landing,dir)
|
||||
local event = {
|
||||
type = "callbutton",
|
||||
landing = landing,
|
||||
dir = dir,
|
||||
}
|
||||
celevator.dispatcher.run(dispatcherpos,event)
|
||||
end
|
||||
|
||||
function celevator.controller.handlefs1switch(dispatcherpos,on)
|
||||
local event = {
|
||||
type = "fs1switch",
|
||||
state = on,
|
||||
}
|
||||
celevator.dispatcher.run(dispatcherpos,event)
|
||||
end
|
||||
|
||||
function celevator.dispatcher.checkiqueue(dtime)
|
||||
for hash,iqueue in pairs(celevator.dispatcher.iqueue) do
|
||||
local pos = minetest.get_position_from_hash(hash)
|
||||
for iid,time in pairs(iqueue) do
|
||||
iqueue[iid] = time-dtime
|
||||
if iqueue[iid] < 0 then
|
||||
iqueue[iid] = nil
|
||||
local event = {}
|
||||
event.type = "interrupt"
|
||||
event.iid = iid
|
||||
celevator.dispatcher.run(pos,event)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_globalstep(celevator.dispatcher.checkiqueue)
|
||||
|
||||
minetest.register_abm({
|
||||
label = "Run otherwise idle dispatchers if a user is nearby",
|
||||
nodenames = {"celevator:dispatcher","celevator:dispatcher_open"},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = function(pos)
|
||||
local event = {
|
||||
type = "abm"
|
||||
}
|
||||
celevator.dispatcher.run(pos,event)
|
||||
end,
|
||||
})
|
281
dispatcherfw.lua
Normal file
281
dispatcherfw.lua
Normal file
@ -0,0 +1,281 @@
|
||||
local pos,event,mem = ...
|
||||
|
||||
local changedinterrupts = {}
|
||||
|
||||
local function interrupt(time,iid)
|
||||
mem.interrupts[iid] = time
|
||||
changedinterrupts[iid] = true
|
||||
end
|
||||
|
||||
mem.messages = {}
|
||||
|
||||
local function send(carid,channel,message)
|
||||
table.insert(mem.messages,{
|
||||
carid = carid,
|
||||
channel = channel,
|
||||
message = message,
|
||||
})
|
||||
end
|
||||
|
||||
mem.formspec = ""
|
||||
|
||||
local function fs(element)
|
||||
mem.formspec = mem.formspec..element
|
||||
end
|
||||
|
||||
if event.type == "program" then
|
||||
mem.carstatus = {}
|
||||
mem.screenstate = "oobe_welcome"
|
||||
mem.editingfloor = 1
|
||||
mem.screenpage = 1
|
||||
mem.editingconnection = 1
|
||||
mem.newconncarid = 0
|
||||
if not mem.params then
|
||||
mem.params = {
|
||||
carids = {},
|
||||
floorheights = {5,5,5},
|
||||
floornames = {"1","2","3"},
|
||||
floorsserved = {},
|
||||
}
|
||||
end
|
||||
elseif event.type == "ui" then
|
||||
local fields = event.fields
|
||||
if mem.screenstate == "oobe_welcome" then
|
||||
if fields.license then
|
||||
mem.screenstate = "oobe_license"
|
||||
elseif fields.next then
|
||||
mem.screenstate = "oobe_floortable"
|
||||
end
|
||||
elseif mem.screenstate == "oobe_license" then
|
||||
if fields.back then
|
||||
mem.screenstate = "oobe_welcome"
|
||||
end
|
||||
elseif mem.screenstate == "oobe_floortable" or mem.screenstate == "floortable" then
|
||||
local exp = event.fields.floor and minetest.explode_textlist_event(event.fields.floor) or {}
|
||||
if event.fields.back then
|
||||
mem.screenstate = "oobe_welcome"
|
||||
elseif event.fields.next then
|
||||
mem.screenstate = (mem.screenstate == "oobe_floortable" and "oobe_connections" or "parameters")
|
||||
mem.screenpage = 1
|
||||
elseif exp.type == "CHG" then
|
||||
mem.editingfloor = #mem.params.floornames-exp.index+1
|
||||
elseif exp.type == "DCL" then
|
||||
mem.editingfloor = #mem.params.floornames-exp.index+1
|
||||
mem.screenstate = (mem.screenstate == "oobe_floortable" and "oobe_floortable_edit" or "floortable_edit")
|
||||
elseif event.fields.edit then
|
||||
mem.screenstate = (mem.screenstate == "oobe_floortable" and "oobe_floortable_edit" or "floortable_edit")
|
||||
elseif event.fields.add then
|
||||
table.insert(mem.params.floorheights,5)
|
||||
table.insert(mem.params.floornames,tostring(#mem.params.floornames+1))
|
||||
elseif event.fields.remove then
|
||||
table.remove(mem.params.floorheights,mem.editingfloor)
|
||||
table.remove(mem.params.floornames,mem.editingfloor)
|
||||
mem.editingfloor = math.max(1,mem.editingfloor-1)
|
||||
elseif event.fields.moveup then
|
||||
local height = mem.params.floorheights[mem.editingfloor]
|
||||
local name = mem.params.floornames[mem.editingfloor]
|
||||
table.remove(mem.params.floorheights,mem.editingfloor)
|
||||
table.remove(mem.params.floornames,mem.editingfloor)
|
||||
table.insert(mem.params.floorheights,mem.editingfloor+1,height)
|
||||
table.insert(mem.params.floornames,mem.editingfloor+1,name)
|
||||
mem.editingfloor = mem.editingfloor + 1
|
||||
elseif event.fields.movedown then
|
||||
local height = mem.params.floorheights[mem.editingfloor]
|
||||
local name = mem.params.floornames[mem.editingfloor]
|
||||
table.remove(mem.params.floorheights,mem.editingfloor)
|
||||
table.remove(mem.params.floornames,mem.editingfloor)
|
||||
table.insert(mem.params.floorheights,mem.editingfloor-1,height)
|
||||
table.insert(mem.params.floornames,mem.editingfloor-1,name)
|
||||
mem.editingfloor = mem.editingfloor - 1
|
||||
end
|
||||
elseif mem.screenstate == "oobe_floortable_edit" or mem.screenstate == "floortable_edit" then
|
||||
if event.fields.back or event.fields.save then
|
||||
mem.screenstate = (mem.screenstate == "oobe_floortable_edit" and "oobe_floortable" or "floortable")
|
||||
local height = tonumber(event.fields.height)
|
||||
if height then
|
||||
height = math.floor(height+0.5)
|
||||
mem.params.floorheights[mem.editingfloor] = math.max(0,height)
|
||||
end
|
||||
mem.params.floornames[mem.editingfloor] = string.sub(event.fields.name,1,256)
|
||||
end
|
||||
elseif mem.screenstate == "oobe_connections" or mem.screenstate == "connections" then
|
||||
local exp = event.fields.connection and minetest.explode_textlist_event(event.fields.connection) or {}
|
||||
if event.fields.back then
|
||||
mem.screenstate = "oobe_floortable"
|
||||
elseif event.fields.next and #mem.params.carids > 0 then
|
||||
mem.screenstate = (mem.screenstate == "oobe_connections" and "status" or "parameters")
|
||||
mem.screenpage = 1
|
||||
elseif exp.type == "CHG" then
|
||||
mem.editingconnection = #mem.params.carids-exp.index+1
|
||||
elseif exp.type == "DCL" then
|
||||
mem.editingconnection = #mem.params.carids-exp.index+1
|
||||
mem.screenstate = (mem.screenstate == "oobe_connections" and "oobe_connection" or "connection")
|
||||
elseif event.fields.edit then
|
||||
mem.screenstate = (mem.screenstate == "oobe_connections" and "oobe_connection" or "connection")
|
||||
elseif event.fields.add then
|
||||
mem.newconnfloors = {}
|
||||
for i in ipairs(mem.params.floornames) do
|
||||
mem.newconnfloors[i] = true
|
||||
end
|
||||
mem.screenstate = (mem.screenstate == "oobe_connections" and "oobe_newconnection" or "newconnection")
|
||||
elseif event.fields.remove then
|
||||
mem.carstatus[mem.params.carids[mem.editingconnection]] = nil
|
||||
table.remove(mem.params.carids,mem.editingconnection)
|
||||
mem.editingconnection = math.max(1,mem.editingconnection-1)
|
||||
end
|
||||
elseif mem.screenstate == "oobe_newconnection" or mem.screenstate == "newconnection" then
|
||||
local exp = event.fields.floors and minetest.explode_textlist_event(event.fields.floors) or {}
|
||||
if event.fields.back then
|
||||
mem.screenstate = (mem.screenstate == "oobe_newconnection" and "oobe_connections" or "connections")
|
||||
elseif event.fields.connect and fields.carid and tonumber(fields.carid) then
|
||||
mem.screenstate = (mem.screenstate == "oobe_newconnection" and "oobe_connecting" or "connecting")
|
||||
local floornames = {}
|
||||
local floorheights = {}
|
||||
for i=1,#mem.params.floornames,1 do
|
||||
if mem.newconnfloors[i] then
|
||||
table.insert(floornames,mem.params.floornames[i])
|
||||
table.insert(floorheights,mem.params.floorheights[i])
|
||||
elseif #floornames > 0 then
|
||||
floorheights[#floorheights] = floorheights[#floorheights]+mem.params.floorheights[i]
|
||||
end
|
||||
end
|
||||
send(tonumber(fields.carid),"pairrequest",{
|
||||
dispatcherid = mem.carid,
|
||||
floornames = floornames,
|
||||
floorheights = floorheights,
|
||||
})
|
||||
interrupt(3,"connecttimeout")
|
||||
elseif exp.type == "CHG" then
|
||||
local floor = #mem.params.floornames-exp.index+1
|
||||
mem.newconnfloors[floor] = not mem.newconnfloors[floor]
|
||||
end
|
||||
elseif mem.screenstate == "oobe_connectionfailed" or mem.screenstate == "connectionfailed" then
|
||||
if fields.back then
|
||||
mem.screenstate = (mem.screenstate == "oobe_connectionfailed" and "oobe_newconnection" or "newconnection")
|
||||
end
|
||||
end
|
||||
elseif event.iid == "connecttimeout" then
|
||||
if mem.screenstate == "oobe_connecting" then
|
||||
mem.screenstate = "oobe_connectionfailed"
|
||||
elseif mem.screenstate == "connecting" then
|
||||
mem.screenstate = "connectionfailed"
|
||||
end
|
||||
elseif event.channel == "pairok" then
|
||||
if mem.screenstate == "oobe_connecting" or mem.screenstate == "connecting" then
|
||||
interrupt(nil,"connecttimeout")
|
||||
mem.screenstate = (mem.screenstate == "oobe_connecting" and "oobe_connections" or "connections")
|
||||
mem.carstatus[event.source] = {
|
||||
upcalls = {},
|
||||
dncalls = {},
|
||||
carcalls = {},
|
||||
position = event.msg.drive.status.apos or 0,
|
||||
state = event.msg.carstate,
|
||||
}
|
||||
mem.params.floorsserved[event.source] = mem.newconnfloors
|
||||
table.insert(mem.params.carids,event.source)
|
||||
end
|
||||
end
|
||||
|
||||
fs("formspec_version[6]")
|
||||
fs("size[16,12]")
|
||||
fs("background9[0,0;16,12;celevator_fs_bg.png;true;3]")
|
||||
|
||||
if mem.screenstate == "oobe_welcome" then
|
||||
fs("image[6,1;4,2;celevator_logo.png]")
|
||||
fs("label[1,4;Welcome to your new MTronic XT elevator dispatcher!]")
|
||||
fs("label[1,4.5;Before continuing, make sure you have at least two controllers in group operation mode and ready to connect.]")
|
||||
fs("label[1,5.5;Press Next to begin.]")
|
||||
fs("button[1,10;2,1;license;License Info]")
|
||||
fs("button[13,10;2,1;next;Next >]")
|
||||
elseif mem.screenstate == "oobe_license" then
|
||||
local licensefile = io.open(minetest.get_modpath("celevator")..DIR_DELIM.."COPYING")
|
||||
local license = minetest.formspec_escape(licensefile:read("*all"))
|
||||
licensefile:close()
|
||||
fs("textarea[1,1;14,8;license;This applies to the whole celevator mod\\, not just this dispatcher:;"..license.."]")
|
||||
fs("button[7,10.5;2,1;back;OK]")
|
||||
elseif mem.screenstate == "oobe_floortable" or mem.screenstate == "floortable" then
|
||||
if mem.screenstate == "oobe_floortable" then
|
||||
fs("label[1,1;Enter details of all floors this group will serve, then press Next.]")
|
||||
fs("label[1,1.3;Include all floors served by any car in the group, even if not served by all cars.]")
|
||||
fs("button[1,10;2,1;back;< Back]")
|
||||
fs("button[13,10;2,1;next;Next >]")
|
||||
else
|
||||
fs("label[1,1;EDIT FLOOR TABLE]")
|
||||
fs("button[1,10;2,1;next;Done]")
|
||||
end
|
||||
fs("textlist[1,2;6,7;floor;")
|
||||
for i=#mem.params.floornames,1,-1 do
|
||||
fs(minetest.formspec_escape(string.format("%d - Height: %d - PI: %s",i,mem.params.floorheights[i],mem.params.floornames[i]))..(i==1 and "" or ","))
|
||||
end
|
||||
fs(";"..tostring(#mem.params.floornames-mem.editingfloor+1)..";false]")
|
||||
if #mem.params.floornames < 100 then fs("button[8,2;2,1;add;New Floor]") end
|
||||
fs("button[8,3.5;2,1;edit;Edit Floor]")
|
||||
if #mem.params.floornames > 2 then fs("button[8,5;2,1;remove;Remove Floor]") end
|
||||
if mem.editingfloor < #mem.params.floornames then fs("button[8,6.5;2,1;moveup;Move Up]") end
|
||||
if mem.editingfloor > 1 then fs("button[8,8;2,1;movedown;Move Down") end
|
||||
elseif mem.screenstate == "oobe_floortable_edit" or mem.screenstate == "floortable_edit" then
|
||||
if mem.screenstate == "oobe_floortable_edit" then
|
||||
fs("button[7,10.5;2,1;back;OK]")
|
||||
fs("label[1,5;The Floor Height is the distance (in meters/nodes) from the floor level of this floor to the floor level of the next floor.]")
|
||||
fs("label[1,5.5;(not used at the highest floor)]")
|
||||
fs("label[1,6.5;The Floor Name is how the floor will be displayed on the position indicators.]")
|
||||
else
|
||||
fs("button[7,10.5;2,1;save;Save]")
|
||||
end
|
||||
fs("label[1,1;Editing floor "..tostring(mem.editingfloor).."]")
|
||||
fs("field[1,3;3,1;height;Floor Height;"..tostring(mem.params.floorheights[mem.editingfloor]).."]")
|
||||
fs("field[5,3;3,1;name;Floor Name;"..minetest.formspec_escape(mem.params.floornames[mem.editingfloor]).."]")
|
||||
elseif mem.screenstate == "oobe_connections" or mem.screenstate == "connections" then
|
||||
if mem.screenstate == "oobe_connections" then
|
||||
fs("label[1,1;Connect to each car in the group, then click Done.]")
|
||||
fs("button[1,10;2,1;back;< Back]")
|
||||
if #mem.params.carids > 0 then fs("button[13,10;2,1;next;Done >]") end
|
||||
else
|
||||
fs("label[1,1;EDIT CONNECTIONS]")
|
||||
if #mem.params.carids > 0 then fs("button[1,10;2,1;next;Done]") end
|
||||
end
|
||||
if #mem.params.carids > 0 then
|
||||
fs("textlist[1,2;6,7;connection;")
|
||||
for i=#mem.params.carids,1,-1 do
|
||||
fs(string.format("Car %d - ID #%d",i,mem.params.carids[i])..(i==1 and "" or ","))
|
||||
end
|
||||
fs(";"..tostring(#mem.params.floornames-mem.editingfloor+1)..";false]")
|
||||
else
|
||||
fs("label[1,2;No Connections]")
|
||||
end
|
||||
if #mem.params.carids < 16 then fs("button[8,2;2,1;add;New Connection]") end
|
||||
if #mem.params.carids > 0 then fs("button[8,3.5;2,1;edit;Edit Connection]") end
|
||||
if #mem.params.carids > 0 then fs("button[8,5;2,1;remove;Remove Connection]") end
|
||||
elseif mem.screenstate == "oobe_newconnection" or mem.screenstate == "newconnection" then
|
||||
local numfloors = 0
|
||||
for _,v in ipairs(mem.newconnfloors) do
|
||||
if v then numfloors = numfloors + 1 end
|
||||
end
|
||||
if mem.screenstate == "oobe_newconnection" then
|
||||
fs("label[1,1;Enter the car ID and select the floors served (click them to toggle), then click Connect.]")
|
||||
fs("label[1,1.3;You must select at least two floors.]")
|
||||
fs("button[1,10;2,1;back;< Back]")
|
||||
if numfloors >= 2 then fs("button[13,10;2,1;connect;Connect >]") end
|
||||
else
|
||||
fs("label[1,1;NEW CONNECTION]")
|
||||
fs("button[1,10;2,1;back;< Back]")
|
||||
if numfloors >= 2 then fs("button[13,10;2,1;connect;Connect >]") end
|
||||
end
|
||||
fs("textlist[8,2;6,7;floors;")
|
||||
for i=#mem.params.floornames,1,-1 do
|
||||
fs(string.format("%s - %s",minetest.formspec_escape(mem.params.floornames[i]),mem.newconnfloors[i] and "YES" or "NO")..(i==1 and "" or ","))
|
||||
end
|
||||
fs(";0;false]")
|
||||
fs("field[2,3;4,1;carid;Car ID;]")
|
||||
elseif mem.screenstate == "oobe_connecting" or mem.screenstate == "connecting" then
|
||||
fs("label[1,1;Connecting to controller...]")
|
||||
elseif mem.screenstate == "oobe_connectionfailed" or mem.screenstate == "connectionfailed" then
|
||||
fs("label[4,4;Connection timed out!]")
|
||||
fs("label[4,5;Make sure the car ID is correct and]")
|
||||
fs("label[4,5.5;that the controller is ready to pair.]")
|
||||
fs("button[1,10;2,1;back;< Back]")
|
||||
end
|
||||
|
||||
mem.infotext = string.format("ID: %d",mem.carid)
|
||||
|
||||
return pos,mem,changedinterrupts
|
1
init.lua
1
init.lua
@ -8,6 +8,7 @@ local components = {
|
||||
"callbuttons",
|
||||
"pilantern",
|
||||
"fs1switch",
|
||||
"dispatcher",
|
||||
}
|
||||
|
||||
for _,v in ipairs(components) do
|
||||
|
BIN
textures/celevator_dispatcher_front_bottom_open.png
Normal file
BIN
textures/celevator_dispatcher_front_bottom_open.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
textures/celevator_dispatcher_front_top.png
Normal file
BIN
textures/celevator_dispatcher_front_top.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
BIN
textures/celevator_dispatcher_front_top_open.png
Normal file
BIN
textures/celevator_dispatcher_front_top_open.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
textures/celevator_dispatcher_front_top_open_lside.png
Normal file
BIN
textures/celevator_dispatcher_front_top_open_lside.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Loading…
x
Reference in New Issue
Block a user