Posted 12 October 2013 - 07:24 AM
Hello, I've just recently finished my first 'major' project with OpenPeripheral, it was working fine and dandy for about a week until it decided that 'num' had suddenly become a function.
Problematic Function:
Full code:
The program is meant to compare a list of ME system items with a user-input list of items, assign names to matched items, print their quantities, calculate deltaQuantities and give an ETA based on delta and current quantity.
Issues arise when the program tries to serialize the current user-input list of tracked items (trackedItemsdat).
Logically the only items that should ever end up on the list are coming from tonumber(arg2) and tostring(arg3). Furthermore what baffles me is that it adds and saves the first tracked item fine, and were you to terminate it there, restart, and add another item - everything works as intended, but add a second and suddenly serialize finds a function somewhere in trackedItemsdat.
I'm really confused as to why this is happening, especially because it was working fine running for 5 days straight chunkloaded, until I came back from afk to this error:
parallel: 22: textutils: 166: Cannot serialize type function.
The code was not modified prior to that.
I then loaded a better Serialize program I found here as 'slize' to see if the server changed/updated the textutils in rom, but only to get the same error. So it seems somehow a function is indeed making it's way into trackedItemsdat and I can't track it down. I've even tried to iterate-print the whole list and it didn't seem to print any functions.
Please help me in my struggles, as it is my first bigger CC project I made from scratch, if anyone with a fresh perspective on the code could locate the problem, I would be deeply grateful.
Thanks for taking time to read this in advance :)/>
Problematic Function:
Spoiler
filename = "tracked_items.mhb"
local trackedItems = {}
local trackedItemsdat = {}
if fs.exists(filename) then
f = fs.open(filename,"r")
data = f.readLine()
if data ~= nil then
trackedItemsdat = textutils.unserialize(data)
trackedItems = textutils.unserialize(data)
end
else
f = fs.open(filename,"w")
f.close()
end
local offset = 10
local MEItems = {}
local mOffset = 10
local tItem = {}
local acolor = 0xFFFFFF
local eta = 0
local etamsg = ""
local index = 256
local cIndex = 256
local avg = 0
function MManage()
while true do
event, msg = os.pullEvent("chat_command")
data = {}
iter = 1
for i in string.gmatch(msg,"%S+") do
data["arg"..iter] = i
iter = iter + 1
end
arg1 = data["arg1"]
arg2 = data["arg2"]
arg3 = data["arg3"]
outcolor = 0xFF0000
outtext = " "
if arg1 == "add" then
print("add detected. arg1:"..arg1.." arg2:"..arg2.." arg3"..arg3)
local num = tonumber(arg2)
match = nil
for i in string.gmatch(arg2,":") do
match = i
end
if match == ":" then
print(" a : found")
tmeta = {}
for i in string.gmatch(arg2,"%d+") do
table.insert(tmeta,i)
end
id = tonumber(tmeta[1])
meta = tonumber(tmeta[2])
print("id: "..id.." meta: "..meta)
if meta and id then
num = id + (meta * 32768)
end
end
if num then
str = tostring(arg3)
if str then
num = tonumber(num)
ins = {["id"] = num,["name"] = str}
table.insert(trackedItems,ins)
table.insert(trackedItemsdat,ins)
for i=1,#trackedItemsdat do
for i,o in pairs(trackedItemsdat[i]) do
print(o)
end
print(trackedItemsdat[i])
end
f = fs.open(filename,"w")
wrt = textutils.serialize(trackedItemsdat)
f.writeLine(wrt)
f.close()
end
else
outtext = "Error: argument#2 must be a real number."
outcolor = 0xFF0000
end
end
if arg1 == "remove" or arg1 == "delete" then
str = tostring(arg2)
if str then
success = false
for i=#trackedItems,1,-1 do
dItem = trackedItems[i]
if dItem["name"] == str then
dItem["txlabel"].delete()
dItem["txamount"].delete()
dItem["txdam"].delete()
dItem["eta"].delete()
dItem["txlabel"] = nil
dItem["txamount"] = nil
dItem["txdam"] = nil
dItem["eta"] = nil
table.remove(trackedItems,i)
for o=i,#trackedItems do
dItem = trackedItems[o]
y = dItem["txlabel"].getY()
dItem["txlabel"].setY(y-5)
dItem["txamount"].setY(y-5)
dItem["txdam"].setY(y-5)
dItem["eta"].setY(y-5)
end
end
end
for i=#trackedItemsdat,1,-1 do
dItem = trackedItemsdat[i]
if dItem["name"] == str then
table.remove(trackedItemsdat,i)
f = fs.open(filename,"w")
wrt = textutils.serialize(trackedItemsdat)
f.writeLine(wrt)
f.close()
success = true
end
end
if success then
outcolor = 0x00FF00
outtext = "Item removed.."
else
outcolor = 0xFFFF00
outtext = "Item not found!"
end
end
end
error.setColor(outcolor)
error.setText(outtext)
sleep(4)
error.setText(" ")
end
end
Full code:
Spoiler
local bridge = peripheral.wrap("left")
local net = peripheral.wrap("right")
os.loadAPI("m")
rednet.open("right")
bridge.clear()
local width = 70
local storageUnits = {
{
["id"] = "batbox_1",
["name"] = "Main Power",
["set"] = 1,
["main"] = true
},
{
["id"] = "batbox_2",
["name"] = "Main2",
["set"] = 1,
["main"] = false
},
{
["id"] = "batbox_3",
["name"] = "Main3",
["set"] = 1,
["main"] = false
},
{
["id"] = "batbox_4",
["name"] = "Main4",
["set"] = 1,
["main"] = false
}
}
local offset = 0
--for key, storageUnit in pairs(storageUnits) do
storageUnit = storageUnits[1]
pxOffset = 100 + offset * 20
storageUnit["eu"] = bridge.addText(5,20 + pxOffset, "retrieving..", 0xFFFFFF)
storageUnit["eu"].setScale(0.5)
storageUnit["eu"].setZIndex(1)
storageUnit["percent"] = bridge.addText(5, 15 + pxOffset, "connecting...", 0xFFFFFF)
storageUnit["percent"].setScale(0.5)
storageUnit["percent"].setZIndex(1)
storageUnit["bar"] = bridge.addGradientBox(4, 14 + pxOffset, 0, 10, 0xCC0000, 0.7, 0xCC0000, 0.7, 2)
storageUnit["bar"].setZIndex(0)
storageUnit["bg"] = bridge.addBox(5, 14 + pxOffset, width, 10, 0x000000, 0.25)
storageUnit["horline1"] = bridge.addBox(3, 13 + pxOffset, width+2, 1, 0x555555, 0.5)
storageUnit["horline2"] = bridge.addBox(3, 24 + pxOffset, width+2, 1, 0x555555, 0.5)
storageUnit["verline1"] = bridge.addBox(3, 14 + pxOffset, 1, 10, 0x555555, 0.5)
storageUnit["verline2"] = bridge.addBox(4+width, 14 + pxOffset, 1, 10, 0x555555, 0.5)
storageUnit["label"] = bridge.addText(4, 4 + pxOffset, storageUnit["name"], 0xFFFFFF)
for key, storageUnit in pairs(storageUnits) do
storageUnit["last2"] = 0
storageUnit["last3"] = 0
storageUnit["last4"] = 0
storageUnit["last5"] = 0
storageUnit["last6"] = 0
storageUnit["last7"] = 0
storageUnit["last8"] = 0
storageUnit["last9"] = 0
storageUnit["last10"] = 0
storageUnit["last11"] = 0
storageUnit["last12"] = 0
storageUnit["last13"] = 0
storageUnit["last14"] = 0
storageUnit["last15"] = 0
storageUnit["last16"] = 0
storageUnit["last%"] = 0
storageUnit["curr%"] = 0
end
storageUnit = storageUnits[1]
storageUnit["deltaEU"] = bridge.addText(35, 15 + pxOffset, "+~", 0xFFFFFF)
storageUnit["deltaEU"].setScale(0.5)
storageUnit["deltaEU"].setZIndex(1)
offset = offset + 1
--end
local fabstate = false
rednet.broadcast("massfab_off")
local cnt = 0
function main()
while true do
--for i=#storageUnits,1,-1 do
storageUnit = storageUnits[1]
if net.isPresentRemote(storageUnit["id"]) then
capacity = net.callRemote(storageUnit["id"], "getCapacity")
amount = net.callRemote(storageUnit["id"], "getStored")
end
storageUnit = storageUnits[2]
if net.isPresentRemote(storageUnit["id"]) then
capacity2 = net.callRemote(storageUnit["id"], "getCapacity")
amount2 = net.callRemote(storageUnit["id"], "getStored")
end
storageUnit = storageUnits[3]
if net.isPresentRemote(storageUnit["id"]) then
capacity3 = net.callRemote(storageUnit["id"], "getCapacity")
amount3 = net.callRemote(storageUnit["id"], "getStored")
end
storageUnit = storageUnits[4]
if net.isPresentRemote(storageUnit["id"]) then
capacity4 = net.callRemote(storageUnit["id"], "getCapacity")
amount4 = net.callRemote(storageUnit["id"], "getStored")
end
storageUnit = storageUnits[1]
maxcap = capacity + capacity2 + capacity3 + capacity4
curamount = amount + amount2 + amount3 + amount4
cnt = curamount / maxcap
cnt = m.round(tonumber(cnt*10),3)
cnt = tonumber(cnt/10)
if cnt == 1 and fabstate == false then
rednet.broadcast("massfab_on")
storageUnit["verline1"].setColor(0xFF22FF)
storageUnit["verline2"].setColor(0xFF22FF)
storageUnit["horline1"].setColor(0xFF22FF)
storageUnit["horline2"].setColor(0xFF22FF)
fabstate = true
end
if cnt < 0.9 and fabstate == true then
rednet.broadcast("massfab_off")
storageUnit["verline1"].setColor(0x555555)
storageUnit["verline2"].setColor(0x555555)
storageUnit["horline1"].setColor(0x555555)
storageUnit["horline2"].setColor(0x555555)
fabstate = false
end
local deu = 0
storageUnit = storageUnits[1]
storageUnit["curr%"] = amount
storageUnit = storageUnits[2]
storageUnit["curr%"] = amount2
sotrageUnit = storageUnits[3]
storageUnit["curr%"] = amount3
storageUnit = storageUnits[4]
storageUnit["curr%"] = amount4
for i=1,4 do
storageUnit = storageUnits[i]
storageUnit["last16"] = storageUnit["last15"]
storageUnit["last15"] = storageUnit["last14"]
storageUnit["last14"] = storageUnit["last13"]
storageUnit["last13"] = storageUnit["last12"]
storageUnit["last12"] = storageUnit["last11"]
storageUnit["last11"] = storageUnit["last10"]
storageUnit["last10"] = storageUnit["last9"]
storageUnit["last9"] = storageUnit["last8"]
storageUnit["last8"] = storageUnit["last7"]
storageUnit["last7"] = storageUnit["last6"]
storageUnit["last6"] = storageUnit["last5"]
storageUnit["last5"] = storageUnit["last4"]
storageUnit["last4"] = storageUnit["last3"]
storageUnit["last3"] = storageUnit["last2"]
storageUnit["last2"] = storageUnit["last%"]
storageUnit["last%"] = storageUnit["curr%"]
deu16 = storageUnit["last15"] - storageUnit["last16"]
deu15 = storageUnit["last14"] - storageUnit["last15"]
deu14 = storageUnit["last13"] - storageUnit["last14"]
deu13 = storageUnit["last12"] - storageUnit["last13"]
deu12 = storageUnit["last11"] - storageUnit["last12"]
deu11 = storageUnit["last10"] - storageUnit["last11"]
deu10 = storageUnit["last9"] - storageUnit["last10"]
deu9 = storageUnit["last8"] - storageUnit["last9"]
deu8 = storageUnit["last7"] - storageUnit["last8"]
deu7 = storageUnit["last6"] - storageUnit["last7"]
deu6 = storageUnit["last5"] - storageUnit["last6"]
deu5 = storageUnit["last4"] - storageUnit["last5"]
deu4 = storageUnit["last3"] - storageUnit["last4"]
deu3 = storageUnit["last2"] - storageUnit["last3"]
deu2 = storageUnit["last%"] - storageUnit["last2"]
deu1 = storageUnit["curr%"] - storageUnit["last%"]
deu = deu + (deu1 + deu2 + deu3 + deu4 + deu5 + deu6 + deu7 + deu8 + deu9 + deu10 + deu11 + deu12 + deu13 + deu14 + deu15 + deu16) / 16
deu = deu - 0
end
deu = deu / 10
storageUnit = storageUnits[1]
deu = m.round(tonumber(deu),2)
deu = tonumber(deu)
deutxt = deu.."eu/t"
if deu > 0 then deutxt = "+"..deu.."eu/t" end
if storageUnit["last16"] == 0 then deutxt = "averaging.." end
storageUnit["deltaEU"].setText(deutxt)
local color = 0x00FF00
local color2 = 0x00FF00
local colorp = 0x00FF00
local colort = 0xFFFFFF
if cnt == 1 then
color = 0x00FFFF
color2 = 0x3366FF
colorp = 0x992299
colort = colorp
end
if cnt < 1 and cnt >= 0.9 then
color = 0x00FF33
color2 = 0x00FFFF
colorp = 0x00FFFF
colort = 0x00FFFF
end
if cnt < 0.9 and cnt >= 0.6 then
color = 0x00FF00
color2 = 0x33FF00
colorp = 0xFFFFFF
colort = colorp
end
if cnt < 0.6 and cnt >= 0.3 then
color = 0x44FF00
color2 = 0xFFFF00
colorp = 0xFFFFFF
colort = colorp
end
if cnt < 0.3 and cnt >= 0.1 then
color = 0xFFFF00
color2 = 0xFF6600
colorp = 0xFFFF44
colort = colorp
end
if cnt < 0.1 then
color = 0xFF0000
color2 = 0x440000
colorp = 0xFF5500
colort = colorp
end
if fabstate == true then
color = 0x00FFFF
color2 = 0x3366FF
colorp = 0x992299
colort = 0x992299
end
storageUnit["eu"].setText(curamount.." / "..maxcap)
storageUnit["eu"].setColor(colort)
storageUnit["deltaEU"].setColor(colorp)
storageUnit["bar"].setColor(color)
storageUnit["bar"].setColor2(color2)
storageUnit["bar"].setWidth(width * cnt)
tx = cnt * 100
storageUnit["percent"].setText(tx.."%")
storageUnit["percent"].setColor(colort)
sleep(0.5)
end
end
local time = 0
function timer()
time = 0
fabtime = 0
fulltime = 0
while true do
term.setBackgroundColor(colors.blue)
term.setTextColor(colors.yellow)
--term.clear()
term.setCursorPos(1,1)
-- print("Time running: "..time)
term.setTextColor(colors.purple)
-- print("Massfab time: "..fabtime)
term.setTextColor(colors.orange)
wastage = fulltime*92*20
-- print("Potential energy wasted: "..wastage.."eu")
if fabstate == true then
fabtime = fabtime + 1
end
if cnt == 1 then
fulltime = fulltime + 1
end
time = time + 1
sleep(1)
end
end
filename = "tracked_items.mhb"
local trackedItems = {}
local trackedItemsdat = {}
if fs.exists(filename) then
f = fs.open(filename,"r")
data = f.readLine()
if data ~= nil then
trackedItemsdat = textutils.unserialize(data)
trackedItems = textutils.unserialize(data)
end
else
f = fs.open(filename,"w")
f.close()
end
local offset = 10
local MEItems = {}
local mOffset = 10
local tItem = {}
local acolor = 0xFFFFFF
local eta = 0
local etamsg = ""
local index = 256
local cIndex = 256
local avg = 0
function MScan()
me = peripheral.wrap("back")
while true do
if time < index then
cIndex = time
else
cIndex = index
end
if trackedItems ~= nil then
increment = 0
for key, tItem in pairs(trackedItems) do
print("name: "..tItem["name"])
print("id: "..tItem["id"])
mOffset = 10 + increment
mpxOffset = mOffset * 5 + 195
increment = increment + 1
if tItem["time"] == nil then
tItem["time"] = 0
end
if tItem["eta"] == nil then
tItem["eta"] = bridge.addText(86, 4 + mpxOffset, etamsg, 0x3333FF)
tItem["eta"].setScale(0.5)
end
if tItem["txlabel"] == nil then
tItem["txlabel"] = bridge.addText(4, 4 + mpxOffset, tItem["name"],0xFFFFFF)
tItem["txlabel"].setScale(0.5)
end
if tItem["txamount"] == nil then
tItem["txamount"] = bridge.addText(34, 4 + mpxOffset, "loadin'",0xFFFFFF)
tItem["txamount"].setScale(0.5)
end
if tItem["txdam"] == nil then
tItem["txdam"] = bridge.addText(62, 4 + mpxOffset, "calculatin'",0xFFFFFF)
tItem["txdam"].setScale(0.5)
end
if tItem["avg"] == nil then
tItem["avg"] = 0.069
end
if tItem["am"..index] == nil then
for i=1,index do
tItem["am"..i] = 0
end
end
mOffset = mOffset + 1
end
end
if trackedItems ~= nil then
print("calculus part reached")
info = me.listItems()
lItems = {}
if info ~= nil then
for i,o in pairs(info) do
lItems[tostring(i)] = o
end
else
info = {["nil"] = true}
end
for i=#trackedItems,1,-1 do
tItem = trackedItems[i]
if tItem["time"] < index then
tItem["time"] = tItem["time"] + 1
end
if lItems[tostring(tItem["id"])] ~= nil then
tItem["count"] = lItems[tostring(tItem["id"])]
tItem["am0"] = tItem["count"]
else
tItem["count"] = 0
tItem["am0"] = tItem["count"]
end
print("cIndex: "..tItem["time"])
for o=1,tItem["time"] do
b = tItem["time"] + 1 - o
tItem["am"..b] = tItem["am"..b-1]
end
tItem["avg"] = 0
for u=0,tItem["time"] - 1 do
de1 = tItem["am"..u+1]
de2 = tItem["am"..u]
tItem["avg"] = tItem["avg"] + de2 - de1
end
tItem["avg"] = tItem["avg"] / cIndex
tItem["txamount"].setText(tostring(tItem["count"]))
sym = "+"
avg = tItem["avg"]
avg = tonumber(avg)
print("avg: "..avg)
if avg ~= "waiting.." then
if avg > 0 then sym = "+" else sym = "" end
acolor = 0xFFFFFF
if avg > 0 and avg < 1 then acolor = 0x88FF88 end
if avg >= 1 then acolor = 0x00FF00 end
if avg < 0 and avg > -1 then acolor = 0xFFDD88 end
if avg <= -1 then acolor = 0xFF4400 end
end
etamsg = ""
if avg < 0 then
eta = tItem["count"] / (-avg)
etaa = eta
etah = math.floor(etaa/3600)
etaa = etaa % 3600
etam = math.floor(etaa/60)
etaa = etaa % 60
etas = math.floor(etaa)
if etah > 0 then
etamsg = "ETA: "..etah.."h "..etam.."m "..etas.."s"
else if etam > 0 then
etamsg = "ETA: "..etam.."m "..etas.."s"
else if etas > 0 then
etamsg = "ETA: "..etas.."s"
else
etamsg = "ETA: less than 1s"
end
end
end
end
tItem["eta"].setText(etamsg)
tItem["txdam"].setColor(acolor)
tItem["txdam"].setText(sym .. m.round(avg,2) .. "i/s")
end
end
sleep(1)
end
print("MScan exit.")
end
error = bridge.addText(4, 190, " ",0xFF0000)
function MManage()
while true do
event, msg = os.pullEvent("chat_command")
data = {}
iter = 1
for i in string.gmatch(msg,"%S+") do
data["arg"..iter] = i
iter = iter + 1
end
arg1 = data["arg1"]
arg2 = data["arg2"]
arg3 = data["arg3"]
outcolor = 0xFF0000
outtext = " "
if arg1 == "add" then
print("add detected. arg1:"..arg1.." arg2:"..arg2.." arg3"..arg3)
local num = tonumber(arg2)
match = nil
for i in string.gmatch(arg2,":") do
match = i
end
if match == ":" then
print(" a : found")
tmeta = {}
for i in string.gmatch(arg2,"%d+") do
table.insert(tmeta,i)
end
id = tonumber(tmeta[1])
meta = tonumber(tmeta[2])
print("id: "..id.." meta: "..meta)
if meta and id then
num = id + (meta * 32768)
end
end
if num then
str = tostring(arg3)
if str then
num = tonumber(num)
ins = {["id"] = num,["name"] = str}
table.insert(trackedItems,ins)
table.insert(trackedItemsdat,ins)
for i=1,#trackedItemsdat do
for i,o in pairs(trackedItemsdat[i]) do
print(o)
end
print(trackedItemsdat[i])
end
f = fs.open(filename,"w")
wrt = textutils.serialize(trackedItemsdat)
f.writeLine(wrt)
f.close()
end
else
outtext = "Error: argument#2 must be a real number."
outcolor = 0xFF0000
end
end
if arg1 == "remove" or arg1 == "delete" then
str = tostring(arg2)
if str then
success = false
for i=#trackedItems,1,-1 do
dItem = trackedItems[i]
if dItem["name"] == str then
dItem["txlabel"].delete()
dItem["txamount"].delete()
dItem["txdam"].delete()
dItem["eta"].delete()
dItem["txlabel"] = nil
dItem["txamount"] = nil
dItem["txdam"] = nil
dItem["eta"] = nil
table.remove(trackedItems,i)
for o=i,#trackedItems do
dItem = trackedItems[o]
y = dItem["txlabel"].getY()
dItem["txlabel"].setY(y-5)
dItem["txamount"].setY(y-5)
dItem["txdam"].setY(y-5)
dItem["eta"].setY(y-5)
end
end
end
for i=#trackedItemsdat,1,-1 do
dItem = trackedItemsdat[i]
if dItem["name"] == str then
table.remove(trackedItemsdat,i)
f = fs.open(filename,"w")
wrt = textutils.serialize(trackedItemsdat)
f.writeLine(wrt)
f.close()
success = true
end
end
if success then
outcolor = 0x00FF00
outtext = "Item removed.."
else
outcolor = 0xFFFF00
outtext = "Item not found!"
end
end
end
error.setColor(outcolor)
error.setText(outtext)
sleep(4)
error.setText(" ")
end
end
parallel.waitForAll(main,timer,MScan,MManage)
The program is meant to compare a list of ME system items with a user-input list of items, assign names to matched items, print their quantities, calculate deltaQuantities and give an ETA based on delta and current quantity.
Issues arise when the program tries to serialize the current user-input list of tracked items (trackedItemsdat).
Logically the only items that should ever end up on the list are coming from tonumber(arg2) and tostring(arg3). Furthermore what baffles me is that it adds and saves the first tracked item fine, and were you to terminate it there, restart, and add another item - everything works as intended, but add a second and suddenly serialize finds a function somewhere in trackedItemsdat.
I'm really confused as to why this is happening, especially because it was working fine running for 5 days straight chunkloaded, until I came back from afk to this error:
parallel: 22: textutils: 166: Cannot serialize type function.
The code was not modified prior to that.
I then loaded a better Serialize program I found here as 'slize' to see if the server changed/updated the textutils in rom, but only to get the same error. So it seems somehow a function is indeed making it's way into trackedItemsdat and I can't track it down. I've even tried to iterate-print the whole list and it didn't seem to print any functions.
Please help me in my struggles, as it is my first bigger CC project I made from scratch, if anyone with a fresh perspective on the code could locate the problem, I would be deeply grateful.
Thanks for taking time to read this in advance :)/>