This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Sewbacca's profile picture

os.standby

Started by Sewbacca, 15 March 2016 - 04:52 PM
Sewbacca #1
Posted 15 March 2016 - 05:52 PM
And NO, it isn't a suggestion,
I want to program it myself.

I want to program a standby function, and I had the following ideas:
  1. Save all events and play it queue all after a reboot
  2. Save _G with all functions, threads, tables, strings and other values in a file and jump to after the reboot point
And I had the following problems:
  1. Not all events were saved (I tested it with worms)
  2. There isn't a goto command

Have somebody any ideas or enhancement?
Edited on 15 March 2016 - 05:01 PM
KingofGamesYami #2
Posted 15 March 2016 - 06:51 PM
Persistence is impossible. I tried. I gave up after two or three hours.

A script has to be built to specifically handle it's own persistence. That's really all there is to it. You can't save functions from _G to a file. There is no way to implement a goto command. A program can do a number of things you cannot record nor replicate.
Edited on 15 March 2016 - 05:51 PM
Creator #3
Posted 15 March 2016 - 07:27 PM
Isn't a function technically just a bunch of bits in the RAM memory (RAS syndrome)? So if there was a way to get these bytes and write them to the HDD. Also you need locals, which are impossible to get without debug.
Sewbacca #4
Posted 15 March 2016 - 07:36 PM
Windows can save the content of the RAM into a file, so you can cut the power of the PC and after a restart, you will get the state before the standby back.
Dragon53535 #5
Posted 15 March 2016 - 08:20 PM
Yeah windows can, but this is CC in which the computers are severely limited with their interaction with the real computer. Also, like the others said, the debug library which allows you to view locals out of scope isn't available in CC which limits the amount of information you could save anyways.
Edited on 15 March 2016 - 07:20 PM
Sewbacca #6
Posted 15 March 2016 - 08:27 PM
And what about the events? What, if I simulate all actions of the user in fast motion?
Edited on 15 March 2016 - 07:30 PM
valithor #7
Posted 15 March 2016 - 08:31 PM
And what is with the events? What is when I simulate all actions from the user in fast motion?

You have to remember CC event queue can only hold 255 events. If anymore than 255 events are queued the new ones are lost. If that is not the case, then seeing your code would help.

With that said I decided to mess around with persistence, and will finish and post the code I came up with when I get home.
Creator #8
Posted 15 March 2016 - 08:34 PM
Well, but one program might append all the event data to a file. When you release the events again, the file will have duplicated events.
Lignum #9
Posted 15 March 2016 - 09:19 PM
Another way to do it is to implement Lua in Lua. All programs that shall be affected by standby would have to be run through this implementation. This allows you to track down exactly where the program left off, save all necessary state, and restore from that later on. If you want to pull this off, and trust me, it's no simple task, you should take a look at yueliang, which is an implementation of Lua 5 in Lua 5. Though is it really worth it? Any programs running in this implementation of Lua would likely be horribly slow as a consequence, and even getting it to work is an insane amount of effort just for this particular feature.

But why restore the exact state anyway? Wouldn't it make more sense for a standby to feed events to background activities exclusively?
valithor #10
Posted 15 March 2016 - 09:25 PM
Here is the very very basic example that I came up with. I seperated it into two files just for simplicity during testing. They could easily be modified into a single program if you so wished (run the one that reads the log file first, then delete log file, and run the one that records events).

I have done very basic tests with this, and from what I could tell it worked. If you find anything that does not please tell me.

Code that records the input and writes it to a file:

local yield = coroutine.yield
local resume = coroutine.resume

_ENV.coroutine.yield = function(...)
  local event = {yield(...)}
  if event[#event] ~= "Yield event" then
	local h = fs.open("log","a")
	h.writeLine(table.concat(event,";")..";")
	h.close()
  else
	event[#event] = nil
  end
  return unpack(event)
end

_ENV.coroutine.resume = function(co,...)
  local event = {...}
  event[#event+1] = "Yield event"
  return resume(co,unpack(event))
end

-- End logging

Code that reads the file and handles the events:

--fast foward

local h = fs.open("log","r")
local file = h.readAll()
h.close()

--Processing the file
local events = {}

for event in file:gmatch("(..-)\n") do
  local first = true
  for word in event:gmatch("(..-);") do
	if first then
	  events[#events+1] = {word}
	  first = false
	else
	  table.insert(events[#events],word)
	end
  end
end

--end processing

local oldRaw = os.pullEventRaw
local oldPullEvent = os.pullEvent

_ENV.os.pullEventRaw = function(filter,pullEvent)
  if #events == 0 then
	_ENV.os.pullEventRaw = oldRaw
	return oldRaw(filter)
  else
	for i = 1, #events do
	  if (events[1][1] == filter) or filter==nil then
        if pullEvent and events[1] == "terminate" then
          error("terminated")
        end
		local temp = events[1]
		table.remove(events,1)
		return unpack(temp)
	  else
		table.remove(events,1)
	  end
	end
	_ENV.os.pullEventRaw = oldRaw
	return oldRaw(filter)
  end
end

_ENV.os.pullEvent = function(filter)
  if #events == 0 then
	_ENV.os.pullEvent = oldPullEvent
	return oldPullEvent(filter)
  else
	return _ENV.os.pullEventRaw(filter,true)
  end
end

Keep in mind this is only half of what needs to be done to accomplish persistence. In order to achieve complete persistence it would be best to randomly seed math.random and save whatever you seeded it with. In addition things must be overwritten, such as fs.open. In order to have complete persistence, a copy of all files that are opened must be made, and fs.open should mess with those instead of the actual ones. There are a few other things that must be done, but recording and requeueing the events is the hardest part of it.

Edit: just going to note this is a proof of concept if anything. I can think of a few things that will break it, but this is to be used more of as a thing to look at to show it is possible.
Edited on 15 March 2016 - 08:56 PM
valithor #11
Posted 15 March 2016 - 11:31 PM
Got bored, so I decided to implement persistence for timers:

http://www.pastebin.com/x1E4bRGM
http://www.pastebin.com/vueFrKBd
Edited on 15 March 2016 - 10:31 PM
Sewbacca #12
Posted 16 March 2016 - 12:32 PM
xD And thanks
Edited on 16 March 2016 - 11:32 AM