a question about Roblox studio, or rather, about dataStore. If you save the values directly in the script by the pointsStore:SetAsync ("Mars", 19) when outputting data:GetCurrentPage() - this value is output, but if you do this via a function, the value is saved, but does not appear when the data:GetCurrentPage(). How can I save user data?
save the values directly in the script:
PlayerPoints:SetAsync("Mars", 19)
local success, err = pcall(function()
local Data = PlayerPoints:GetSortedAsync(false, 5)
local WinsPage = Data:GetCurrentPage()
print(WinsPage)
end)
save the values directly in the function:
local function givePointsPlayer(player, points)
local pointsOld = pointsStore:GetAsync(player.Name.."&"..tostring(player.UserId).."&"..tostring(os.date("*t").month))
if (pointsOld == nil) then
pointsOld = 0
end
print(pointsOld)
local success, err = pcall(function()
pointsStore:SetAsync(
player.Name.."&"..tostring(player.UserId).."&"..tostring(os.date("*t").month),
pointsOld + points
)
end)
end
EventEditPointsPlayer.OnServerEvent:Connect( function(player, points)
givePointsPlayer(player, points)
end)
answer:
answer
how do I need to save user data so that it is output via :GetCurrentPage() ??
If you want to get the data from the pages, you need to write some code to go through each entry and page. Here's an example from the DevHub tutorial:
-- Sort data into pages of three entries (descending order)
local pages = characterAgeStore:GetSortedAsync(false, 3)
while true do
-- Get the current (first) page
local data = pages:GetCurrentPage()
-- Iterate through all key-value pairs on page
for _, entry in pairs(data) do
print(entry.key .. ":" .. tostring(entry.value))
end
-- Check if last page has been reached
if pages.IsFinished then
break
else
print("----------------")
-- Advance to next page
pages:AdvanceToNextPageAsync()
end
end
For more information, see this tutorial from Roblox DevHub: https://developer.roblox.com/en-us/articles/Data-store
Related
I wrote a door save system.
That is, if the user previously bought them, then when re-entering the game, they must be open.
My code works, but the door doesn't save at all.
-- DoorsDataStore
-- Save Stats Doors
local opend = false
local datastorage = game:GetService("DataStoreService")
local isitopen_1 = datastorage:GetDataStore("Door")
game.Players.PlayerAdded:Connect(function(player)
local boolValueDoors = Instance.new("Folder")
boolValueDoors.Name = "BoolValueDoors"
boolValueDoors.Parent = player
local door_1 = Instance.new("BoolValue")
door_1.Parent = boolValueDoors
door_1.Name = "BoolValueDoor_1"
door_1.Value = isitopen_1:GetAsync(player.UserId)
print("True or False")
print(player.BoolValueDoor_1.Value)
end)
game.Players.PlayerRemoving:Connect(function(player)
local success, erromsg = pcall(function()
isitopen_1:SetAsync(player.UserId, player.BoolValueDoor_1.Value)
end)
if erromsg then
warn("Error")
end
end)
-- TouchDoor
script.Parent.Touched:Connect(function(hit)
local humanoid = hit.Parent:FindFirstChild("Humanoid")
if (humanoid ~= nil) then
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player.leaderstats.Coins.Value >= script.Parent.Price.Value then
player.leaderstats.Coins.Value -= script.Parent.Price.Value
player.leaderstats.Level.Value += 1
script.Parent:Destroy()
player.BoolValueDoors.BoolValueDoor_1.Value = true
print("Save Door")
end
end
end)
I tried writing this code in different ways, in different versions, tried through validation. My code still doesn't do what I want.
There are multiple possible problems I see:
1.
SetAsync takes a string as the first argument, you are giving it a number value. To fix this use tostring(player.UserId)
2.
When the player first joins, the value will be set to nil, because there is no data in the datastore under the UserId, and nil is not a boolean.
I’m not sure if these are actual issues and I currently cannot check if these are real problems because I’m not on my computer but they may be something you want to change.
Also it would be nice to know if you encountered any errors when executing the code.
You should also make trigger a remote event that opens the door on the clientside in the PlayerAdded function if the value is true.
bear with me but this is my first post so unsure of general formats etc.
I am currently testing with my first data store system on ROBLOX. After following a tutorial I managed to get a data store to store, load and save a cash value specified to the userID that went into the leaderboard. I am currently trying to edit the system to work with a value saved to the player, rather than a leaderstat value but it doesn't seem to be either loading or saving the value correctly.
If you take a look at the code below it is set up to print out strings to confirm the saving/loading has worked but it does not either load or save the value correctly.
Currently the script loads the value and a separate localscript displays the value as text to a display gui with two buttons than can either increase or decrease the value.
I am very new to ROBLOX Lua, so any help would be greatly appreciated.
Script located within ServerScriptService:
local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("DataStore")
local data2
game.Players.PlayerAdded:Connect(function(player)
local SusTune = Instance.new("Folder")
SusTune.Name = "SusTune"
SusTune.Parent = player
local fcamber = Instance.new("IntValue")
fcamber.Name = "fCamber"
fcamber.Parent = SusTune
local success, errormessage = pcall(function()
data2 = myDataStore:GetAsync(player.UserId.."-FC")
end)
if success then
fcamber.Value = data2
print("Successfully loaded data!")
print(fcamber.Value)
else
warn(errormessage)
print("There was an error while getting your data.")
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local success, errormessage = pcall(function()
myDataStore:SetAsync(player.UserId.."-FC",player.SusTune.fCamber.Value)
end)
if success then
print("Data saved successfully!")
else
print("There was an error when saving data.")
warn(errormessage)
end
end)
LocalScript located within gui button:
local counterDisplay = script.Parent
local increaseButton = script.Parent.Parent.Increase
local decreaseButton = script.Parent.Parent.Decrease
local counter = game.Players.LocalPlayer.SusTune.fCamber.Value
counterDisplay.Text = counter
increaseButton.MouseButton1Click:Connect(function()
print("+1 added")
counter += 1
game.Players.LocalPlayer.SusTune.fCamber.Value = counter
counterDisplay.Text = counter
end)
decreaseButton.MouseButton1Click:Connect(function()
print("-1 added")
counter -= 1
game.Players.LocalPlayer.SusTune.fCamber.Value = counter
counterDisplay.Text = counter
end)
I have personally tried comparing this version to the working cash version but cannot work out why its not working. If its something really silly or simple I am going to hate myself and feel like an idiot, but been staring at it for an hour so need some help. Many thanks in advance :)
EDIT:
I think I have managed to narrow down the error.
When running the game and using console the buttons do not change the fCamber.Value BUT when running it in studio you can visually see the value changing with each button click, also confirmed by the ‘+/-1 added’ which is outputted in both studio and Roblox console.
After using SetASync in the main script, I had the script output the value it had just saved using a GetASync immediately afterwards (for testing purposes) and it seems the value itself is not saving to the data store.
I’m not sure if this extra data will benefit or not, but thought it would be a good detail to add.
z32
Im trying to make an experience script. The only thing I can't seem to figure is Data Saving. Im using file.Write and whenever I have my script read the player's level and experience from the data, it doesnt show up. I have my variables xp equal to 0 and level equal to 1. If I wanted to save the number I assigned or any number added to this to equal a new one to a txt file using file.Write as well as having that data read whenever a player spawns, how could I accomplish this?
local xp = 0
local level = 1
local players = player.GetAll()
for k ,v in pairs(players) do
file.Write("xpdata.txt", xp)
file.Write("leveldata.txt", level)
end
hook.Add("PlayerSpawn", "leveldata", function()
file.Read("xpdata.txt", "DATA")
file.Read("leveldata.txt", "DATA")
end)
I think you need to use json.
I can't write now a whole example but you can have a look at this page https://wiki.gideros.rocks/index.php/Start_Here#Save.2Fread_data_persistently
maybe that can help you understand the concept.
What do you expect to happen if you just read a file into nirvana?
hook.Add("PlayerSpawn", "leveldata", function()
file.Read("xpdata.txt", "DATA")
file.Read("leveldata.txt", "DATA")
end)
Here you read two files but you don't do anything with the return values.
file.Read returns a string with the files contents if successful.
You need to do something with the return value.
local xpData = file.Read("xpdata.txt", "DATA")
if not xpData then
print("Reading data/xpdata.txt failed!")
else
print("XP: ", xpData)
end
Of course you should store that data per player and make sure each player gets its own xp assigned.
local xp = 0
local level = 1
local players = player.GetAll()
for k ,v in pairs(players) do
file.Write("xpdata.txt", xp)
file.Write("leveldata.txt", level)
end
This doesn't make too much sense as well.
You're writing to the same file for every player. Each loop cycle will overwrite the file of the cycle before.
Also having the same xp and level for each player won't help much.
So either you have one file per player or you have some kind of structure in that common file that allows you to write and read player specific data.
You need to "serialize" your data befor you write it to the file and deserialize it later.
This can be achieved by using two utility functions
https://wiki.facepunch.com/gmod/util.TableToJSON
https://wiki.facepunch.com/gmod/util.JSONToTable
Then you can do something like this
local playerData = {}
-- for each player
for k, player in pairs(players) do
-- add a table with xp and lvl so you can later access it by AccountID
playerData[player.AccountID] = {xp = player.xp, lvl = player.lvl}
end
local jsonStr = util.TableToJSON(playerData)
file.Write("playerdata.xp", jsonStr")
I'll leave the rest up to you so you can learn something.
I've never liked the default window switching possibilities in Awesome, so I thought I'd implement Alt-Tab behavior that takes history into account (and does fancy opacity effects).
When Alt-Tab is pressed, the entire history is recorded in a table, and appended to that history are the minimized windows (within the same tag). When this table is generated, I instantiate a keygrabber that captures Tab-press events (to switch to the next client in the table) and Alt-release events (to abort entirely).
A flag keeps track of whether the user is in the process of Alt-tabbing, to prevent the table from being generated over and over again.
The code (it's a lot and you probably don't need to see it, but my experience tells me that when I don't post all the code, people will ask for it eventually):
altTabbing = false
altTabIndex = 1
altTabHistory = {}
clientOpacities = {}
function altTabSetOpacities(restore)
for i,c in pairs(altTabHistory) do
if not restore and i ~= altTabIndex then
c.opacity = 0.5
else
c.opacity = clientOpacities[i]
end
end
end
function myAltTab()
-- First check if the user is already alttabbing, in which case the history
-- should NOT be updated. If the user has just pressed alt-tab, generate a new
-- history-table
if not altTabbing then -- generate history-table
-- Clear Tables
for i in pairs(altTabHistory) do altTabHistory[i] = nil end
for i in pairs(clientOpacities) do clientOpacities[i] = nil end
-- Get focus history for current tag
local s = mouse.screen;
local idx = 0
local c = awful.client.focus.history.get(s, idx)
while c do
table.insert(altTabHistory, c)
table.insert(clientOpacities, c.opacity)
idx = idx + 1
c = awful.client.focus.history.get(s, idx)
end
-- Minimized clients will not appear in the focus history
-- Find them by cycling through all clients, and adding them to the list
-- if not already there.
-- This will preserve the history AND enable you to focus on minimized clients
local t = awful.tag.selected(s)
local all = client.get(s)
for i = 1, #all do
local c = all[i]
local ctags = c:tags();
-- check if the client is on the current tag
local isCurrentTag = false
for j = 1, #ctags do
if t == ctags[j] then
isCurrentTag = true
break
end
end
if isCurrentTag then
-- check if client is already in the history
-- if not, add it
local addToHistory = true
for k = 1, #altTabHistory do
if altTabHistory[k] == c then
addToHistory = false
break
end
end
if addToHistory then
table.insert(altTabHistory, c)
table.insert(clientOpacities, c.opacity)
end
end
end
-- reset current index and flag
altTabIndex = 1
altTabbing = true
-- Now that we have collected all windows, we should run a keygrabber
-- as long as the user is alt-tabbing:
keygrabber.run(
function (mod, key, event)
-- Stop alt-tabbing when the alt-key is released
if key == "Alt_L" and event == "release" then
altTabbing = false
altTabSetOpacities(true)
c = altTabHistory[altTabIndex]
client.focus = c
c:raise()
return false -- stop keygrabber
end
-- Move to next client on each Tab-press
if key == "Tab" and event == "press" then
myAltTab()
return true -- keep going
end
return true -- keep going
end
)
end -- if not altTabbing
-- at this point, the user is alt-tabbing, so we should raise
-- the next client in the history-table
if #altTabHistory < 2 then return end
-- Switch to next client
altTabIndex = altTabIndex + 1
if altTabIndex > #altTabHistory then
altTabIndex = 1 -- wrap around
end
-- focus on current client
local c = altTabHistory[altTabIndex]
c.minimized = false
c:raise()
-- make current client stand out
altTabSetOpacities(false)
end
I realize there's a lot of code, but the main thing is the keygrabber. For still unknown reasons, Awesome sometimes crashes while I'm Alt-Tabbing using this approach. I want to replace the keygrabber by connecting signals to the Alt and Tab keys, and disconnecting them as soon as the user is done. However, I'm not able to do this for some reason.
I instantiate a new key-object like this:
local altkey = awful.key({}, "Alt_L")[1]
I found out by trial and error that awful.key() actually returns a table of which I could query the first element for key, keysym etc, hence the [1]. However, when I try to connect a signal to this object, the LUA interpreter complains and tells me it's a nil object. So my question is: am I doing the right thing here? Is it even possible to replace the keygrabber in the way I intend to?
To use the Alt_L key in Awesome you should refer to "Mod1" in your rc.lua file, to make it mor readable I added the following line to the beginning of my configuration so Alt_L can be used.
Alt_L = "Mod1"
I can't figure out how to put the objects created by a simple function in a table, to have them figure as individual identities..
E.g.
local function spawncibo()
nuovoCibo = display.newImage("immagini/cibo/cibo001.png")
end
timer.performWithDelay(1500, spawncibo, -1)
I tried to do it with a for loop, but it doesn't work (if i try to print the table I always get a nil result).
Any suggestion would be immensely appreciated!
Providing I have correctly understood your question, you may try something like this :
local cibo = {}
local function spawncibo()
cibo[#cibo+1] = display.newImage(string.format(
"immagini/cibo/cibo%3d.png", #cibo+1))
end
timer.performWithDelay(1500, spawncibo, -1)
This will read files cibo001.png, cibo002.png, ... every 1.5 s and put all images into the cibo array.
local spawnedCibos = {}
local function spawncibo()
nuovoCibo = display.newImage("immagini/cibo/cibo001.png")
table.insert(spawnedCibos, nuovoCibo);
end
timer.performWithDelay(1500, spawncibo, -1);
local function enterFrameListener( event )
for index=#spawnedCibos, 1, -1 do
local cibo = spawnedCibos[index];
cibo.x = cibo.x + 1;
if cibo.x > display.contentWidth then
cibo:removeSelf();
table.remove(spawnedCibos, index);
end
end
end
You could try this...
local spawned = {} -- local table to hold all the spawned images
local timerHandle = nil -- local handle for the timer. It can later be used to cancel it if you want to
local function spawnCibo()
local nuovoCibo = display.newImage('immagini/cibo/cibo001.png')
table.insert(spawned, nuovoCibo) -- insert the new DisplayObject (neovoCibo) at the end of the spawned table.
end
local function frameListener()
for k, v in pairs(spawned) do -- iterate through all key, value pairs in the table
if (conditions) then -- you will probably want to change conditions to some sort of method to determine if you want to delete the cibo
display.remove(spawned[k]) -- remove the part of the object that gets rendered
spawned[k] = nil -- remove the reference to the object in the table, freeing it up for garbage collection
end
end
end
timer.performWithDelay(1500, spawnCibo, 0) -- call spawnCibo() every 1.5 seconds, forever (That's what the 0 is for) or until timer.cancel is called on timerHandle
Runtime:addEventListener('enterFrame', frameListener) --
If you've got any other questions, feel free to ask.