lsave
Licence: MIT/x11 (no need to have the entire licence text; the two comments detailing this are sufficient; please add "modified" before "lsave" if you do modify it, though.)
What it is: Data saving utility; saves data as lua text to a file. (You can easily read and edit from the file, but it's up to you to check that the re-loaded data is acceptable)
Code (NOT api)
On pastebin (may be more up to date; forum topic = effort + breaks indentation)
Spoiler
local lsave = {} -- will carry the public functions; loadfile does not like globals :/ function lsave.load(sFile) -- This function will check that lsave saved the file in the future. if not fs.exists(sFile) then return false, "nofile" end -- We can't load a file that doesn't exist. local hHandle = io.open(sFile, "r") local err, res = pcall(function() return setfenv(loadfile(sFile),getfenv())() end) if not err then return false, res end return true, res end -- Saving helper format strings/functions lsave.types = {} lsave.types.boolean = "data[%q] = %s" lsave.types.string = "data[%q] = %q" lsave.types.number = "data[%q] = %d" -- Saving function function lsave.save(sFile, data) if type(sFile) ~= "string" or type(data) ~= "table" then return false, "Invalid arguments" end local sData = "local data = {} -- This file, generated by lsave 0.5. Edit at your own risk.\n\n" for k, v in pairs(data) do local sDataType = type(v) local saveHelper = lsave.types[sDataType] if not saveHelper then -- We have problem, let's just print it, and continue without saving it. print("Warning: (saveToFile) unknown data type (ignoring), in key: " .. k) else -- No errors, save it. if type(saveHelper) == "string" then sData = sData .. string.format(saveHelper, k, tostring(v)) .. "\n" elseif type(saveHelper) == "function" then -- For the future, and custom stuff. sData = sData .. saveHelper(k, v) .. "\n" end end end sData = sData .. "\nreturn data" -- We need to return the config in order to retrieve it. -- Delete and save. local hHandle, err = io.open(sFile, "w") if not hHandle then return false, err end hHandle:write(sData) hHandle:close() return true end return lsave -- This, so you can do "lsave = loadfile("lsave")()" -- Remove the line if you want to just paste it in your program, instead.
How to use:
Spoiler
Assuming your program is on a computer's root directory:
1) Copy code from codeblock or pastebin;
2) (ingame) Get your computer (or disk's) ID (type 'id' at the shell)
3) Make a new file called 'lsave', and paste into it.
4) Move file to yourminecraftdir/saves/yoursavename/computer/yourcomputerid OR disk/yourdiskid
5) In your program, add (somewhere at the top, i.e before you attempt to use it, and so it only gets called once):
To save:
To load:
Note: This is best "merged" with default values, let's assume the above code comes before this:
I know, this is not the best example, but you should get the point.
matrix screensaverAssuming your program is on a computer's root directory:
1) Copy code from codeblock or pastebin;
2) (ingame) Get your computer (or disk's) ID (type 'id' at the shell)
3) Make a new file called 'lsave', and paste into it.
4) Move file to yourminecraftdir/saves/yoursavename/computer/yourcomputerid OR disk/yourdiskid
5) In your program, add (somewhere at the top, i.e before you attempt to use it, and so it only gets called once):
local lsave do local loadFunc, err = loadfile("lsave") if type(loadFunc) == "function" then lsave = loadFunc() else error(err) end end6) To load/save values (currently only supporting strings, booleans, and numbers):
To save:
local tableOfThingsToSave = {} tableOfThingsToSave["yourStringName"] = "I am a string." tableOfThingsToSave["yourBooleanName"] = true tableOfThingsToSave["yourNumberName"] = 42 local isSaved, err = lsave.save("yourdatafilename", tableOfThingsToSave) if isSaved then -- Save Successful else -- Save failed, error is 'err': print("Failed saving! error: ", err) end
To load:
Note: This is best "merged" with default values, let's assume the above code comes before this:
local function mergeTable(t1, t2) -- This function lets us impose t2's values onto t1, meaning that if something is missing from t2, t1 will have a default. for k, v in pairs(t2) t1[k] = v end return t1 end local isLoaded, loadedData = lsave.load("yourdatafilename") if not isLoaded then if not loadedData == "nofile" then -- Don't error if the file doesn't exist! -- We couldn't load (and the file exists), loadedData is the error error("Failed loading! error: ", loadedData) end else -- We don't want to attempt to merge if nothing was loaded. tableOfThingsToSave = mergeTable(tableOfThingsToSave, loadedData) end -- You can now access tableOfThingsToSave["yourString"].
I know, this is not the best example, but you should get the point.
Pastebin: http://pastebin.com/ZXeRgLHt (not commented, will upon request)
-- Too lazy to detail instructions as of now.
-- Except that you can press spacebar to return nicely.
0.8:
now has some hidden messages (which you can read in the source), and updates less uniformly.
Spoiler
-- Matrix screensaver v0.8 -- (C) 2012 User 'Advert' at http://www.computercraft.info/forums2/ -- X11/mit licence (use/modify at your will, but please, leave credit where due) -- Spacebar to quit cleanly! local mobj = {} do -- Standart variables. mobj.x = 0 mobj.y = 0 -- Offscreen mobj.lingerMin = 3 -- Minimum time to linger (frames) mobj.lingerMax = 10 -- Maximum time to linger mobj.linger = 10 -- How long this object will linger mobj.tailLenMin = 3 -- Minimum tail length mobj.tailLenMax = 10 -- Maximum tail length mobj.tailLen = 10 mobj.chars = "1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;'\\ASDFGHJKL:\"|zxcvbnm,./ZXCVBNM<>?" mobj.charsLen = mobj.chars:len() mobj.currentTail = {"a", "a", "a", "a", "a", "a", "a", "a", "a", "a"} mobj.secretText = {} mobj.skipFrame = 0 mobj.skipFrameMin = 1 mobj.skipFrameMax = 3 mobj.skipFrameMod = -1 mobj.currFrame = 0 end function mobj:new(o, ...) local o = o or {} setmetatable(o, self) self.__index = self o:__init(...) return o end function mobj:__init(x) self.linger = math.random(self.lingerMin, self.lingerMax) self.tailLen = math.random(self.tailLenMin, self.tailLenMax) self.x = x self.y = 1 self.nFrame = 1 self.currentTail = {} self.skipFrame = math.random(self.skipFrameMin, self.skipFrameMax) + self.skipFrameMod end function mobj:randomLinger() self.linger = math.random(self.lingerMin, self.lingerMax) end function mobj:printPos(x, y, sText) term.setCursorPos(x, y) term.write(sText) end function mobj:printPosT(x, y, sText) if self.secretText[y] and self.secretText[y][x] then sText = self.secretText[y][x] end return self:printPos(x, y, sText) end function mobj:randomChar() local r = math.random(1, self.charsLen) return string.sub(self.chars, r, r) end function mobj:printTail() for i = 1, self.tailLen do if not self.currentTail[i] then break end self:printPosT(self.x, self.y - i, self.currentTail[i]) end end local termX, termY = term.getSize() do for y = 1, termY do mobj.secretText[y] = {} end function mobj:addSecretText(x, y, sText) if sText:len() + x > termX then -- lolno. else for i = 1, sText:len() do local chr = sText:sub(i, i) self.secretText[y][x + i-1] = chr end end end function mobj:addSecretTextD(x, y, dir, sText) -- 1 = bottomright, 2 = bottomleft, 3 = topright, 4 = topleft local xmod = dir %2 == 1 and 1 or -1 local ymod = (dir == 1 or dir == 2) and 1 or -1 local finalx, finaly = x + (xmod * sText:len()), y + (ymod *sText:len()) --print("finalx, finaly", finalx, finaly) --read() local cx, cy = x, y for i = 1, sText:len() do local cx, cy = x + (xmod * (i -1)), y + (ymod * (i -1)) if self.secretText[cy] then self.secretText[cy][cx] = sText:sub(i, i) end end end end function mobj:render() self:printTail() local sSkip = false if self.currFrame ~= self.skipFrame then self.currFrame = self.currFrame + 1 else self.currFrame = 0 self.nFrame = self.nFrame + 1 if self.nFrame == self.linger then table.insert(self.currentTail, 1, self.lastRandomChar) self:printPosT(self.x, self.y, self.currentTail[1]) self.y = self.y + 1 self.nFrame = 1 if self.y > termY + self.tailLen then self:__init(self.x) end sSkip = true else self.lastRandomChar = self:randomChar() end end if not sSkip then self:printPos(self.x, self.y, self.lastRandomChar) end end local objects = {} local eventT function init() for i = 1, termX do objects[i] = mobj:new({}, i) end eventT = os.startTimer(0) end function render() term.clear() for _, k in pairs(objects) do k:render() end end mobj:addSecretTextD(15, 4, 1, "Casper7526") mobj:addSecretTextD(18, 4, 1, "made me") mobj:addSecretTextD(21, 4, 1, "do this.") mobj:addSecretText(15, 15, "Spacebar to exit.") init() while true do local e, p1, p2 = os.pullEvent() if e == "timer" and p1 == eventT then eventT = os.startTimer(0.05) -- 20 fps render() elseif e == "key" and p1 == 57 then term.clear() term.setCursorPos(1,1) break end end
0.7:
Spoiler
-- Matrix screensaver v0.7 -- (C) 2012 User 'Advert' at http://www.computercraft.info/forums2/ -- X11/mit licence (use/modify at your will, but please, leave credit where due) -- Spacebar to quit cleanly! local mobj = {} do -- Standart variables. mobj.x = 0 mobj.y = 0 -- Offscreen mobj.lingerMin = 3 -- Minimum time to linger (frames) mobj.lingerMax = 10 -- Maximum time to linger mobj.linger = 10 -- How long this object will linger mobj.tailLenMin = 3 -- Minimum tail length mobj.tailLenMax = 10 -- Maximum tail length mobj.tailLen = 10 mobj.chars = "1234567890-=!@#$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;'\\ASDFGHJKL:\"|zxcvbnm,./ZXCVBNM<>?" mobj.charsLen = mobj.chars:len() mobj.currentTail = {"a", "a", "a", "a", "a", "a", "a", "a", "a", "a"} end function mobj:new(o, ...) local o = o or {} setmetatable(o, self) self.__index = self o:__init(...) return o end function mobj:__init(x) self.linger = math.random(self.lingerMin, self.lingerMax) self.tailLen = math.random(self.tailLenMin, self.tailLenMax) self.x = x self.y = 1 self.nFrame = 1 self.currentTail = {} end function mobj:randomLinger() self.linger = math.random(self.lingerMin, self.lingerMax) end local function printPos(x, y, sText) term.setCursorPos(x, y) term.write(sText) end function mobj:randomChar() local r = math.random(1, self.charsLen) return string.sub(self.chars, r, r) end function mobj:printTail() for i = 1, self.tailLen do if not self.currentTail[i] then break end printPos(self.x, self.y - i, self.currentTail[i]) end end local termX, termY = term.getSize() function mobj:render() self:printTail() self.nFrame = self.nFrame + 1 if self.nFrame == self.linger then table.insert(self.currentTail, 1, self:randomChar()) printPos(self.x, self.y, self.currentTail[1]) self.y = self.y + 1 self.nFrame = 1 if self.y > termY + self.tailLen then self:__init(self.x) end else printPos(self.x, self.y, self:randomChar()) end end local objects = {} local eventT function init() for i = 1, termX do objects[i] = mobj:new({}, i) end eventT = os.startTimer(0) end function render() term.clear() for _, k in pairs(objects) do k:render() end end init() while true do local e, p1, p2 = os.pullEvent() if e == "timer" and p1 == eventT then eventT = os.startTimer(0.05) -- 20 fps render() elseif e == "key" and p1 == 57 then term.clear() term.setCursorPos(1,1) break end end
Edited by Advert, 12 February 2012 - 12:31 AM.