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

Help with error please

Started by Levistator, 16 July 2013 - 01:47 AM
Levistator #1
Posted 16 July 2013 - 03:47 AM
This is my code for a tunnelQuarry. I have spent quite a bit of time on if with research planing and just plain old typing. But when I tried to run it on my turtle I got an error that i do not understand for the context it was in. the error reads, "tunnelQuarry:152: attempt to index ? (a nil value). I have highlighted the line that is erroring. if you would rather look at the cleaner version on pastebin the address is http://pastebin.com/9NDnbK0Z

local tArgs = {...}
local resetPos = {}
local height = tArgs[1]
local width = tArgs[2]
local depth = tArgs[3]
local currHeight = 0 --sets a changeable variable to 0 for saving
local currWidth = 0 --sets a changeable variable to 0 for saving
local currDepth = 0 --sets a changeable variable to 0 for saving
local resetHeight = resetPos[2] or 0
local resetWidth = resetPos[1] or 0
local resetDepth = resetPos[3] or 0
local m=0 --makes a multipurpose variable

function forward() --makes a persistant forward function in case of gravel/sand/mob/player
		while turtle.forward() == false do --keeps looping if it cant move forward, stops when it does succesfully.
				if turtle.detect() then --detects for a block as obstruction
						turtle.dig()  -- breaks block if detected
				else
						turtle.attack() --else attacks to move mob/player
				end
		end
		refuel() --checks if turtle needs fuel, fuels if needed
end

function moveRight() --moves turtle right one
		turtle.turnRight()
		forward()
		turtle.turnLeft()
end

function moveLeft() -- moves turtle left one
		turtle.turnLeft()
		forward()
		turtle.turnRight()
end

function up() --makes a persistant up function in case of gravel/sand/mob/player
		while turtle.up() == false do --loops to move up until succesful
				if turtle.detect() == true then --if block in the way
						turtle.digUp() --breaks it
				else --if mob/player is in the way
						turtle.attackUp() --attacks to move it
				end
		end
end

function digRow() --makes function to dig a row. saves turtle position in row. allows session persistance
local w = fs.open("currPos/"..currWidth,"w") --opens width save file for writing
		for i=1,math.abs(resetWidth-width)-1 do --loop to dig row. reacts for session persistance
				turtle.dig()
				if m==0 then --if it last moved left will move right
						moveRight()
						currWidth = currWidth+1 --currWidth increases towards right
						m=1
				elseif m==1 then --if last moved right will move left
						moveLeft()
						currWidth = currWidth-1 --currWidth decreases towards left
						m=0
				end
				checkInv()
				w.write(currWidth) --writes currWidth to width save file
		end
		turtle.dig() --breaks the last block in the row without possibly moving too far
		w.close() --closes width save file
end

function nextRow() --function to move turtle up to the next row. saves turtle height. allows session persistence
local h = fs.open("currPos/"..currHeight,"w") --opens height save file for writing
		for i=1,math.abs(resetHeight-height) do --loop to dig 1 depth  of tunnel
				digRow() --initiates the digRow function
				up() --when digRow is done moves turtle up to next row
				currHeight = currHeight+1 --currHeight increases going up
				h.write(currHeight) --writes currHeight to height save file
		end
		h.close() --closes height save file
end

function tunnel() --function to move the turtle deeper into tunnel. saves depth. allows session persistence
local d = fs.open("currPos/"..currDepth,"w") --opens depth save file for writing
		for i=1,math.abs(resetDepth-depth)-1 do --loop to dig tunnel
				nextRow() --initiates the function nextRow
				resetTurtlePos()
				forward()
				currDepth = currDepth+1 --currDepth increases further into tunnel
				d.write(currDepth) --writes currDepth to depth save file
		end
		nextRow() --digs final depth of tunnel
		d.close() --closes depth save file.
end

function resetTurtlePos() --function to reset the turtle so that the tunnel is straight. saves width and height. allows session persistence
local w = fs.open("currPos/"..currWidth,"w") --opens width save file for writing
local h = fs.open("currPos/"..currHeight,"w") --opens height save file for writing
		if m==1 then --if it just moved right
				for i=1,math.abs(resetHeight-height) do --moves down, session persistence
						turtle.down()
						currHeight = currHeight-1 --currHeight decreases as move down
						h.write(currHeight) --writes currHeight to height save file
				end
				turtle.turnLeft()
				for i=1,math.abs(resetWidth-width)-1 do --moves left, session persistance
						forward()
						currWidth = currWidth-1 --currWidth decreases as move left
						w.write(currWidth) --writes currWidth to width save file
				end
				turtle.turnRight()
		elseif m==0 then --if itjust moved left
				for i=1,math.abs(resetHeight-height) do --moves down, session persistance
						turtle.down()
						currHeight = currHeight-1 --currHeight decreases as move down
						h.write(currHeight) --write currHeight to height save file
				end
		end
		w.close() --closes width save file
		h.close() --closes height save file
end


function cleanUp() --cleans inventory
		turtle.select(16) --selects enderchest
		turtle.turnRight()
		turtle.turnRight() --turns around
		turtle.place() --places enderchest
		for i=1,14 do --selects each slot 1 through 14 and drops items into enderchest
				turtle.select(i)
				turtle.drop()
		end
end

function checkInv() -- checks if cleanUp needs to happen
		if turtle.getItemCount(14) ~= 0 then --checks last possibly available inventory slot
				cleanUp() --runs cleanUp if inventory is full
		end
end

function refuel() --checks if turtle needs fuel
		if turtle.getFuelLevel() <400 then --if turtle has less than 400 fuel
				turtle.select(15) --turtle selects coal
				turtle.refuel(4) --refuels with 4
				turtle.select(1) --selects slot 1 again
		end
end

function sessionPersistence() --allows for session persistence in this program
		fs.makeDir("currPos") --makes a save directory called, "currPos" for saving
				local w = fs.open("currPos/"..currWidth,"r") --opens width save file for reading
				local h = fs.open("currPos/"..currHeight,"r") --opens height save file for reading
				local d = fs.open("currPos/"..currDepth,"r") --opens depth save file for reading
						table.insert(resetPos,w) --sets data from currPos/currWidth to the table resetPos in slot [1]
						table.insert(resetPos,h) --sets data from currPos/currHeight to the table resetPos in slot [2]
						table.insert(resetPos,d) --sets data from currPos/currDepth to the table resetPos in slot [3]
				w.close() --THIS IS THE ERRORING LINE!
				h.close()
				d.close()
end

function run()
		sessionPersistence()
		tunnel()
end

run()
BlankWolf #2
Posted 16 July 2013 - 05:44 AM
Well, I don't now exactly if this is the problem, but you open 3 files before you closed 1 of them.
Maybe you shoud try to open 1 file do stuff with it and close it befor you open an other file.

w = fs.open()
	-- do stuf
w.close()
h = fs.open()
	-- do other stuff
h.close()
I hope you get what I mean.
Sharidan #3
Posted 16 July 2013 - 09:07 AM
The error message:
"attempt to index a ? (a nil value)
This means that you are either trying to reference a method (function) of an object that does not exist, that you are trying to index a table value that doesnt exist or that the variable you are referencing doesnt have a value - i.e. it's nil.

Lua considers all created variables as nil by default.

In this case you are trying to reference the .close() method of the filesystemobject file handle, however at the time you instantiated the file handle (your "w" variable), the fs API was not able to allocate the file and thus returned nil to your "w" variable.
When you then later try to call the .close() method, that method doesnt exist because the fs.open() function didnt return the file handle object, but rather a nil value indicating an error.

When operating with files through the fs api, you should always check that the fs api actually returned an object (meaning the operation was a success).

You can do so easily with this setup:


local w = fs.open("currPos/"..currWidth,"r")
if (w) then
  -- Perform your fil actions here
  w.close()
end

This will ensure that you always have the file handle and only do file operations when you are able to. This also prevents your application from crashing whenever the fs API is unable to return a file handle object. If the fs API doesnt return a file handle object, you don't need to do anything else in terms of cleanup, since the "w" variable is already nil and thus doesnt contain any data.

You could additionally add an "else" statement to handle things differently in case of an error:


local w = fs.open("currPos/"..currWidth,"r")
if (w) then
  -- Perform your fil actions here
  w.close()
else
  print("Unable to open file for saving!");
end

Of course you can always change what ever goes in in the "else" part of the code to handle things differently in case the fs API is unable to open the file.

Missing return file handle object can occur if:
1) the file doesnt exist
2) the file is somehow locked by another process
3) the allocated space through the CCconfig is used up grossly - i.e. 1Mb allocted but there are files and folders taking up more than that.
4) Lua runs out of memory because of too deeply nested recursive actions (i.e. methods calling them selves continuesly - usually causes a crash).

Hope this helps ya a bit :)/>
Levistator #4
Posted 16 July 2013 - 01:40 PM
ya Thanks it helped get this thing running. now im just working on the actual persistance. :)/>
GermanPlayer #5
Posted 16 July 2013 - 01:42 PM
Hello i need help with pastebin

ihave written on edit startup :

pastebin get DwJDDMJc startup
startup

whats wrong ?
Sharidan #6
Posted 16 July 2013 - 08:58 PM
Glad I could help :)/>