Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Loading and Saving variables — Gideros Forum

Loading and Saving variables

WauloKWauloK Member
edited February 2013 in General questions
I've been searching the forum and Ultimate Guide for information on saving multiple variables into a single settings file.

I used this from the Ultimate Guide first:
local playerName = "Awesome Player"
local file = io.open ( "|D|settings.save" , "w+" )
        file:write( "Playername:" , playerName )
        file:close()	
local playerName = nil
local file = io.open ( "|D|settings.save", "r" )
playerName = file:read()
file:close()
print ( "The playername saved is: ", playerName)
Unfortunately, the output is:
The playername saved is:          Playername:Awesome Player
which means the variable playerName isn't "Awesome Player" but "Playername:Awesome Player" which is not what I want.

Also, if I try multiple file:writes with different variables, I can only read into the first variable and it's almost all the values combined:
local playerOne = "Jason"
local score = 21450
local hiscore = 300000
 
local filesave = io.open("|D|settings.save", "w+")
	filesave:write("playerOne", playerOne)
	filesave:write("score", score)
	filesave:write("hiscore", hiscore)
	filesave:close()
 
playerOne = nil
score = nil
hiscore = nil
 
local fileload = io.open("|D|settings.save", "r")
	playerOne = fileload:read()
	score = fileload:read()
	hiscore = fileload:read()
	fileload:close()
 
print ("Player One: ", playerOne)
print ("Score: ", score)
print ("Hi Score: ", hiscore)
Player One:         playerOneJasonscore0
Score:  nil
Hi Score:   nil
Help! :)
Gideros Tutorials and Mobile apps:
http://BlueBilby.com/

Comments

  • BJGBJG Member
    edited February 2013
    I haven't looked into file handling yet so I only know what I just read here...

    http://www.giderosmobile.com/forum/discussion/377/writing-to-file

    ...but it seems to me that:

    a) You don't want to be writing strings like "playerOne" to the file, just the data.

    b) You're reading back the contents of the whole file into a variable. After that you'll need to process it to put it into a structured form. So I'd be thinking in terms of saving the data in the format of something like a CSV file, with comma delimiters or whatever, then writing a function that could read this in, process it and stick it in a table.

    (But there's a probably a better or standard way that someone will explain...)
  • ar2rsawseenar2rsawseen Maintainer
    edited February 2013 Accepted Answer
    @Waulok as I understand you are trying to save data with keys to represent them. Wel in this case you either have to separate your logic by saving data by lines without keys.

    Or use something from ready to use methods as dataSaver with json:
    http://appcodingeasy.com/Gideros-Mobile/Save-and-load-data-module-for-Gideros-Mobile

    Or saving lua tables to file
    http://www.giderosmobile.com/forum/discussion/367/save-load-a-table

    Likes: BJG

    +1 -1 (+1 / -0 )Share on Facebook
  • Yeah. I will use your datasaver or table saver in the future but I wanted to first do it in plain lua.
    From the above result it means the example given in the Ultimate Guide is wrong.
    Gideros Tutorials and Mobile apps:
    http://BlueBilby.com/
  • ar2rsawseenar2rsawseen Maintainer
    edited February 2013
    In Ultimate guide it is said:
    This has just saved a file called settings.save with the values "Playername: Awesome Player"

    And that is what it did, isn't it?

    My main point is that it is an example of how to handle files (reading/writing) and not how to save and retrieve scores ;)
  • Yeah but I cannot think of a situation where you would want to save something with a key but cannot retrieve it with a key AND cannot easily restore the value you saved as it was.
    Why would you save a value of "Awesome Player" but want to retrieve it as "Playername:Awesome Player"? A totally useless example. Makes no sense whatsover.
    Also, you cannot use playerName=file:read( "Playername"). THAT would be useful.
    No sense at all! :)
    Gideros Tutorials and Mobile apps:
    http://BlueBilby.com/
  • WauloKWauloK Member
    edited February 2013
    Anyway, I have successfully found a way to do what I want. It's not really ideal, but it works:
    local Player = "Jason"
    local Score = 23980
    local HiScore = 349870
     
    local Player2 = nil
    local Score2 = nil
    local HiScore2 = nil
     
    local file=io.open("|D|settings.txt","w+")
    file:write(Player,"\n")
    file:write(Score,"\n")
    file:write(HiScore,"\n")
    file:close()
     
    file2=io.open("|D|settings.txt", "r")
    Player2=file2:read("*line")
    Score2=tonumber(file2:read("*line"))
    HiScore2=tonumber(file2:read("*line"))
    file2:close()
     
    print ("Player: ", Player2)
    print ("Score: ", Score2)
    print ("HiScore: ", HiScore2)
    Gideros Tutorials and Mobile apps:
    http://BlueBilby.com/
  • @Waulok yes well it was an example of the "raw" file handling, to retrieve something by key, you need serializations as json or lua table, and yes your kind of serialization would also work, but for more complex structures it would be advised to use something of what I've mentioned above ;)
  • bowerandybowerandy Guru
    edited February 2013
    @Waulok, I think you should be using Json from the start. It's very flexible and you'll end up with code that can be reused for other things in the future. In my racing game, I have a class called "Driver" and each driver has it's own score/achievements file. I have save() and load() methods that save a driver's data to an external json file and reload from it. Each driver is identified by a string id that is used to generate the external data file name.

    Here's the code:
    function Driver:getData()
    	local data={ 
    		version=DRIVER_DATA_VERSION, 
     
    		-- Driver state
    		name=self.name,
    		carType=self.carType,
     
    		-- Below are stats
    		races=self.races,
    		wins=self.wins,
    		totalMoves=self.totalMoves,
    		winMoves=self.winMoves,
    		winStreak=self.winStreak,
     
    		-- Below are progress/awards
    		turboBoosts=self.turboBoosts, 
    		powerBrakes=self.powerBrakes,
    		victoryMiles=self.victoryMiles,
    		trackStars=self.trackStars,
    		packStars=self.packStars,
    		trophies=self.trophies
    		}
    	return data
    end
     
    function Driver:setData(data)	
    	-- Driver state
    	self.name=self.name or self.id
    	self.carType=data.carType or "Bug450"
     
    	-- Below are stats
    	self.races=data.races or 0
    	self.wins=data.wins or 0 
    	self.totalMoves=data.totalMoves or 0
    	self.winMoves=data.winMoves or 0
    	self.winStreak=data.winStreak or 0
     
    	-- Below are progress/awards
    	self.victoryMiles=data.victoryMiles or 0
    	self.turboBoosts=data.turboBoost or 0
    	self.powerBrakes=data.powerBrakes or 0
    	self.trackStars=data.trackStars or {}
    	self.packStars=data.packStars or {}
    	self.trophies=data.trophies or {}
    end
     
    function Driver:getPathForData()
    	return BhSnapshot.getPathForFile("|D|"..self.id..".driver")
    end
     
    function Driver:loadData()
    	local filename = self:getPathForData()
    	local file = io.open(filename, "r")
    	if file==nil then return nil end
    	local contents = file:read("*a")
    	io.close( file )
    	return Json.Decode(contents)
    end
     
    function Driver:load()
    	local data=self:loadData()
    	if data then
    		bhDebugf("Loaded driver data for %s", self.id)
    		self:setData(data)
    		return true
    	end
    	return false
    end
     
    function Driver:save()
    	local s=Json.Encode(self:getData())	
    	local filename = self:getPathForData()
    	local file=io.open(filename, "w")
    	if file==nil then 
    		bhDebug(string.format("Error opening file %s", filename))
    		return false
    	end
    	file:write(s)
    	file:close()
    	bhDebugf("Saved driver data for %s", self.id)
    	return true
    end
     
    function Driver:reset()
    	self:setData({})
    	os.remove(self:getPathForData())
    	bhDebugf("Reset driver data for %s", self.id)
    	return true
    end
    You'll see that I use two methods getData() and setData() to convert the data in the Driver class to/from a table form suitable for saving as Json. That way, if you want to add in a new score type or piece of persistent information you only have to add a line to each of these two methods. Note that, in this case, "packStars", "trackStars" and "trophies" are actually tables of additional data, not just scalars like numbers or strings. You can see that using Json makes adding these sorts of data types very easy.

    I hope this helps

    best regards
  • techdojotechdojo Guru
    edited February 2013
    I can second the Json approach - it's all I use now, I just serialise a table to JSON, save the string out, then read it back and decode the JSON back to a table, no messing - it just works!

    Attached is the library I currently use.

    And here's some code to use it
    		local file = io.open("|D|settings.json","r")
    		local settings
     
    		if file ~= nil then
     
    			local data = file:read("*a")
    			settings = Json.Decode(data)
     
    			io.close(file)
    		end
     
     
     
                   local file = io.open("|D|settings.json","w")
     
    		if file == nil then 
    			ALERT("WARNING","Can't write settings file")
    			return 
    		end
     
    		local data = Json.Encode(self.parent.settings)
     
    		file:write(data)
    		io.close(file)
    The other advantage is that I can script all my data files in JSON or look at / edit the saved files as they're just ascii.
    zip
    zip
    json.zip
    4K
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • Interestingly, I've just discovered that this:
    file:write(HiScore,"\n")
    will not work on Mac OS X even though it works perfectly fine on Windows 7.
    On OS X, I need to use:
    file:write(HiScore .. "\n")
    I wonder why the difference?
    I only noticed when I worked on the code on Windows and it was working, but testing the same code on OS X would crash the Gideros Player.
    The Ultimate Guide says to use the method above with a comma. I guess it wasn't tested on all platforms.
    Gideros Tutorials and Mobile apps:
    http://BlueBilby.com/
  • Using the comma usually inserts a tab between the strings, whilst .. is the proper lua string concatenation operator.
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • Not on Windows it doesn't ;)
    In fact. If I save a score on Windows, eg. 2750. It works fine with a comma.
    If I use the comma in OSX the value saved is either of these:
    0.
    0.0
    5.
    Or something else totally different. No tab but a dot added for no reason and the wrong value.
    Also, I read in a tutorial somewhere that the comma is the preferred way to do it. Will have to try and find it.
    Gideros Tutorials and Mobile apps:
    http://BlueBilby.com/
  • BJGBJG Member
    edited February 2013
    >I read in a tutorial somewhere that the comma is the preferred way to do it.

    That's what the Lua manual seems to indicate.
    The io.write function simply gets an arbitrary number of string arguments and writes them to the current output file. Numbers are converted to strings following the usual conversion rules; for full control over this conversion, you should use the format function, from the string library:

    > io.write("sin (3) = ", math.sin(3), "\n")
    --> sin (3) = 0.1411200080598672
    > io.write(string.format("sin (3) = %.4f\n", math.sin(3)))
    --> sin (3) = 0.1411

    Avoid code like io.write(a..b..c); the call io.write(a,b,c) accomplishes the same effect with fewer resources, as it avoids the concatenations.
    http://www.lua.org/pil/21.1.html
  • BJGBJG Member
    edited February 2013
    I just installed the latest Gideros release (2012.09.9) on OSX 10.6.7 to check this out. Like @WauloK I find that when using strings, then the form suggested in the Lua manual:
       file:write("one", "two", "three")
    ...works to give "onetwothree" on PC and Mac.

    When you introduce numbers, eg:
         file:write("one", 2, "three")
    ...then you'll get "one2three" on a PC, but unpredictable results like "one-three" on a Mac.

    If you use "tostring" to do the conversion explicitly...
       file:write("one", tostring(2), "three")
    ...then it works on Mac, so something seems to have gone awry with automatic type conversion in this context.

    Likes: WauloK

    +1 -1 (+1 / -0 )Share on Facebook
  • It may be something @atilim needs to look at.
    Gideros Tutorials and Mobile apps:
    http://BlueBilby.com/
Sign In or Register to comment.