json parsing not working on device on Corona - storage

Json parsing is not working on devices while works perfect on simulator, that scene could not be open where I read or write some data.
I have made a class for Json parsing
Here it is,
module(..., package.seeall)
local json=require ("json")
function saveTable(t,filename)
local path = system.pathForFile(filename, system.DocumentsDirectory)
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 loadTable(filename)
local path = system.pathForFile(filename, system.DocumentsDirectory)
local contents = ""
local myTable = {}
local file = io.open(path,"r")
if file then
local contents = file:read("*a")
myTable = json.decode(contents)
io.close(file)
return myTable
end
return nil
end
I actually want an alternative of NSUserDefaults on Corona.
Any help?

Yea, I got it, I used to loadTable first, without saving table, so it would be a problem, never call loadTable before save table :)

Related

invalid argument #3 (Instance expected, got string)

I was looking for a solution of this issue in search engines, but can't find one.
Though there's one that is almost identical, which is 'Invalid Argument #2 (String Expected, got Instance)', I tried looking ways to fix it in reverse, but it uses tostring(), and my issue is about the newest feature: Instance Attributes, which it doesn't support Instances as value, and the only thing I could do is to convert it as a string, now that the issue is about the Part.Parent, which uses Adornee/Instance or something on which I don't know the workaround for this
local LocalPlayer = Players.LocalPlayer;
local Mouse = LocalPlayer:GetMouse();
local function Part_Hide()
if (Toggle_MouseHover == true and Mouse.Target ~= nil) then
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") == nil) then
local Model = Instance.new ("Model", ReplicatedStorage);
Model.Name = "[Part_Storage]";
--Mouse.Target:SetAttribute("Source", Mouse.Target:GetFullName())
Mouse.Target:SetAttribute("Source", Mouse.Target.Name)
Mouse.Target.Parent = Model;
else
local Model = ReplicatedStorage:FindFirstChild("[Part_Storage]");
--Mouse.Target:SetAttribute("Source", Mouse.Target:GetFullName())
Mouse.Target:SetAttribute("Source", Mouse.Target.Name)
Mouse.Target.Parent = Model;
end
end
end
local function Part_Unhide()
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") ~= nil) then
local Storage = ReplicatedStorage:FindFirstChild("[Part_Storage]");
for _, Child in pairs (Storage:GetChildren()) do
--local Source = Child:GetAttribute("Source");
--Child.Parent = Source
Child.Parent = Child:GetAttribute("Source"); -- <-- Cause of the issue
end
end
end
I don't know if there's a way for an Attribute to accept Instances as value
Child.Parent = Child:GetAttribute("Source");
Is there a way to either convert String into an Instance, or an alternative way of saving an Instance as a value, or any kinds of workarounds for this issue? If so, answers are appreciated, thanks in advance!
As you've pointed out, Instances aren't acceptable as an Attribute type.
One workaround might be to create an ObjectValue instead, and use that to hold onto the Instance reference. You can stuff it into the object before moving it over to ReplicatedStorage, and then just delete it when you pull it out of storage.
local LocalPlayer = Players.LocalPlayer
local Mouse = LocalPlayer:GetMouse()
-- if the container for part storage doesn't exist, create it
local PartStorage = ReplicatedStorage:FindFirstChild("[Part_Storage]")
if (PartStorage == nil) then
PartStorage = Instance.new("Model", ReplicatedStorage)
PartStorage.Name = "[Part_Storage]"
end
local function Part_Hide()
if (Toggle_MouseHover == true and Mouse.Target ~= nil) then
-- alias the Mouse Target
local Part = Mouse.Target
local PartSource = Part.Parent
-- move the part to storage
Part.Parent = PartStorage
-- hold onto the reference to where this object came from
local ParentRef = Instance.new("ObjectValue")
ParentRef.Value = PartSource
ParentRef.Name = "ParentRef"
ParentRef.Parent = Part
end
end
local function Part_Unhide()
-- move all parts out of storage
for _, Child in pairs (PartStorage:GetChildren()) do
-- remove the ObjectValue from the child
local PartSource = Child:FindFirstChild("ParentRef")
PartSource.Parent = nil
-- place the child back into the world
Child.Parent = PartSource.Value
-- clean up
PartSource:Destroy()
end
end
As a small note, unless this is intended, you shouldn't do these kinds of world changing operations in a LocalScript, as those changes will only show up for the player that owns the LocalScript. The changes will be replicated to all players if you perform the work in a serverside Script.
I finally managed to make it work, thank you #Kylaaa
Turns out that your method of ObjectValue really works! I was looking for something like that, which holds a value of an instance, though I end up finding Roblox's newest feature and began focusing on it instead (which was my first mistake)
The second mistake was me not using aliases, because I thought using Instance properties/attributes directly would just work same as one being aliased and the alias part would be just for decoration or something that just adds for a line(something like making it easy for reference)
This is now the complete code:
local function Part_Hide()
if (Toggle_MouseHover == true and Mouse.Target ~= nil) then
local Part = Mouse.Target;
local Part_Source = Part.Parent;
local Source = Instance.new ("ObjectValue", Part);
Source.Value = Part_Source;
Source.Name = "Source";
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") == nil) then
local Model = Instance.new ("Model", ReplicatedStorage);
Model.Name = "[Part_Storage]";
Part.Parent = Model;
else
local Model = ReplicatedStorage:FindFirstChild("[Part_Storage]");
Part.Parent = Model;
end
end
end
local function Part_Unhide()
if (ReplicatedStorage:FindFirstChild("[Part_Storage]") ~= nil) then
local Storage = ReplicatedStorage:FindFirstChild("[Part_Storage]");
for _, Child in pairs (Storage:GetChildren()) do
local Source = Child:FindFirstChild("Source");
Child.Parent = Source.Value;
Source:Destroy();
Storage:Destroy();
end
end
end

How do you update one variable in a load-save table in corona SDK

Is it possible to update one variable of a table using the load/save json saving method?I want to change one value/variable in another .lua file. How do I accomplish this?
My main.lua:
local table = {}
table.one = "no"
table.two = "no"
table.three = "no"
loadsave.saveTabe(table, "trying.json", system.DocumentsDirectory)
in check.lua:
local value = loadsave.loadTable("trying.json, system.DocumentsDirectory)
if( 5+5 == 10)then
value.one = "yes"
--HERE I WANT TO SAVE THE VALUE TO THE SAME JSON FILE WITHOUT CHANGING THE OTHER VALUES/VARIABLES ETC.
end
Try this:
local value = loadsave.loadTable("trying.json", system.DocumentsDirectory)
if( 5+5 == 10) then
value.one = "yes"
loadsave.saveTable(value, "trying.json", system.DocumentsDirectory)
end

LUA read text file, make split and send to array

i am new to lua. actually this script use for game server but i need help for getting the value from my store .txt file. so my store system is each players will be save on one file.
Store File
my syntax data from text file
[name]:[points]:[which var point earned on index]
my example data (this var point actually the written data from lua file that sended to text file)
jack:60:4
ronald:40:1
jack:30:1
so when i got from above is the list of
local player = {{(name),(points),(which var point earned on index)},
{(name),(points),(which var point earned on index)},...};
My own code
local line_data = {}
local point_file = io.open("points.txt", "r")
for line in point_file:lines() do
local playername, playerpoint, playervarpointname = line:match("(%d+):(%d+):(%d+)")
local player_data = {playername, playerpoint, playervarpointname}
for i = 1, #line do
player_data = [#player_data + 1] = line[i];
end
line_data[#line_data + 1] = player_data
end
is this the correct code ?
local line_data = {}
local point_file = io.open("points.txt", "r")
for line in point_file:lines() do
local playername, playerpoint, playervarpointname = line:match("([^:]+):(%d+):(%d+)")
local player_data = {playername, playerpoint, playervarpointname}
table.insert(line_data, player_data)
end
Or , imho, '[a-zA-Z0-9]+ ' , may be used instead of '[^:]+'

Corona Writing a file

I am creating a game and need to write the gamedata to a file. I have the game creating the file if its not there and reading the contents of the file (That I put in manually) but I can not get it to write to the file.
local path = system.pathForFile("gameData.gameData", system.DocumentsDirectory)
local myFile
defaultGameData = "It Worked"
if (path) then
myFile = io.open(path, "r")
end
if(myFile) then
print('file')
else
myFile:close()
--io.close(myFile)
myFile = io.open(path, 'w')
myFile:write( "My Test" )
io.close(myFile)
end
myFile = nil
That part works. i then move to the next scene and attempt to write something new
local saveData = "My app state data"
local path = system.pathForFile("gameData.gameData", system.DocumentsDirectory)
local myfile = io.open( path, "w" )
myfile:write( saveData )
io.close( myfile )
But get the error
mainMenu.lua:43: attempt to index local 'myfile' (a nil value)
I know the file is there in the sandbox, and this code was copied from the corona docs. What am I doing wrong???
here are two functions I am using
function SaveTable(t, filename)
local path = system.pathForFile( filename, system.DocumentsDirectory)
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 LoadTable(filename, dir)
if (dir == nil) then
dir = system.DocumentsDirectory;
end
local path = system.pathForFile( filename, dir)
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
Usage:
local t = {
text = "Sometext",
v = 23
};
SaveTable(t, "filename.json");
local u = LoadTable("filename.json");
print(u.text);
print(u.v);
Enjoy!
The error occurs due to the mistake in your code line:
myFile:close()
So either comment the line as:
--myFile:close()
Or do as below (only if you need):
myFile = io.open(path, 'w')
myFile:close()
Keep Coding............. :)
I found the solution. I opened the file to read to see if the file exists. I forgot to close it again before I reopened it in the if statement if the file did exist. I only closed it if it didnt exist.

I have a loadFile error. Lua

I was trying to implement a highscore system into my game but when i try to declare my highscore loadFile I get this error.
Attempt to call global 'loadFile' (a nil value)
Here is my code.
highscore = loadFile ("highscore.txt")
local function checkForFile ()
if highscore == "empty" then
highscore = 0
saveFile("highscore.txt", highscore)
end
end
checkForFile()
print ("Highscore is", highscore)
local function onSystemEvent ()
if playerScore > tonumber(highscore) then
--We use tonumber as highscore is a string when loaded
saveFile("highscore.txt", score)
end
end
Runtime:addEventListener( "system", onSystemEvent )
I am using Corona SDK.
The developers of the corona ask published a nice guide about saving and writing to files, which should fulfill your needs.
Basically you get the path via system.pathForFile and then open it using io.open.
You would do it like this:
local path = system.pathForFile( "highscore.txt", system.DocumentsDirectory )
local file = io.open(path, 'w+')
And then, to get the content of the file:
local content = file:read('*a')
local highscore
if (content ~= null)
highscore = tonumber(content)
// do stuff with the loaded highscore
end
And to write to the file:
file:write(highscore)
The file you are loading is not a Lua file but a text file. So there is no point in using loadfile even if it existed. Use instead io.read with file:read or file:lines (where file is the object returned by io.open()).

Resources