From bf31b4384e9eb52288dc4c3d60d075843ecd6422 Mon Sep 17 00:00:00 2001 From: cheapie Date: Fri, 31 May 2024 23:26:37 -0500 Subject: Add destination-based dispatching Still uses a crude ETA algorithm for now and is missing some features, but it is working and usable at a basic level --- controllerfw.lua | 4 + crafts.lua | 9 +++ dbdkiosk.lua | 171 ++++++++++++++++++++++++++++++++++++++++ dispatcher.lua | 3 + dispatcherfw.lua | 67 +++++++++++++++- init.lua | 1 + textures/celevator_dbdkiosk.png | Bin 0 -> 815 bytes 7 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 dbdkiosk.lua create mode 100644 textures/celevator_dbdkiosk.png diff --git a/controllerfw.lua b/controllerfw.lua index 26aabf2..3392179 100644 --- a/controllerfw.lua +++ b/controllerfw.lua @@ -734,6 +734,10 @@ elseif event.type == "dispatchermsg" then mem.groupupcalls[event.msg] = nil elseif event.channel == "groupdncancel" then mem.groupdncalls[event.msg] = nil + elseif event.channel == "swingupcall" and mem.carstate == "normal" then + mem.swingupcalls[event.msg] = true + elseif event.channel == "swingdncall" and mem.carstate == "normal" then + mem.swingdncalls[event.msg] = true elseif event.channel == "carcall" and mem.carstate == "normal" then mem.carcalls[event.msg] = true send(event.source,"status",mem) diff --git a/crafts.lua b/crafts.lua index dd4b796..fd4390d 100644 --- a/crafts.lua +++ b/crafts.lua @@ -287,3 +287,12 @@ minetest.register_craft({ "basic_materials:steel_strip", }, }) + +minetest.register_craft({ + output = "celevator:dbdkiosk", + recipe = { + {"basic_materials:steel_strip","basic_materials:ic","default:glass"}, + {"basic_materials:steel_strip","mesecons_lightstone:lightstone_white_off","default:glass"}, + {"basic_materials:steel_strip","","default:glass"}, + }, +}) diff --git a/dbdkiosk.lua b/dbdkiosk.lua new file mode 100644 index 0000000..7f5996f --- /dev/null +++ b/dbdkiosk.lua @@ -0,0 +1,171 @@ +celevator.dbdkiosk = {} + +function celevator.dbdkiosk.checkprot(pos,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 false + end + return true +end + +function celevator.dbdkiosk.updatefields(pos) + if minetest.get_node(pos).name ~= "celevator:dbdkiosk" then return end + local meta = minetest.get_meta(pos) + local screenstate = meta:get_string("screenstate") + if screenstate == "connect" then + meta:set_string("formspec","formspec_version[7]size[8,5]field[0.5,0.5;7,1;carid;Dispatcher ID;]field[0.5,2;7,1;landing;Landing Number;]button[3,3.5;2,1;save;Save]") + elseif screenstate == "main" then + local landing = meta:get_int("landing") + local fs = "formspec_version[7]" + fs = fs.."size[8,14]" + fs = fs.."label[3,0.5;Please select a floor\\:]" + local floornames = minetest.deserialize(meta:get_string("floornames")) + local floorsavailable = minetest.deserialize(meta:get_string("floorsavailable")) + local showfloors = {} + for i=1,#floornames,1 do + if floorsavailable[i] then + table.insert(showfloors,i) + end + end + local startfloor = (meta:get_int("screenpage")-1)*10+1 + for i=1,10,1 do + local floornum = showfloors[startfloor+i-1] + local floorname = floornum and floornames[floornum] + if floorname and floornum ~= landing then + fs = fs..string.format("button[2,%f;4,1;floor%d;%s]",12-i,floornum,minetest.formspec_escape(floorname)) + end + end + if startfloor > 1 then + fs = fs.."button[3.75,12.2;0.8,0.8;scrolldown;vvv]" + end + if startfloor+9 < #showfloors then + fs = fs.."button[3.75,1;0.8,0.8;scrollup;^^^]" + end + meta:set_string("formspec",fs) + elseif screenstate == "assignment" then + local fs = "formspec_version[7]" + fs = fs.."size[8,14]" + fs = fs.."label[3,3;Please use elevator]" + fs = fs.."style_type[label;font_size=*4]" + fs = fs.."label[3.5,5;"..meta:get_string("assignedcar").."]" + meta:set_string("formspec",fs) + elseif screenstate == "error" then + local fs = "formspec_version[7]" + fs = fs.."size[8,14]" + fs = fs.."label[3.5,0.5;ERROR]" + fs = fs.."label[2.5,3;Could not find a suitable elevator]" + fs = fs.."label[2.5,3.5;Please try again later]" + meta:set_string("formspec",fs) + end +end + +function celevator.dbdkiosk.handlefields(pos,_,fields,player) + local name = player:get_player_name() + local meta = minetest.get_meta(pos) + local screenstate = meta:get_string("screenstate") + if screenstate == "connect" then + if not (fields.save and celevator.dbdkiosk.checkprot(pos,name)) then return end + if not (tonumber(fields.carid) and tonumber(fields.landing)) then return end + local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",fields.carid))) + if not carinfo then return end + if not (carinfo.dispatcherpos and celevator.dispatcher.isdispatcher(carinfo.dispatcherpos)) then return end + local dmem = minetest.deserialize(minetest.get_meta(carinfo.dispatcherpos):get_string("mem")) + if not dmem then return end + local floornames = dmem.params.floornames + local floorsavailable = {} + for i=1,#floornames,1 do + floorsavailable[i] = true + end + meta:set_string("floornames",minetest.serialize(floornames)) + meta:set_string("floorsavailable",minetest.serialize(floorsavailable)) + meta:set_int("screenpage",1) + meta:set_string("screenstate","main") + meta:set_int("carid",tonumber(fields.carid)) + meta:set_int("landing",tonumber(fields.landing)) + celevator.dbdkiosk.updatefields(pos) + elseif screenstate == "main" then + for k,v in pairs(fields) do + if v and string.sub(k,1,5) == "floor" then + local floor = tonumber(string.sub(k,6,-1)) + if not floor then return end + local carid = meta:get_int("carid") + local carinfo = minetest.deserialize(celevator.storage:get_string(string.format("car%d",carid))) + if not carinfo then return end + if not (carinfo.dispatcherpos and celevator.dispatcher.isdispatcher(carinfo.dispatcherpos)) then return end + local dmem = minetest.deserialize(minetest.get_meta(carinfo.dispatcherpos):get_string("mem")) + if dmem then + local floornames = dmem.params.floornames + meta:set_string("floornames",minetest.serialize(floornames)) + end + local event = { + type = "dbdkiosk", + source = minetest.hash_node_position(pos), + player = name, + srcfloor = meta:get_int("landing"), + destfloor = floor, + } + celevator.dispatcher.run(carinfo.dispatcherpos,event) + end + end + if fields.scrollup then + local page = meta:get_int("screenpage") + meta:set_int("screenpage",page+1) + elseif fields.scrolldown then + local page = meta:get_int("screenpage") + meta:set_int("screenpage",math.max(1,page-1)) + end + celevator.dbdkiosk.updatefields(pos) + elseif screenstate == "assignment" or screenstate == "error" then + meta:set_string("screenstate","main") + celevator.dbdkiosk.updatefields(pos) + end +end + +function celevator.dbdkiosk.showassignment(pos,assignment) + local meta = minetest.get_meta(pos) + if meta:get_string("screenstate") == "main" then + local carnames = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"} + if carnames[assignment] then + meta:set_string("screenstate","assignment") + meta:set_string("assignedcar",carnames[assignment]) + else + meta:set_string("screenstate","error") + end + celevator.dbdkiosk.updatefields(pos) + minetest.after(5,function() + meta:set_string("screenstate","main") + celevator.dbdkiosk.updatefields(pos) + end) + end +end + +minetest.register_node("celevator:dbdkiosk",{ + description = "Elevator Destination Entry Kiosk", + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "4dir", + groups = { + cracky = 1, + }, + node_box = { + type = "fixed", + fixed = { + {-0.2,-0.5,0.4,0.2,0.1,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_sides.png^celevator_dbdkiosk.png", + }, + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("screenstate","connect") + celevator.dbdkiosk.updatefields(pos) + end, + on_receive_fields = celevator.dbdkiosk.handlefields, +}) diff --git a/dispatcher.lua b/dispatcher.lua index b58c6eb..a8bcf1c 100644 --- a/dispatcher.lua +++ b/dispatcher.lua @@ -345,6 +345,9 @@ function celevator.dispatcher.finish(pos,mem,changedinterrupts) }) end end + for _,message in ipairs(mem.kioskmessages) do + celevator.dbdkiosk.showassignment(minetest.get_position_from_hash(message.pos),message.car) + 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 "") diff --git a/dispatcherfw.lua b/dispatcherfw.lua index 318a69d..6489944 100644 --- a/dispatcherfw.lua +++ b/dispatcherfw.lua @@ -8,7 +8,9 @@ local function interrupt(time,iid) end mem.messages = {} +mem.kioskmessages = {} if not mem.powerstate then mem.powerstate = "awake" end +if not mem.dbdcalls then mem.dbdcalls = {} end local function getpos(carid) local floormap = {} @@ -98,6 +100,14 @@ local function send(carid,channel,message) }) end +local function kiosksend(kioskpos,carnum) + table.insert(mem.kioskmessages,{ + pos = kioskpos, + type = "assigned", + car = carnum, + }) +end + local function getnextcallabove(carid,dir,startpos,carcalls,upcalls,dncalls) for i=(startpos or getpos(carid)),#mem.params.floorheights,1 do if not dir then @@ -299,6 +309,7 @@ if event.type == "program" then mem.assigneddn = {} mem.upeta = {} mem.dneta = {} + mem.dbdcalls = {} if not mem.params then mem.params = { carids = {}, @@ -750,7 +761,48 @@ elseif event.type == "abm" or event.type == "remotewake" or (event.iid == "run" for floor,carid in pairs(mem.assigneddn) do mem.dneta[floor] = calculateeta(carid,floor,"down") end - if busy or event.type == "remotewake" then + for k,call in ipairs(mem.dbdcalls) do + if call.assigned then + local carstate = mem.carstatus[call.assigned].state + local doorstate = mem.carstatus[call.assigned].doorstate + local direction = mem.carstatus[call.assigned].direction + local desireddir = (call.srcfloor < call.destfloor and "up" or "down") + if direction == desireddir and doorstate ~= "closed" then + if carstate == "normal" then send(call.assigned,"carcall",realtocarfloor(call.assigned,call.destfloor)) end + table.remove(mem.dbdcalls,k) + end + else + local direction = (call.srcfloor < call.destfloor and "up" or "down") + local eligiblecars = {} + local revcarids = {} + for carnum,carid in pairs(mem.params.carids) do + if mem.carstatus[carid].state == "normal" and mem.params.floorsserved[carid][call.srcfloor] and mem.params.floorsserved[carid][call.destfloor] then + table.insert(eligiblecars,carid) + end + revcarids[carid] = carnum + end + local besteta = 999 + local bestcar + if #eligiblecars > 0 then + for _,carid in pairs(eligiblecars) do + local eta = calculateeta(carid,call.srcfloor,direction) + if eta < besteta then + besteta = eta + bestcar = carid + end + end + end + if bestcar then + call.assigned = bestcar + send(bestcar,(direction == "up" and "swingupcall" or "swingdncall"),realtocarfloor(bestcar,call.srcfloor)) + kiosksend(call.kioskpos,revcarids[bestcar]) + else + table.remove(mem.dbdcalls,k) + kiosksend(call.kioskpos,-1) + end + end + end + if busy or event.type == "remotewake" or #mem.dbdcalls > 0 then mem.powerstate = "awake" interrupt(nil,"sleep") interrupt(1,"run") @@ -809,6 +861,19 @@ elseif event.type == "remotemsg" then send(mem.params.carids[event.car],"carcall",event.floor) end end +elseif event.type == "dbdkiosk" then + if mem.powerstate == "asleep" then + mem.powerstate = "awake" + interrupt(0,"getstatus") + interrupt(1,"run") + elseif mem.powerstate == "timing" then + mem.powerstate = "awake" + end + table.insert(mem.dbdcalls,{ + srcfloor = event.srcfloor, + destfloor = event.destfloor, + kioskpos = event.source, + }) end if not (mem.screenstate == "status" or mem.screenstate == "menu") then diff --git a/init.lua b/init.lua index 9b794e9..7cc2a30 100644 --- a/init.lua +++ b/init.lua @@ -9,6 +9,7 @@ local components = { "pilantern", "fs1switch", "dispatcher", + "dbdkiosk", "decorations", "crafts", } diff --git a/textures/celevator_dbdkiosk.png b/textures/celevator_dbdkiosk.png new file mode 100644 index 0000000..87b64a7 Binary files /dev/null and b/textures/celevator_dbdkiosk.png differ -- cgit v1.2.3