From 6856fc39790ed0ec912148d7fff91a9b95808e65 Mon Sep 17 00:00:00 2001
From: cheapie <no-email-for-you@example.com>
Date: Fri, 18 Aug 2023 18:15:31 -0500
Subject: Assorted bug fixes

---
 controller.lua   | 11 ++++++++---
 controllerfw.lua | 29 +++++++++++++++++++++++++----
 drive_entity.lua | 23 ++++++++++++++++++++---
 drive_null.lua   |  5 +++++
 4 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/controller.lua b/controller.lua
index 3de026c..8d6b210 100644
--- a/controller.lua
+++ b/controller.lua
@@ -400,7 +400,7 @@ function celevator.controller.finddrive(pos)
 	return drivepos,minetest.registered_nodes[drivename]._celevator_drive_type
 end
 
-function celevator.controller.finish(pos,mem)
+function celevator.controller.finish(pos,mem,changedinterrupts)
 	if not celevator.controller.iscontroller(pos) then
 		return
 	else
@@ -416,9 +416,11 @@ function celevator.controller.finish(pos,mem)
 				elseif command.command == "estop" then
 					celevator.drives[drivetype].estop(drivepos)
 				elseif command.command == "open" then
-					celevator.drives[drivetype].movedoors(drivepos,"open")
+					minetest.after(0.25,celevator.drives[drivetype].movedoors,drivepos,"open")
 				elseif command.command == "close" then
 					celevator.drives[drivetype].movedoors(drivepos,"close")
+				elseif command.command == "resetfault" then
+					celevator.drives[drivetype].resetfault(drivepos)
 				end
 			end
 		end
@@ -479,7 +481,10 @@ function celevator.controller.finish(pos,mem)
 		meta:set_string("formspec_hidden",mem.formspec or "")
 		meta:set_string("infotext",mem.infotext or "")
 		local hash = minetest.hash_node_position(pos)
-		celevator.controller.iqueue[hash] = mem.interrupts
+		if not celevator.controller.iqueue[hash] then celevator.controller.iqueue[hash] = mem.interrupts end
+		for iid in pairs(changedinterrupts) do
+			celevator.controller.iqueue[hash][iid] = mem.interrupts[iid]
+		end
 		celevator.storage:set_string("controller_iqueue",minetest.serialize(celevator.controller.iqueue))
 		controllerleds(pos,mem.showrunning)
 		celevator.controller.running[hash] = nil
diff --git a/controllerfw.lua b/controllerfw.lua
index 9491396..abfc358 100644
--- a/controllerfw.lua
+++ b/controllerfw.lua
@@ -1,5 +1,7 @@
 local pos,event,mem = ...
 
+local changedinterrupts = {}
+
 local function fault(ftype,fatal)
 	if fatal then mem.fatalfault = true end
 	if not mem.activefaults then mem.activefaults = {} end
@@ -17,6 +19,8 @@ if not mem.drive.status then
 		vel = 0,
 		maxvel = 0,
 	}
+elseif mem.drive.status.fault then
+	fault("drive"..mem.drive.status.fault,true)
 end
 
 if mem.drive.state == "uninit" then
@@ -51,8 +55,13 @@ local doorstates = {
 }
 
 local faultnames = {
+	opentimeout = "Door Open Timeout",
+	closetimeout = "Door Close Timeout",
 	drivecomm = "Lost Communication With Drive",
 	driveuninit = "Drive Not Configured",
+	drivemetaload = "Drive Metadata Load Failure",
+	drivebadorigin = "Drive Origin Invalid",
+	drivedoorinterlock = "Attempted to Move Doors With Car in Motion",
 }
 
 local function drivecmd(command)
@@ -61,13 +70,16 @@ end
 
 local function interrupt(time,iid)
 	mem.interrupts[iid] = time
+	changedinterrupts[iid] = true
 end
 
-local function getpos()
+local function getpos(pioffset)
 	local ret = 0
+	local searchpos = mem.drive.status.apos
+	if pioffset then searchpos = math.max(0,searchpos+0.5) end
 	for k,v in ipairs(mem.params.floorheights) do
 		ret = ret+v
-		if ret > mem.drive.status.apos then return k end
+		if ret > searchpos then return k end
 	end
 	return mem.params.floorheights[#mem.params.floorheights]
 end
@@ -163,12 +175,14 @@ local function open()
 	mem.doorstate = "opening"
 	drivecmd({command = "open"})
 	interrupt(0.2,"checkopen")
+	interrupt(10,"opentimeout")
 end
 
 local function close()
 	mem.doorstate = "closing"
 	drivecmd({command = "close"})
 	interrupt(0.2,"checkclosed")
+	interrupt(10,"closetimeout")
 end
 
 mem.formspec = ""
@@ -374,6 +388,7 @@ elseif event.type == "ui" then
 			mem.faultlog = {}
 			mem.activefaults = {}
 			mem.fatalfault = false
+			drivecmd({command = "resetfault"})
 		end
 	end
 elseif event.iid == "opened" and mem.doorstate == "opening" then
@@ -409,15 +424,21 @@ elseif event.type == "callbutton" and mem.carstate == "normal" then
 elseif event.iid == "checkopen" then
 	if mem.drive.status.doorstate == "open" then
 		interrupt(0,"opened")
+		interrupt(nil,"opentimeout")
 	else
 		interrupt(0.2,"checkopen")
 	end
 elseif event.iid == "checkclosed" then
 	if mem.drive.status.doorstate == "closed" then
 		interrupt(0,"closed")
+		interrupt(nil,"closetimeout")
 	else
 		interrupt(0.2,"checkclosed")
 	end
+elseif event.iid == "opentimeout" then
+	fault("opentimeout",true)
+elseif event.iid == "closetimeout" then
+	fault("closetimeout",true)
 end
 
 local oldstate = mem.carstate
@@ -727,7 +748,7 @@ else
 	mem.showrunning = false
 end
 
-mem.pifloor = mem.params.floornames[getpos()]
+mem.pifloor = mem.params.floornames[getpos(true)]
 local hidepi = {
 	bfdemand = true,
 	uninit = true,
@@ -754,4 +775,4 @@ if mem.carstate == "normal" and (mem.doorstate == "open" or mem.doorstate == "op
 	mem.lanterns[getpos()] = mem.direction
 end
 
-return pos,mem
+return pos,mem,changedinterrupts
diff --git a/drive_entity.lua b/drive_entity.lua
index 6f4f988..74e58c8 100644
--- a/drive_entity.lua
+++ b/drive_entity.lua
@@ -208,7 +208,9 @@ function celevator.drives.entity.step(dtime)
 				local origin = minetest.string_to_pos(meta:get_string("origin"))
 				if not origin then
 					minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(pos))
+					meta:set_string("fault","badorigin")
 					table.remove(entitydrives_running,i)
+					return
 				end
 				if state == "start" then
 					sound = true
@@ -370,7 +372,7 @@ function celevator.drives.entity.getstatus(pos,call2)
 		return celevator.drives.null.get_status(pos,true)
 	elseif node.name ~= "celevator:drive" then
 		minetest.log("error","[celevator] [entity drive] Could not load drive status at "..minetest.pos_to_string(pos))
-		return
+		return {fault = "metaload"}
 	else
 		local meta = minetest.get_meta(pos)
 		local ret = {}
@@ -380,6 +382,8 @@ function celevator.drives.entity.getstatus(pos,call2)
 		ret.maxvel = tonumber(meta:get_string("maxvel")) or 0.2
 		ret.state = meta:get_string("state")
 		ret.doorstate = meta:get_string("doorstate")
+		ret.fault = meta:get_string("fault")
+		if ret.fault == "" then ret.fault = nil end
 		return ret
 	end
 end
@@ -387,11 +391,20 @@ end
 function celevator.drives.entity.movedoors(drivepos,direction)
 	local drivehash = minetest.hash_node_position(drivepos)
 	local entitydrives_running = minetest.deserialize(celevator.storage:get_string("entitydrives_running")) or {}
+	local drivemeta = minetest.get_meta(drivepos)
 	for _,hash in pairs(entitydrives_running) do
-		if drivehash == hash then return end
+		if drivehash == hash then
+			minetest.log("error","[celevator] [entity drive] Attempted to open doors while drive at "..minetest.pos_to_string(drivepos).." was still moving")
+			drivemeta:set_string("fault","doorinterlock")
+			return
+		end
 	end
-	local drivemeta = minetest.get_meta(drivepos)
 	local origin = minetest.string_to_pos(drivemeta:get_string("origin"))
+	if not origin then
+		minetest.log("error","[celevator] [entity drive] Invalid origin for drive at "..minetest.pos_to_string(drivepos))
+		drivemeta:set_string("fault","badorigin")
+		return
+	end
 	local apos = tonumber(drivemeta:get_string("apos")) or 0
 	local carpos = vector.add(origin,vector.new(0,apos,0))
 	local carnode = minetest.get_node(carpos)
@@ -411,6 +424,10 @@ function celevator.drives.entity.movedoors(drivepos,direction)
 	end
 end
 
+function celevator.drives.entity.resetfault(pos)
+	minetest.get_meta(pos):set_string("fault","")
+end
+
 local function carsearch(pos)
 	for i=1,500,1 do
 		local searchpos = vector.subtract(pos,vector.new(0,i,0))
diff --git a/drive_null.lua b/drive_null.lua
index 28c7e04..417d857 100644
--- a/drive_null.lua
+++ b/drive_null.lua
@@ -225,3 +225,8 @@ function celevator.drives.null.getstatus(pos,call2)
 		return ret
 	end
 end
+
+function celevator.drives.null.resetfault(pos)
+	--This drive has no possible faults at this time (drive communication faults are generated by the controller), but the controller expects to be able to call this
+	minetest.get_meta(pos):set_string("fault","")
+end
-- 
cgit v1.2.3