Some problems with Rob Miracle's json saving method

Hello!

I’m trying to use the “Rob Miracle’s json saving method” (https://forums.coronalabs.com/topic/37893-rob-miracles-json-saving-method/) to save a high score in my game, but I let some an error, because

“High score” is always equal to “score”, and the highest value is not saved.

In game.lua

local function isNewHighScore () local isNewScore = score \> highscore if isNewScore then highscore = score end end local t = {} t.number = score loadsave.saveTable(t, "isNewScore.json", system.DocumentsDirectory) newTable = loadsave.loadTable("isNewScore.json", system.DocumentsDirectory) loadsave.printTable(newTable) highcoreText = display.newText( score, 220, 243, native.systemFont, 24 )

In loadsave.lua

local M = {} local json = require("json") local \_defaultLocation = system.DocumentsDirectory local \_realDefaultLocation = \_defaultLocation local \_validLocations = { [system.DocumentsDirectory] = true, [system.CachesDirectory] = true, [system.TemporaryDirectory] = true } function M.saveTable(t, filename, location) if location and (not \_validLocations[location]) then error("Attempted to save a table to an invalid location", 2) elseif not location then location = \_defaultLocation end local path = system.pathForFile( filename, location) local file = io.open(path, "w") if file then local contents = json.encode(t) file:write( contents ) io.close( file ) return true else return false end end function M.loadTable(filename, location) if location and (not \_validLocations[location]) then error("Attempted to load a table from an invalid location", 2) elseif not location then location = \_defaultLocation end local path = system.pathForFile( filename, location) local contents = "" local myTable = {} local file = io.open( path, "r" ) if file then -- read all contents of file into a string local contents = file:read( "\*a" ) myTable = json.decode(contents); io.close( file ) return myTable end return nil end function M.changeDefault(location) if location and (not location) then error("Attempted to change the default location to an invalid location", 2) elseif not location then location = \_realDefaultLocation end \_defaultLocation = location return true end function M.print\_r ( t ) local print\_r\_cache={} local function sub\_print\_r(t,indent) if (print\_r\_cache[tostring(t)]) then print(indent.."\*"..tostring(t)) else print\_r\_cache[tostring(t)]=true if (type(t)=="table") then for pos,val in pairs(t) do if (type(val)=="table") then print(indent.."["..pos.."] =\> "..tostring(t).." {") sub\_print\_r(val,indent..string.rep(" ",string.len(pos)+8)) print(indent..string.rep(" ",string.len(pos)+6).."}") elseif (type(val)=="string") then print(indent.."["..pos..'] =\> "'..val..'"') else print(indent.."["..pos.."] =\> "..tostring(val)) end end else print(indent..tostring(t)) end end end if (type(t)=="table") then print(tostring(t).." {") sub\_print\_r(t," ") print("}") else sub\_print\_r(t," ") end print() end M.printTable = M.print\_r return M

I’m not sure but why you don’t do

newTable = loadsave.loadTable("isNewScore.json", system.DocumentsDirectory) local highscore = newTable.number -- I would use 'highscore' instead of 'number':) ... local highcoreText = display.newText( highscore , 220, 243, native.systemFont, 24 )

In the case high score changed you can use

 highcoreText.text = highscore

What is more you can find isNewScore.json by select File->Show Project Sandbox in Simulator. In new window go to Documents folder. So after highscore should be saved you can check what highscore value is. 

Hi,

You’d probably want something like:

local highscoreText local function isNewHighScore (score) local highscore = tonumber(highscoreText.text) if score \> highscore then return score end return highscore end loadsave.saveTable({ score = isNewHighScore(score) }, "isNewScore.json", system.DocumentsDirectory) newTable = loadsave.loadTable("isNewScore.json", system.DocumentsDirectory) loadsave.printTable(newTable) highscoreText = display.newText( score, 220, 243, native.systemFont, 24 )

Hope that helps.

-dev

@Idurniat

I changed the code the way you wrote it.

In the file “isNewScore.json” the score changes, but when I return to the “menu.lua” scene and switch to the scene “game.lua”, the value is zero ;(((

@Develephant

22:02:23.012  ERROR: Runtime error

22:02:23.012  C:\Users\wwww\Desktop\GAME\game.lua:1656: attempt to index upvalue ‘highscoreText’ (a nil value)

22:02:23.012  stack traceback:

22:02:23.012  C:\Users\wwww\Desktop\GAME\game.lua:1656: in function ‘isNewHighScore’

22:02:23.012  C:\Users\wwww\Desktop\GAME\game.lua:1663: in function ‘?’

22:02:23.012  ?: in function <?:190>

Something is wrong(

@borrrz - Do you think there is a problem with Rob’s code (which hundreds of folks have used w/o issues) or something else is going on?

I’m not asking to be confrontational, but I do want to point out, the problem is likely in the way you’re using it.

PS - Kudos by the way for posting your code and the code you used from Rob.  That is awesome.

PPS - I probably misread the title, I’m guessing you meant 'having some problems using Rob’s …"  

I’ll think about this a little bit more and offer some solutions shortly.

I heavily modified your code (may contain typos).

local scoreTable local score = 0 -- local highScoreLabel = display.newText( score, 220, 243, native.systemFont, 24 ) -- --- local function saveScoreData() loadsave.saveTable( scoreTable, "score.json", system.DocumentsDirectory) end -- local function restoreScoreData() scoreTable = loadsave.loadTable( "score.json", system.DocumentsDirectory) or { highScore = 0 } end -- local function checkForhighScore() if( score \> scoreTable.highScore ) then scoreTable.highScore = score highScoreLabel.text = tostring(score) saveScoreData() end end -- local function dumpScoreData() loadsave.printTable(scoreTable) end restoreScoreData()

Let me suggest, that if you wanted to you could also store/restore your scores using SSK2 persist:
https://roaminggamer.github.io/RGDocs/pages/SSK2/libraries/persist/
 
This is a ‘arbitrary data storage’ system that also has auto-caching and delayed writes to avoid performance hits writes for cases just like this, where the score might be changing very frequently.  
 
Tip: Writing to storage many times per second can slow down your game, so updating the score table saved ‘on disk’ like you’re doing can have negative side-effects.
 
Assuming you have SSK2 installed in your project, using persist would look like this:
 
main.lua

ssk.persist.setDefault( "score.json", "highScore", 0 )

your code (elsewhere):

local score = 0 -- localize persist calls to speed up code local pGet = ssk.persist.get local pSet = ssk.persist.set -- local highScoreLabel = display.newText( score, 220, 243, native.systemFont, 24 ) -- local function checkForhighScore() if( score \> pGet( "score.json", "highScore" ) ) then pSet( "score.json", "highScore" , score ) highScoreLabel.text = tostring(score) end end -- local function dumpScoreData() print("High score: ", pGet( "score.json", "highScore" ) ) end

@roaminggamer

Sorry, I use google translator to communicate, because I started to learn English not so long ago.

Yes, the problem is that I’m using it incorrectly. Thank you for the solutions provided, as soon as I test them, I will write about the result)

@roaminggamer - I liked your SSK2 utility, it’s amazing.

Maybe I explained it wrong the first time.

I would like this line to write a high score:

local highScoreLabel = display.newText( score, 220, 243, native.systemFont, 24 )

I installed SSK2, inserted your code, but in the file “score.json” the value does not change: {“defaults”:{“highScore”:0}}.

I tried to use EGO before that. Everything worked perfectly, but I do not like the fact that a high score was shown after the application was restarted.

I hope you can help me fix this)

There are many ways to save data.  If I’m being honest, my loadsave code, as happy as I am with it’s success is overkill if you are only saving one value. If you have much more complex save data, it’s great. Take a Lua table, save a JSON file with one line of code. Load it back in when the app starts and you have a table of settings.

But since I created that, we’ve added new API’s that make setting storage and retrieval a bit easier.  Look at:

system.setPreferences() and system.getPreferences()

https://docs.coronalabs.com/api/library/system/setPreferences.html

https://docs.coronalabs.com/api/library/system/getPreference.html

But I don’t think storage of the value seems to be the main issue as much as it is tracking the current score value, the all time high score value, displaying the current score and displaying the all time high score.

For instance, you don’t need to store the current score. If your using modules for different scenes like using Composer, you may need to pass the current score value between your game scene and your game over/high score scene. You only need to store your all time high score. You need to test to see if your latest current score is greater than the all time high score and then store the high score if it’s higher.

The loadsave code is hard to mess up if you have a Lua table of values to save.

Rob

Please be aware, I didn’t answer with code using Rob’s solution because I like to answer with code I’m familiar with.

His code is great and will perfectly suit your needs / solve your problem.  

https://github.com/roaminggamer/RG_FreeStuff/raw/master/AskEd/2018/03/highScore.zip

That said, I’m going to give you a working example that shows you how to track ‘high’ score from run to run using SSK2 and persist.

You can modify my example to use Rob’s code easy-peasy  OK?

https://www.youtube.com/watch?v=Pc7eT4MZGPg&feature=youtu.be

@Rob Miracle - Yes, I read this, but for now it’s quite difficult for me. Thank you for responding)

@roaminggamer - Wow, thank you so much for such a detailed response)

I’ll try it tomorrow, I already have 4:25 a.m. and I need to sleep)

@roaminggamer - My enemy is my inattention.

I skipped this line:

checkForNewHighScore()

Thank you) I could not solve this without your help :slight_smile:

Hi,

I’m putting this here in case anyone in the future needs it https://marketplace.coronalabs.com/plugin/score-keeper

-dev

I’m not sure but why you don’t do

newTable = loadsave.loadTable("isNewScore.json", system.DocumentsDirectory) local highscore = newTable.number -- I would use 'highscore' instead of 'number':) ... local highcoreText = display.newText(&nbsp;highscore&nbsp;, 220, 243, native.systemFont, 24 )

In the case high score changed you can use

&nbsp;highcoreText.text =&nbsp;highscore

What is more you can find isNewScore.json by select File->Show Project Sandbox in Simulator. In new window go to Documents folder. So after highscore should be saved you can check what highscore value is. 

Hi,

You’d probably want something like:

local highscoreText local function isNewHighScore (score) local highscore = tonumber(highscoreText.text) if score \> highscore then return score end return highscore end loadsave.saveTable({ score = isNewHighScore(score) }, "isNewScore.json", system.DocumentsDirectory) newTable = loadsave.loadTable("isNewScore.json", system.DocumentsDirectory) loadsave.printTable(newTable) highscoreText = display.newText( score, 220, 243, native.systemFont, 24 )

Hope that helps.

-dev

@Idurniat

I changed the code the way you wrote it.

In the file “isNewScore.json” the score changes, but when I return to the “menu.lua” scene and switch to the scene “game.lua”, the value is zero ;(((

@Develephant

22:02:23.012  ERROR: Runtime error

22:02:23.012  C:\Users\wwww\Desktop\GAME\game.lua:1656: attempt to index upvalue ‘highscoreText’ (a nil value)

22:02:23.012  stack traceback:

22:02:23.012  C:\Users\wwww\Desktop\GAME\game.lua:1656: in function ‘isNewHighScore’

22:02:23.012  C:\Users\wwww\Desktop\GAME\game.lua:1663: in function ‘?’

22:02:23.012  ?: in function <?:190>

Something is wrong(