How do I access tables created in one function from another?

Posted by Bevern on Sat 02 Aug 2008 09:43 PM — 7 posts, 28,180 views.

#0
I'm trying to make an xp tracker that tracks the last hour's experience gained and this is what I have thus far:


function newrecord (name, line, wildcards)

	if tracking == nil then
		tracking = {}
	end -- if
	record = {}
	record.xp = wildcards [1]
	record.time = os.time()
	table.insert(tracking, record)

end -- function

function showxp (name, line, wildcards)
	xphour = 0
	while next(tracking) ~= nil do
		record = tracking[1]
		print (record.time)
		if record.time < os.time() - 3600 then
			table.remove(tracking, 1)
		else -- Everything after is newer
			xphour = xphour + record.xp
		end -- if
	end -- while
	print ("Experience gained this hour: " .. xphour)
end --function


But when running showxp it gives me the error message

Run-time error
World: Aardwolf
Function/Sub: showxp called by alias
Reason: processing alias ""
[string "Script file"]:15: bad argument #1 to 'next' (table expected, got nil)
stack traceback:
        [C]: in function 'next'
        [string "Script file"]:15: in function <[string "Script file"]:13>
Error context in script:
  11 : end -- function
  12 : 
  13 : function showxp (name, line, wildcards)
  14 :  xphour = 0
  15*:  while next(tracking) ~= nil do
  16 :          record = tracking[1]
  17 :          print (record.time)
  18 :          if record.time < os.time() - 3600 then
  19 :                  table.remove(tracking, 1)


Which seems to me that it's saying either the table isn't saving after the newrecord function runs or there's some other way to access tables that aren't created by the executing function. What am I doing wrong here? Thanks
Australia Forum Administrator #1
You have the right general idea, but are you sure that newrecord was called before showxp? Perhaps some print statements to make sure.

If the first thing you do, after reloading the script file, is to do showxp, then the tracking table won't exist. Maybe do this:


function showxp (name, line, wildcards)
	xphour = 0
        tracking = tracking or {}  --> make sure table exists


Meanwhile, won't this go into an infinite loop?


while next(tracking) ~= nil do
		record = tracking[1]
		print (record.time)
		if record.time < os.time() - 3600 then
			table.remove(tracking, 1)
		else -- Everything after is newer
			xphour = xphour + record.xp
		end -- if
	end -- while


Once you stop removing records that are over an hour old, it will loop forever.

Perhaps:


for k, record in pairs (tracking) do
  print (record.time)
  if record.time < os.time() - 3600 then
    tracking [k] = nil  -- delete old records
  else -- Everything after is newer
    xphour = xphour + record.xp
  end -- if
end -- for


This will step through the table once, deleting old records, and add up xp.


#2
Thanks, that worked great. Another question: I'm trying to serialize the table into a string so I can save it as a variable and then reload it. I used the serialize.lua script and amended "require "serialize"" to the top of the script but I get this when I try to run it:

Run-time error
Plugin: Aardwolf_Level_Tracker (called from world: Aardwolf)
Function/Sub: showexpt called by alias
Reason: processing alias ""
[string "Plugin"]:270: attempt to index global 'serialize' (a nil value)
stack traceback:
        [string "Plugin"]:270: in function <[string "Plugin"]:252>
Error context in script:
270*:  print ("stats = " .. serialize.save (statstable))

Australia Forum Administrator #3
Can you show the exact code? If I saw this:


require "serialize"  

print ("stats = " .. serialize.save (statstable))

...

[string "Plugin"]:270: attempt to index global 'serialize' (a nil value)


... I would be surprised.

However maybe the "require" line was not executed.
#4
It seems the problem I was having is that the "require" must be inside the function calling it rather than something global(unless I'm mistaken). I've come across another problem with serializing however. Just for testing purposes I created the following two functions:



function test1 ()
	require "serialize"
	if GetVariable ("statstable") then
		loadstring (GetVariable ("statstable"))
	else
		statstable = statstable or {}
		statstable.currentlevel = 0
		statstable.resettime = os.time()
		statstable.totalbonuss = 0
		statstable.totalbonusi = 0
		statstable.totalbonusw = 0
		statstable.totalbonusd = 0
		statstable.totalbonusc = 0
		statstable.totalbonusl = 0
		statstable.totalbonustrains = 0
		statstable.totalgold = 0
		statstable.totalkills = 0
		statstable.totallevels = 0
		statstable.totalpups = 0
		statstable.totalremorts = 0
		statstable.totalxp = 0
		statstable.installtime = os.time()
	end -- if
	SetVariable ("statstable", serialize.save ("statstable"))
end

function test2 ()
	loadstring (GetVariable ("statstable")) 
	print (statstable.totalxp)
end

First I create the table and then serialize it with test1 which results in the "statstable" variable becoming:


statstable = {}
  statstable.totalbonusw = 0
  statstable.installtime = 1217988982
  statstable.totalbonusi = 0
  statstable.totalbonusl = 0
  statstable.totalxp = 12341
  statstable.totalpups = 0
  statstable.resettime = 1217988982
  statstable.currentlevel = 0
  statstable.totalremorts = 0
  statstable.totallevels = 0
  statstable.totalkills = 0
  statstable.totalbonusc = 0
  statstable.totalbonusd = 0
  statstable.totalbonuss = 0
  statstable.totalgold = 0
  statstable.totalbonustrains = 0


This seems strange since I'd think the brackets should end after the last line, not just be {}

Test2 is supposed to load it and then print it's value. It seems that it's not loading correctly however because it still prints out the value of the table's totalxp value rather than loading it from the variable.
Australia Forum Administrator #5
Quote:

This seems strange since I'd think the brackets should end after the last line, not just be {}


Why? You did it exactly the same way. You created the table in one line, and then changed all its contents.


statstable = statstable or {}
statstable.currentlevel = 0
statstable.resettime = os.time()
... etc.


Quote:

It seems the problem I was having is that the "require" must be inside the function calling it rather than something global(unless I'm mistaken).


It can be global, however I am doubting it was executed if it was nil.


Quote:

function test2 ()
loadstring (GetVariable ("statstable"))
print (statstable.totalxp)
end

It seems that it's not loading correctly however ...


Compare to my example at the bottom of this page:

http://www.gammon.com.au/forum/?id=4960

I had this:


function OnPluginInstall ()
  assert (loadstring (GetVariable ("my_variables") or "")) ()
end -- function OnPluginInstall


Note the extra brackets at the end of the line? Your "loadstring" created a function but didn't execute it, thus statstable was not changed. At least change it to:


function test2 ()
	loadstring (GetVariable ("statstable"))  ()
	print (statstable.totalxp)
end


#6
Excellent, thank you very much.