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

Attempt to call nil on this program

Started by gknova61, 27 November 2012 - 07:10 PM
gknova61 #1
Posted 27 November 2012 - 08:10 PM
Idk what's wrong with this, it says attempt to call nil on line 17
http://pastebin.com/tjzbPDf2

This is happening on every program that uses this function or the code of it even this one :(/> http://pastebin.com/XR9C8z75 Currently the code is commented out for that program but just find "if not fs.exists" and it should be the first piece of commented out code that comes up that isn't working ;)/>
Cranium #2
Posted 27 November 2012 - 08:28 PM
Is http enabled on your computercraft? If not, enable it and try again.
gknova61 #3
Posted 27 November 2012 - 09:16 PM
Yup, it's enabled on the emulator. Still attempt to call nil on line 26. It gets a response, it just has a problem with fs.

EDIT: BONUS!!! I got a problem with this program too, attempt to call nil :(/>
http://pastebin.com/zqvjshdA

<3 u :D/>
KaoS #4
Posted 28 November 2012 - 03:59 AM
on that second code you have something to check if http is not nilm if it is nil you print something and use return. return does not work in a program, you should use

error( "Pastebin requires the HTTP API\nSet enableAPI_http to 1 in mod_ComputerCraft.cfg" )
to cancel effectively or your code will keep running
Cranium #5
Posted 28 November 2012 - 04:29 AM
on that second code you have something to check if http is not nilm if it is nil you print something and use return. return does not work in a program, you should use

error( "Pastebin requires the HTTP API\nSet enableAPI_http to 1 in mod_ComputerCraft.cfg" )
to cancel effectively or your code will keep running
Actually, return works just fine. There are examples of it working in several of the default programs with CC. One being the pastebin program. Instead of throwing an error, it just prints, then exits the program.
For it having error on line 26, that may be that your shell.resolve is not working like you need it to. Try doing shell.resolve("/"..path). I don't know if that would work, but that's what Kaos and I did when we were working on the file system for SmartPaste.
KaoS #6
Posted 28 November 2012 - 04:31 AM
:mellow:/> I am now officially freaked out… return working outside of a function…
Cranium #7
Posted 28 November 2012 - 04:34 AM
EDIT: BONUS!!! I got a problem with this program too, attempt to call nil :(/>
http://pastebin.com/zqvjshdA
For the error on that one, you call "if pastebinGet(pastebinIds,fileName) then", when it should be "if pastebinGet(pastebinIds,fileNames) then". You forgot the "s" in fileNames

:mellow:/> I am now officially freaked out… return working outside of a function…
Whatever you do… DON'T FREAK OUT.
Lyqyd #8
Posted 28 November 2012 - 06:17 AM
:mellow:/>/> I am now officially freaked out… return working outside of a function…

Why should this be surprising? Programs are loadstring()'d and run as functions in os.run(), so of course return works to exit the function. :)/>
KaoS #9
Posted 28 November 2012 - 06:36 AM
AHHHH that explains it I guess, I just didn't realize. I think there was something contradictory in the 5.1 reference manual
gknova61 #10
Posted 28 November 2012 - 02:33 PM
EDIT: BONUS!!! I got a problem with this program too, attempt to call nil :(/>
http://pastebin.com/zqvjshdA
For the error on that one, you call "if pastebinGet(pastebinIds,fileName) then", when it should be "if pastebinGet(pastebinIds,fileNames) then". You forgot the "s" in fileNames

Works perfect, thanks cran :3 but can anyone solve this one? :)/> http://pastebin.com/tjzbPDf2
Attempt to call nil on line 26 for those who don't wana test it :P/>

EDIT: This is happening on every program that uses this function or the code of it even this one :(/> http://pastebin.com/XR9C8z75 Currently the code is commented out for that program but just find "if not fs.exists" and it should be the first piece of commented out code that comes up that isn't working ;)/>
Cranium #11
Posted 28 November 2012 - 06:59 PM
had to change your config to work with only config in stead of apis/config, because if limitations to writing to ROM. Also, line 249 did not specify multiple arguments in config.load().

GPS Tower:
Spoiler


--Originally by MysticT
--TODO: Implement HTTP Publishing total amount of GPS Requests served

local tLocations = {}
local tKnownLocations = {}
local bDebug = false

--Download config API
local function pastebinGet(code,path)
local sCode = code
local sFile = path
local sPath = shell.resolve( sFile )
if fs.exists( sPath ) then
fs.delete(sPath)
end

local response = http.get(
"http://pastebin.com/raw.php?i="..textutils.urlEncode( sCode )
)

if response then
local sResponse = response.readAll()
response.close()

local file = fs.open( sPath, "w" )
file.write( sResponse )
file.close()
                return true

else
return false
end 
end

if not http then
    print( "GPS requires the HTTP API" )
    print( "Set enableAPI_http to 1 in mod_ComputerCraft.cfg" )
    return false
end

if not fs.exists("config") then
if pastebinGet("fkcMT9CE","config") then
else
print("Something went wrong! No response!")
return false
end
end

-- Helper functions

local function clear()
term.clear()
term.setCursorPos(1, 1)
end

local function table_size(t)
local i = 0
for _,_ in pairs(t) do
i = i + 1
end
return i
end

local function connect()
for _,s in ipairs(rs.getSides()) do
if peripheral.isPresent(s) and peripheral.getType(s) == "modem" then
rednet.open(s)
print( "No modem active. Opening "..sFreeSide.." modem" )
return true
end
end
print("No modem attached")
return false
end

local function _print(...)
if bDebug then
print(...)
end
end

local function vector_equal(v1, v2)
return v1.x == v2.x and v1.y == v2.y and v1.z == v2.z
end

-- Load/Save functions

local function save()
_print("Saving locations...")
local file = fs.open("locations.dat", "w")
if file then
for id, loc in pairs(tKnownLocations) do
file.writeLine(tostring(id)..": "..tostring(loc.x)..", "..tostring(loc.y)..", "..tostring(loc.z))
end
file.close()
_print("Locations saved")
return true
end
_print("Error saving locations")
return false
end

local function load()
_print("Loading locations")
local file = fs.open("locations.dat", "r")
if file then
local i = 0
local sLine = file.readLine()
while sLine do
local sId, sX, sY, sZ = string.match(sLine, "(%d+): (%-?%d+), (%-?%d+), (%-?%d+)")
local id, x, y, z = tonumber(sId), tonumber(sX), tonumber(sY), tonumber(sZ)
if id and x and y and z then
tKnownLocations[id] = vector.new(x, y, z)
i = i + 1
end
sLine = file.readLine()
end
file.close()
_print(n, " locations loaded")
return true, i
end
_print("Error loading locations")
return false
end

-- Location functions

local function trilaterate(A, B, C)
local a2b = B.position - A.position
local a2c = C.position - A.position
if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then
return nil
end
local d = a2b:length()
local ex = a2b:normalize( )
local i = ex:dot( a2c )
local ey = (a2c - (ex * i)):normalize()
local j = ey:dot( a2c )
local ez = ex:cross( ey )
local r1 = A.distance
local r2 = B.distance
local r3 = C.distance
local x = (r1*r1 - r2*r2 + d*d) / (2*d)
local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j)
local result = A.position + (ex * x) + (ey * y)
local zSquared = r1*r1 - x*x - y*y
if zSquared > 0 then
local z = math.sqrt(zSquared)
local result1 = result + (ez * z)
local result2 = result - (ez * z)
local rounded1, rounded2 = result1:round(), result2:round()
if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then
return result1, result2
else
return rounded1
end
end
return result:round()
end

local function narrow(p1, p2, fix)
local dist1 = math.abs((p1 - fix.position):length() - fix.distance)
local dist2 = math.abs((p2 - fix.position):length() - fix.distance)
if math.abs(dist1 - dist2) < 0.05 then
return p1, p2
elseif dist1 < dist2 then
return p1:round()
else
return p2:round()
end
end

function locate(id)
local tFixes = {}
local p1, p2
for _,t in pairs(tLocations[id]) do
table.insert(tFixes, { ["position"] = vector.new(t.x, t.y, t.z), ["distance"] = t.d })
end
local i = 3
while (p1 == nil or p2 ~= nil) and i <= #tFixes do
if not p1 then
p1, p2 = trilaterate(tFixes[1], tFixes[2], tFixes[i])
else
p1, p2 = narrow(p1, p2, tFixes[i])
end
i = i + 1
end
if p1 and p2 then
_print("Ambiguous position")
_print("Could be "..p1.x..","..p1.y..","..p1.z.." or "..p2.x..","..p2.y..","..p2.z)
elseif p1 then
if not tKnownLocations[id] or not vector_equal(tKnownLocations[id], p1) then
print("Location added:")
print(id, ": ", p1)
tKnownLocations[id] = p1
save()
end
else
_print("Couldn't determine location for ", id)
end
end

local function addLocation(id, t)
if not tLocations[t.id] then
tLocations[t.id] = {}
end
local tLoc = {}
tLoc.x = t.x
tLoc.y = t.y
tLoc.z = t.z
tLoc.d = t.d
tLocations[t.id][id] = tLoc
if table_size(tLocations[t.id]) >= 3 then
_print("Trying to locate #", t.id)
locate(t.id)
end
end

-- Event handlers

local function handle_message(id, msg)
local st = string.match(msg, "<LOCATION> (.+)")
if st then
local t = textutils.unserialize(st)
if t and type(t) == "table" then
_print("Location received from ", id, ":")
_print(t.id, ": ", "(", t.x, ", ", t.y, ", ", t.z, ", ", t.d, ")")
addLocation(id, t)
end
end
end

local function handle_char(c)
c = string.lower(c)
if c == "l" then
print("Locations:")
for id, loc in pairs(tKnownLocations) do
print(id, ": ", loc)
end
elseif c == "c" then
clear()
end
end

-- Start program

local function host()
os.loadAPI("config")
config.load(nil,"config") --forgot to define multiple arguments
local nMasterID = tonumber(config.readVal("mId"))
local tLoc = {}
tLoc.x = tonumber(config.readVal("x"))
tLoc.y = tonumber(config.readVal("y"))
tLoc.z = tonumber(config.readVal("z"))
config.save()
os.unloadAPI("config")
if not nMasterID or not tLoc.x or not tLoc.y or not tLoc.z then
printUsage()
return
end
clear()
if not connect() then
return
end
print("==================================================")
    print("Powered by G&amp;K Industries. Contact representative, gknova61 if any issues.")
    print("==================================================")
print( "Position is "..tLoc.x..","..tLoc.y..","..tLoc.z )
print( "Serving GPS requests" )
local nServed = 0
--print("Waiting for messages...")
while true do
local id, msg, dist = rednet.receive()
--print("Message received from ", id, " at ", dist, " meters.")
if msg == "PING" then
rednet.send(id,textutils.serialize({tLoc.x,tLoc.y,tLoc.z}))
nServed = nServed + 1 
if nServed > 1 then
local x,y = term.getCursorPos()
term.setCursorPos(1,y-1)
end
print(nServed.." GPS Requests served")
end
tLoc.id = id
tLoc.d = dist
rednet.send(nMasterID, "<LOCATION> "..textutils.serialize(tLoc))
end
end

local function printUsage()
local sName = fs.getName(shell.getRunningProgram())
print("Usage:")
print(sName, " receive [debug]")
print(sName, " host id x y z")
end

local tArgs = {...}
local sAction = tArgs[1]

if sAction and not fs.exists("config") then
printUsage()
return false
elseif not sAction and fs.exists("config") then
host()
elseif sAction == "host" and not fs.exists("config") then
if #tArgs < 5 then
printUsage()
return false
end
local mId = tArgs[2]
local x = tArgs[3]
local y = tArgs[4]
local z = tArgs[5]
os.loadAPI("config")
config.load(nil,"config")
config.writeVal("mId",mId)
config.writeVal("x",x)
config.writeVal("y",y)
config.writeVal("z",z)
config.save()
os.unloadAPI("config")
end

if sAction == "receive" then
if #tArgs > 1 then
if string.lower(tArgs[2]) == "debug" then
bDebug = true
else
printUsage()
return
end
end
clear()
if not connect() then
return
end
local ok, n = load()
if ok then
print("Loaded ", n, " locations")
end
print("Press l to list located computers")
print("Press c to clear the screen")
while true do
local evt, arg1, arg2 = os.pullEvent()
if evt == "rednet_message" then
handle_message(arg1, arg2)
elseif evt == "char" then
handle_char(arg1)
end
end
end

Config:
Spoiler


--[[
Program: Config API
Version: 1.0
Author:  ben657
Support: 

Description: This API allows you to easily make configs for
    your users to edit, rather than them having to
    read code and edit variables. These files can
             then be read by this API and the values can be
    used in your programs.

Note: Currently, tables cannot be written to configs, but in
      the future this functionality may be implemented.
--]]

loaded = false
dir = ""
file = ""
path = ""
internal = {}

 function create()
local file = fs.open(path,"a")
file.close()
 end

 --[[
 Attempts to load the config using the specified directory
 and file name, and load the contents into internal memory.
 If the path is not found, it will be created.
 --]]
function load(directory,fileName)
dir = directory
file = fileName
if dir ~= nil then
path = dir.."/"..file
fs.makeDir(dir)
create(path)
local file = fs.open(path, "r")
repeat
line = file.readLine()
if(line ~= nil) then
local asWords = line:gsub(":","")
local parts = {}
for word in asWords:gmatch("%w+") do table.insert(parts,word) end
internal[parts[1]] = parts[2]
end
until line == nil
loaded = true
file.close()
else
path = file
create(path)
local file = fs.open(path, "r")
repeat
line = file.readLine()
if(line ~= nil) then
local asWords = line:gsub(":","")
local parts = {}
for word in asWords:gmatch("%w+") do table.insert(parts,word) end
internal[parts[1]] = parts[2]
end
until line == nil
loaded = true
file.close()
end
end

--[[
Attempts to write the specified value to the specified key in the
internal config.
Returns true if successful.
Returns false if no config is loaded.
This only writes to the config in memory, not the file. To save
to file, call config.save().
--]]
function writeVal(key,value)
if(loaded == false) then
return false
else
local toWrite = value
if(value == true) then toWrite = "true"
elseif(value == false) then toWrite = "false" end
internal[key] = toWrite
return true
end
end

--[[
Attempts to read a value from the internal config and return it.
Returns the value assigned to the specified key if successful.
Returns nil if no config is loaded or no value was found at the key.
--]]
function readVal(key)
if(loaded == false) then
return nil
end
toReturn = internal[key]
if(toReturn == "true") then return true
elseif(toReturn == "false") then return false
else return internal[key] end
end

--[[
Attempts to save the internal config to the loaded file path.
Returns true if successful.
Returns false if no config is loaded.
The internal config is unloaded after saving, so config.load()
must be called again to use the config.
--]]
function save()
if(loaded == true) then
local file = fs.open(path,"w")
for i,v in pairs(internal) do
file.writeLine(i.." = "..v)
end
file.close()
internal = {}
loaded = false
return true
else
return false
end
end

--[[
Returns true if the config has no data.
Returns false if the config contains any data.
Returns nil if no config is loaded.
--]]
function isEmpty()
if(loaded == false) then
return nil
end
if(fs.getSize(path) == 0)then
return true
else return false end
end

You now have another error in your config file regarding table index expected, got nil on line 63. Hope that helps…