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

[1.21] Advert's Utilities (For Coders) + Matrix Screensaver

Started by Advert, 11 February 2012 - 05:50 AM
Advert #1
Posted 11 February 2012 - 06:50 AM
I'll post various utility functions I come up with here; if you spot any errors/problems, have any suggestions, or need some help, post away!

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:
SpoilerAssuming 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
end
6) 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.
matrix screensaver

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-=!@#$%^&amp;*()_+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-=!@#$%^&amp;*()_+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 on 11 February 2012 - 11:31 PM
Espen #2
Posted 11 February 2012 - 10:59 AM
Very nice contribution, you really made an effort for ease of use.
+1 for that, keep up the good work! :D/>/>
Advert #3
Posted 11 February 2012 - 01:35 PM
Very nice contribution, you really made an effort for ease of use.
+1 for that, keep up the good work! :D/>/>

Thank you, I'll add table support, and maybe a easier how-to after I finish my current project ^_^/>/>


Edit: Added a matrix-style screensaver.
Edited on 11 February 2012 - 04:17 PM
Advert #4
Posted 11 February 2012 - 09:45 PM
Updated matrix-style'd screensaved; now has some hidden messages (which you can read in the source), and updates less uniformly.
Rodizipa #5
Posted 14 February 2012 - 12:18 PM
:(/>/> CASPER
Advert #6
Posted 14 February 2012 - 01:15 PM
;)/>/> CASPER
I see you found one of the messages :(/>/>

Other than that, I'm redesigning lsave later on, once I'm not busy.
Rodizipa #7
Posted 14 February 2012 - 01:25 PM
an Advert, how i install the matrix ss ?
Advert #8
Posted 14 February 2012 - 01:53 PM
Grab it from pastebin, copy the code (there's a texbox with it under, you can click in and CTRL-A to select it all, then CTRL-C to copy it)
Find ".minecraft", where you can either put it on a computer, or on every computer:
For a single computer: (in .minecraft) "savesYOUR_WORLDcomputerYOUR COMPUTER ID"
For any computer: (in .minecraft) "modsComputerCraftluaromprograms"
In your selected directory (out of the two above),

make a new file and paste into it. save it as matrix-ss (no extension)

You can also save it to a disk, if you desire, just follow "For Any Computer", and instead of YOUR COMPUTER ID, use "diskYOUR DISK ID"
Sithus #9
Posted 07 July 2012 - 09:07 AM
So how would I go about displaying the matrix screensaver onto a monitor screen?