Posted 01 July 2013 - 12:14 PM
Hi, hello and good day. I apologize for my first post being a question, but I'm also offering a workaround (for my particular requirements) which might help others, so I hope it's excusable. Short disclaimer: I did search the forums using the in-built search, google and browsing manually, but did not find any topics addressing my problem explicitly, so I'm pretty confident this is not a duplicate of some EAQ list entry. If it is, please, show me the way :)/>
To the point: I've recently been getting into the perilous topic that is persistency in Lua in general, and in ComputerCraft in particular. In my research, I've come across some posts indicating that events should actually "survive" across saving/quitting a world and reloading it (or chunk unloading/reloading). The posts in question are:
- immibis on state saving
- Cloudy commenting on the event queue
Since one of the two is from a ComputerCraft developer, I was quite hopeful. But after some unsuccessful experimentation I decided to have a peek at the Java side of things (I hope this is not considered rude, it was done truly only with the goal of understanding event persistency in mind). From what I saw, the event queue is stored without the expected response IDs for the individual "commands". This results in them having a response ID of -1 after reloading the world, and thus no event will be dispatched on the Lua side.
Therefore my question: is this intended behavior, and if so, for what reason? Storage size/bandwidth? It seems to me that saving the response IDs would not be that bad of an overhead, plus it could even be patched in without breaking backwards compatibility (if it's not present in the save, just fall back to -1). If it is not intended behavior, how do the chances stand of this being fixed anytime soon?
Finally, my workaround: I only needed this in the context of persistently storing a Turtle's position. Somewhat along the lines of what immibis wrote, although a little more simplistic (native call, save id, wait for event; if set when loading wait for event on startup). Seeing as this won't work, here's what I've decided to do instead: check the fuel. This obviously only works if the turtles use fuel (but seriously, why wouldn't they). The basic idea is: save the fuel state before issuing the move command, if there's a reboot while moving wait at the startup for a bit, then check if the fuel level changed. Since only successful moves consume (exactly one) fuel, this is a pretty good indicator as to whether the last movement command was successful or not. It works really well for me, but at the same time is hardly satisfactory, given its hacky nature.
Anyway, I'd be happy to get some official feedback on the not-dispatching-events-for-pending-commands-after-reloads thing. Thanks!
PS: I'm using the latest version at this date, 1.53. Also, though I don't think it's really necessary, here's the (simplified) code I've tested with.
Event driven and broken:
Workaround:
Edit: fixed a derp in the code samples (missing success check around updateState()).
Edit 2: I built a small API based on the mentioned workaround.
To the point: I've recently been getting into the perilous topic that is persistency in Lua in general, and in ComputerCraft in particular. In my research, I've come across some posts indicating that events should actually "survive" across saving/quitting a world and reloading it (or chunk unloading/reloading). The posts in question are:
- immibis on state saving
- Cloudy commenting on the event queue
Since one of the two is from a ComputerCraft developer, I was quite hopeful. But after some unsuccessful experimentation I decided to have a peek at the Java side of things (I hope this is not considered rude, it was done truly only with the goal of understanding event persistency in mind). From what I saw, the event queue is stored without the expected response IDs for the individual "commands". This results in them having a response ID of -1 after reloading the world, and thus no event will be dispatched on the Lua side.
Therefore my question: is this intended behavior, and if so, for what reason? Storage size/bandwidth? It seems to me that saving the response IDs would not be that bad of an overhead, plus it could even be patched in without breaking backwards compatibility (if it's not present in the save, just fall back to -1). If it is not intended behavior, how do the chances stand of this being fixed anytime soon?
Finally, my workaround: I only needed this in the context of persistently storing a Turtle's position. Somewhat along the lines of what immibis wrote, although a little more simplistic (native call, save id, wait for event; if set when loading wait for event on startup). Seeing as this won't work, here's what I've decided to do instead: check the fuel. This obviously only works if the turtles use fuel (but seriously, why wouldn't they). The basic idea is: save the fuel state before issuing the move command, if there's a reboot while moving wait at the startup for a bit, then check if the fuel level changed. Since only successful moves consume (exactly one) fuel, this is a pretty good indicator as to whether the last movement command was successful or not. It works really well for me, but at the same time is hardly satisfactory, given its hacky nature.
Anyway, I'd be happy to get some official feedback on the not-dispatching-events-for-pending-commands-after-reloads thing. Thanks!
PS: I'm using the latest version at this date, 1.53. Also, though I don't think it's really necessary, here's the (simplified) code I've tested with.
Event driven and broken:
Spoiler
local x,y,z,facing,moving,moveId=0,0,0,0,false,-1
function save() --[[ saves all state variables ]] end
function load() --[[ loads all state variables ]] end
-- moveFunction is a native (forward, back, up, down) and direction is for
-- keeping track where we are going to update our state after the move.
function beginMove(moveFunction,direction)
moveId = moveFunction()
if moveId == -1 then return false end
moving = direction
save()
return finishMove()
end
function finishMove()
local event, responseID, success
while event ~= "turtle_response" or responseID ~= moveId do
event, responseID, success = os.pullEvent("turtle_response")
end
-- Updates x,y,z based on movement type and facing.
if success then updateState() end
moving = false
moveId = -1
save()
return success
end
load()
if moving then finishMove() end
-- Imagine some code for continually moving the turtle in a circle.
moveInCircle()
Workaround:
Spoiler
local x,y,z,facing,moving,preMoveFuel=0,0,0,0,false,0
function save() --[[ saves all state variables ]] end
function load() --[[ loads all state variables ]] end
function beginMove(moveFunction,direction)
preMoveFuel = turtle.getFuelLevel()
local moveId = moveFunction()
if moveId == -1 then return false end
moving = direction
save()
return finishMove(moveId)
end
function finishMove(moveId)
local success
if moveId >= 0 then
local event, responseID
while event ~= "turtle_response" or responseID ~= moveId do
event, responseID, success = os.pullEvent("turtle_response")
end
else
-- Wait until we are sure we could have finished an active move.
os.sleep(1)
if preMoveFuel == turtle.getFuelLevel() then
success = false
else
-- Possibly some more checks here (that we did not move more than once or refueled).
success = true
end
end
-- Updates x,y,z based on movement type and facing.
if success then updateState() end
moving = false
save()
return success
end
load()
if moving then finishMove(-1) end
-- Imagine some code for continually moving the turtle in a circle.
moveInCircle()
Edit: fixed a derp in the code samples (missing success check around updateState()).
Edit 2: I built a small API based on the mentioned workaround.