basically, when i tried to make a variable in the data for the players’ kills on each class… it doesnt really save properly… yeah uhh i dont know what im doing wrong, because it does save on the current session but resets when i restart the game in studio.
heres the big script
by the way, ignore all the other stuff. what i really need help with is where i do sessionData[plr.UserId][plrr.class.Value…“KILLS”] = killsgotten. it simply doesnt save, just thought that giving the whole script would help out
local players = game:GetService("Players")
local runs = game:GetService("RunService")
local dataserv = game:GetService("DataStoreService")
local database = dataserv:GetDataStore("data")
local sessionData = {}
local function playerjoin(plr)
local secretvalues = Instance.new("Folder")
secretvalues.Name = "secretstats"
local evensecreter = Instance.new("Folder")
evensecreter.Name = "notvalues"
evensecreter.Parent = secretvalues
local killvalues = Instance.new("Folder")
killvalues.Name = "classkillvalues"
killvalues.Parent = secretvalues
local subs = Instance.new("BoolValue")
subs.Name = "hasSubspace"
subs.Parent = secretvalues
local jugg = Instance.new("BoolValue")
jugg.Name = "hasJuggernaut"
jugg.Parent = secretvalues
local sergy = Instance.new("BoolValue")
sergy.Name = "hasSergeant"
sergy.Parent = secretvalues
local cyboring = Instance.new("BoolValue")
cyboring.Name = "hasCyborg"
cyboring.Parent = secretvalues
local credits = Instance.new("IntValue")
credits.Name = "credits"
credits.Parent = secretvalues
local alltimekills = Instance.new("IntValue")
alltimekills.Name = "allTimeKills"
alltimekills.Parent = secretvalues
local success = nil
local playerData = nil
local attempt = 1
repeat
success, playerData = pcall(function()
return database:GetAsync(plr.UserId)
end)
attempt+=1
if not success then
warn("not success")
task.wait(3)
end
until success or attempt == 5
if success then
if playerData == nil then
print("no data 4", plr.Name, "makin new")
playerData = {
["hasSubspace"] = false,
["hasJuggernaut"] = false,
["hasSergeant"] = false,
["hasCyborg"] = false,
["credits"] = 0,
["allTimeKills"] = 0
}
end
if playerData.hasSubspace == nil then
playerData.hasSubspace = false
end
if playerData.hasJuggernaut == nil then
playerData.hasJuggernaut = false
end
if playerData.hasSergeant == nil then
playerData.hasSergeant = false
end
if playerData.hasCyborg == nil then
playerData.hasCyborg = false
end
if playerData.credits == nil then
playerData.credits = 0
end
if playerData.allTimeKills == nil then
playerData.allTimeKills = 0
end
sessionData[plr.UserId] = playerData
print("loadd data")
else
plr:Kick("sumthin weird happened,, (no this is not secret. your data didnt load so im kicking you alright?)")
end
subs.Value = sessionData[plr.UserId].hasSubspace
subs.Changed:Connect(function()
sessionData[plr.UserId].hasSubspace = subs.Value
end)
jugg.Value = sessionData[plr.UserId].hasJuggernaut
jugg.Changed:Connect(function()
sessionData[plr.UserId].hasJuggernaut = jugg.Value
end)
sergy.Value = sessionData[plr.UserId].hasSergeant
sergy.Changed:Connect(function()
sessionData[plr.UserId].hasSergeant = sergy.Value
end)
cyboring.Value = sessionData[plr.UserId].hasCyborg
cyboring.Changed:Connect(function()
sessionData[plr.UserId].hasCyborg = cyboring.Value
end)
credits.Value = sessionData[plr.UserId].credits
credits.Changed:Connect(function()
sessionData[plr.UserId].credits = credits.Value
end)
alltimekills.Changed:Connect(function()
sessionData[plr.UserId].allTimeKills = alltimekills.Value
end)
print(sessionData[plr.UserId][plr.class.Value.."KILLS"]) -- prints nil
task.spawn(function()
local bindy = Instance.new("BindableEvent")
bindy.Name = "killevent"
bindy.Event:Connect(function(plrr, killsgotten)
if plrr == plr then
if sessionData[plr.UserId][plrr.class.Value.."KILLS"] == nil then -- pls help with this stuff
--table.insert(sessionData[plr.UserId], {[plrr.class.Value.."KILLS"] = killsgotten})
sessionData[plr.UserId][plrr.class.Value.."KILLS"] = killsgotten -- prints the right amount
local instancevalue = killvalues:FindFirstChild(plrr.class.Value)
if instancevalue == nil then
local thiskillvalue = Instance.new("IntValue")
thiskillvalue.Name = plrr.class.Value
thiskillvalue.Value = killsgotten
thiskillvalue.Parent = killvalues
end
print(sessionData[plr.UserId][plrr.class.Value.."KILLS"])
elseif sessionData[plr.UserId][plrr.class.Value.."KILLS"] ~= nil then
sessionData[plr.UserId][plrr.class.Value.."KILLS"] += killsgotten
print(sessionData[plr.UserId][plrr.class.Value.."KILLS"]) -- prints the right amount (in this session)
local instancevaluee = killvalues:FindFirstChild(plrr.class.Value)
if instancevaluee ~= nil then
print("um lets killgive") -- prints
instancevaluee.Value = sessionData[plr.UserId][plrr.class.Value.."KILLS"]
elseif instancevaluee == nil then
print("aww its nil")
end
end
end
end)
bindy.Parent = evensecreter
end)
secretvalues.Parent = plr
end
players.PlayerAdded:Connect(playerjoin)
local function PlayerLeaving(plr)
if sessionData[plr.UserId] then
local success = nil
local errormsg = nil
local attempt = 1
repeat
success, errormsg = pcall(function()
database:SetAsync(plr.UserId, sessionData[plr.UserId])
end)
attempt+=1
if not success then
warn("didnt save now",plr.Name)
task.wait(3)
end
until success or attempt == 5
if success then
else
warn("ddidnt save",plr.Name)
end
end
end
players.PlayerRemoving:Connect(PlayerLeaving)
local function shutdown()
if runs:IsStudio() then
-- if id need to make it not save in studio i would do return here btw so it should theoretically save anyway
end
for i, player in ipairs(players:GetPlayers()) do
task.spawn(function()
PlayerLeaving(player)
end)
end
end
game:BindToClose(shutdown)
oh wait, actually, none of my variables save now!! i wonder what could have happened… cuz they did work before…
I recommend replacing the shutdown function with this:
local function shutdown()
if runs:IsStudio() then
-- if id need to make it not save in studio i would do return here btw so it should theoretically save anyway
task.wait(1) -- You might need to increase the duration, depending on the performance of your PC
end
local x, y = 0, 0
for i, player in ipairs(players:GetPlayers()) do
x += 1
task.spawn(function()
PlayerLeaving(player)
y += 1
end)
end
repeat task.wait() until y == x -- This will prevent the game from shutting down either until the 30 second limit is reached...
-- ...or all of the players in your game's data has a chance to save
end
Studio usually closes the play-test too quickly to give data a chance to save properly, the task.wait will force it to stay open. Functions connected to BindToClose will also stop executing once the code finishes running, it doesn’t take into account any active threads. This means that a repeat task.wait() loop is required to force the game to stay open, either until the 30 second limit is reached, or all the of the players in your game’s data has a chance to save
uhh… i dont think that this is the problem, as, when i do success, errormsg = pcall(function() database:SetAsync(plr.UserId, sessionData[plr.UserId]) print('saved') end) it does indeed print “saved”.
I’m noticing a problem: It seems that sessionData is a mixed table (Has a mixture of numerical keys and string keys)
Mixed tables aren’t recommended to be used for saving data, they can become corrupted when SetAsync converts them into JSON format, causing values to be missing. You should use either an array or a dictionary with string keys only to guarantee that the data is saved correctly
oh uh… i wasnt really intending for it to be a mixed table. it seems that when i try to do sessionData[plr.UserId][plrr.class.Value.."KILLS"] = killsgotten it automatically makes it into an array… uhh how do i make it save as [“”] and not [number]??
You can use the tostring function to convert the player’s user ID into a string (Remember to update any comparisons and indexes, as "123" ~= 123 and sessionData[player.UserId] ~= sessionData[tostring(player.UserId)])
From what I can tell, there doesn’t seem to be a need to change the killsgotten array, but there’s a way that you can optimize it to reduce the amount of data you’re trying to save
Instead of creating a new table for each kill, you could check to see if swordKILLS already exists, and if so, increment its value (You could do the same for the other types of kills, of course)
I found out why that’s happening: sessionData[player.UserId] is an array, but you’re trying to index it using a string. This means that sessionData[player.UserID][plrr.class.Value.."KILLS"] is always nil
I’ll try to fix it, but it might need some adjustments afterwards
local players = game:GetService("Players")
local runs = game:GetService("RunService")
local dataserv = game:GetService("DataStoreService")
local database = dataserv:GetDataStore("data")
local sessionData = {}
local function playerjoin(plr)
local secretvalues = Instance.new("Folder")
secretvalues.Name = "secretstats"
local evensecreter = Instance.new("Folder")
evensecreter.Name = "notvalues"
evensecreter.Parent = secretvalues
local killvalues = Instance.new("Folder")
killvalues.Name = "classkillvalues"
killvalues.Parent = secretvalues
local subs = Instance.new("BoolValue")
subs.Name = "hasSubspace"
subs.Parent = secretvalues
local jugg = Instance.new("BoolValue")
jugg.Name = "hasJuggernaut"
jugg.Parent = secretvalues
local sergy = Instance.new("BoolValue")
sergy.Name = "hasSergeant"
sergy.Parent = secretvalues
local cyboring = Instance.new("BoolValue")
cyboring.Name = "hasCyborg"
cyboring.Parent = secretvalues
local credits = Instance.new("IntValue")
credits.Name = "credits"
credits.Parent = secretvalues
local alltimekills = Instance.new("IntValue")
alltimekills.Name = "allTimeKills"
alltimekills.Parent = secretvalues
local success = nil
local playerData = nil
local attempt = 1
repeat
success, playerData = pcall(function()
return database:GetAsync(plr.UserId)
end)
attempt+=1
if not success then
warn("not success")
task.wait(3)
end
until success or attempt == 5
if success then
if playerData == nil then
print("no data 4", plr.Name, "makin new")
playerData = {
["hasSubspace"] = false,
["hasJuggernaut"] = false,
["hasSergeant"] = false,
["hasCyborg"] = false,
["credits"] = 0,
["allTimeKills"] = 0
}
end
if playerData.hasSubspace == nil then
playerData.hasSubspace = false
end
if playerData.hasJuggernaut == nil then
playerData.hasJuggernaut = false
end
if playerData.hasSergeant == nil then
playerData.hasSergeant = false
end
if playerData.hasCyborg == nil then
playerData.hasCyborg = false
end
if playerData.credits == nil then
playerData.credits = 0
end
if playerData.allTimeKills == nil then
playerData.allTimeKills = 0
end
sessionData[plr.UserId] = playerData
print("loadd data")
else
plr:Kick("sumthin weird happened,, (no this is not secret. your data didnt load so im kicking you alright?)")
end
subs.Value = sessionData[plr.UserId].hasSubspace
subs.Changed:Connect(function()
sessionData[plr.UserId].hasSubspace = subs.Value
end)
jugg.Value = sessionData[plr.UserId].hasJuggernaut
jugg.Changed:Connect(function()
sessionData[plr.UserId].hasJuggernaut = jugg.Value
end)
sergy.Value = sessionData[plr.UserId].hasSergeant
sergy.Changed:Connect(function()
sessionData[plr.UserId].hasSergeant = sergy.Value
end)
cyboring.Value = sessionData[plr.UserId].hasCyborg
cyboring.Changed:Connect(function()
sessionData[plr.UserId].hasCyborg = cyboring.Value
end)
credits.Value = sessionData[plr.UserId].credits
credits.Changed:Connect(function()
sessionData[plr.UserId].credits = credits.Value
end)
alltimekills.Changed:Connect(function()
sessionData[plr.UserId].allTimeKills = alltimekills.Value
end)
print(sessionData[plr.UserId][plr.class.Value.."KILLS"]) -- prints nil
task.spawn(function()
local bindy = Instance.new("BindableEvent")
bindy.Name = "killevent"
bindy.Event:Connect(function(plrr, killsgotten)
if plrr == plr then
local killType = plrr.class.Value.."KILLS"
local valueWasFound = false
local totalKills = 0
for _, v in sessionData[plr.UserId] do
if typeof(v) == "table" and v[killType] then
valueWasFound = true
v[killType] += killsgotten
totalKills = v[killType]
break
end
end
if valueWasFound == false then
table.insert(sessionData[plr.UserId], {[killType] = killsgotten})
totalKills = killsgotten
end
local instancevalue = killvalues:FindFirstChild(plrr.class.Value)
if instancevalue then
instancevalue.Value = totalKills
else
local killsvalue = Instance.new("IntValue")
killsvalue.Name = plrr.class.Value
killsvalue.Value = totalKills
killsvalue.Parent = killvalues
end
print(sessionData[plr.UserId])
end
end)
bindy.Parent = evensecreter
end)
secretvalues.Parent = plr
end
players.PlayerAdded:Connect(playerjoin)
local function PlayerLeaving(plr)
if sessionData[plr.UserId] then
local success = nil
local errormsg = nil
local attempt = 1
repeat
success, errormsg = pcall(function()
database:SetAsync(plr.UserId, sessionData[plr.UserId])
end)
attempt+=1
if not success then
warn("didnt save now",plr.Name)
task.wait(3)
end
until success or attempt == 5
if success then
else
warn("ddidnt save",plr.Name)
end
end
end
players.PlayerRemoving:Connect(PlayerLeaving)
local function shutdown()
if runs:IsStudio() then
-- if id need to make it not save in studio i would do return here btw so it should theoretically save anyway
task.wait(1) -- You might need to increase the duration, depending on the performance of your PC
end
local x, y = 0, 0
for i, player in ipairs(players:GetPlayers()) do
x += 1
task.spawn(function()
PlayerLeaving(player)
y += 1
end)
end
repeat task.wait() until y == x -- This will prevent the game from shutting down either until the 30 second limit is reached...
-- ...or all of the players in your game's data has a chance to save
end
game:BindToClose(shutdown)
I tried to avoid making major modifications in-order to keep it familiar and compatible with the current system
@Dimayuplay I’ve edited the code to prevent a possible bug from occuring
no way, the kills value for classes actually saves!! although, the other data (like allTimeKills or hasSubspace) still doesnt save. if you could pleeease help me with that ill be so thankful!!
As I previously mentioned, the issue that some values aren’t saving correctly could be caused due to the fact that it’s a mixed table, and that would require rewriting the system to fix
I do happen to have enough time today to write a new system for you if you’re really willing to sacrifice the current data
oh wait!! nevermind! i actually got it to work myself. basically instead of doing table.insert i just declared the variable in the table so now it looks more like this
also changed the name of datastore
if plrr == plr then
local killType = plrr.class.Value.."KILLS"
local valueWasFound = false
local totalKills = 0
--for _, v in sessionData[plr.UserId] do
-- if typeof(v) == "table" and v[killType] then
-- valueWasFound = true
-- v[killType] += killsgotten
-- totalKills = v[killType]
-- break
-- end
--end
if sessionData[plr.UserId][killType] ~= nil then
valueWasFound = true
sessionData[plr.UserId][killType] += killsgotten
end
if valueWasFound == false then
sessionData[plr.UserId][killType] = killsgotten
totalKills = killsgotten
end
local instancevalue = killvalues:FindFirstChild(plrr.class.Value)
if instancevalue then
instancevalue.Value = totalKills
else
local killsvalue = Instance.new("IntValue")
killsvalue.Name = plrr.class.Value
killsvalue.Value = totalKills
killsvalue.Parent = killvalues
end
print(sessionData[plr.UserId])
end
anyway, THANKS A LOT FOR YOUR HELP!!! if it werent for you our game would have been doomed lol. now i definitely understand more about tables and datastores.
I’ll still share the new system, since I was almost done testing it before I noticed your reply
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local dataStore = DataStoreService:GetDataStore("data") -- Remember to delete the keys before using the new system, unless you're changing the name of the DataStore
local sessionData = {}
local function getData(userId)
local attempts = 0
repeat
attempts += 1
local success, data = pcall(dataStore.GetAsync, dataStore, userId)
if success then return true, data end
task.wait(3)
until attempts == 5
return false, nil
end
Players.PlayerAdded:Connect(function(player)
local success, data = getData(player.UserId)
if success then
if data == nil then
data = {
hasSubspace = false,
hasJuggernaut = false,
hasSergeant = false,
hasCyborg = false,
credits = 0,
allTimeKills = 0,
killData = {}
}
end
sessionData[player.UserId] = data
local secretValues = Instance.new("Folder")
secretValues.Name = "secretstats"
secretValues.Parent = player
local hasSubspace = Instance.new("BoolValue")
hasSubspace.Name = "hasSubspace"
hasSubspace.Value = data.hasSubspace
hasSubspace.Parent = secretValues
local hasJuggernaut = Instance.new("BoolValue")
hasJuggernaut.Name = "hasJuggernaut"
hasJuggernaut.Value = data.hasJuggernaut
hasJuggernaut.Parent = secretValues
local hasSergeant = Instance.new("BoolValue")
hasSergeant.Name = "hasSergeant"
hasSergeant.Value = data.hasSergeant
hasSergeant.Parent = secretValues
local hasCyborg = Instance.new("BoolValue")
hasCyborg.Name = "hasCyborg"
hasCyborg.Value = data.hasCyborg
hasCyborg.Parent = secretValues
local credits = Instance.new("IntValue")
credits.Name = "credits"
credits.Value = data.credits
credits.Parent = secretValues
local allTimeKills = Instance.new("IntValue")
allTimeKills.Name = "allTimeKills"
allTimeKills.Value = data.allTimeKills
allTimeKills.Parent = secretValues
hasSubspace.Changed:Connect(function(value) sessionData[player.UserId].hasSubspace = value end)
hasJuggernaut.Changed:Connect(function(value) sessionData[player.UserId].hasJuggernaut = value end)
hasSergeant.Changed:Connect(function(value) sessionData[player.UserId].hasSergeant = value end)
hasCyborg.Changed:Connect(function(value) sessionData[player.UserId].hasCyborg = value end)
credits.Changed:Connect(function(value) sessionData[player.UserId].credits = value end)
allTimeKills.Changed:Connect(function(value) sessionData[player.UserId].allTimeKills = value end)
local evenSecreter = Instance.new("Folder")
evenSecreter.Name = "notvalues"
evenSecreter.Parent = secretValues
local killValues = Instance.new("Folder")
killValues.Name = "classkillvalues"
killValues.Parent = evenSecreter
local killEvent = Instance.new("BindableEvent")
killEvent.Name = "killevent"
killEvent.Parent = evenSecreter
killEvent.Event:Connect(function(plr, killsGotten)
if plr == player then
local playerClass = player.class.Value
local killType = playerClass.."KILLS"
local killValue = killValues:FindFirstChild(playerClass)
if killValue == nil then
local killValue = Instance.new("IntValue")
killValue.Name = playerClass
killValue.Parent = killValues
end
if sessionData[player.UserId].killData[killType] then
sessionData[player.UserId].killData[killType] += killsGotten
killValue.Value += killsGotten
else
sessionData[player.UserId].killData[killType] = killsGotten
killValue.Value = killsGotten
end
allTimeKills.Value += killsGotten
end
end)
else
player:Kick("sumthin weird happened,, (no this is not secret. your data didnt load so im kicking you alright?)")
end
end)
Players.PlayerRemoving:Connect(function(player)
local data = sessionData[player.UserId]
if data then
local attempts = 0
repeat
attempts += 1
local success = pcall(dataStore.SetAsync, dataStore, player.UserId, data)
if success then break end
task.wait(3)
until attempts == 5
end
end)
game:BindToClose(function()
if RunService:IsStudio() then
task.wait(1)
else
local x, y = 0, 0
local function saveData(userId)
local data = sessionData[userId]
if data then
pcall(dataStore.SetAsync, dataStore, userId, data)
end
y += 1
end
for _, player in Players:GetPlayers() do
x += 1
task.spawn(saveData, player.UserId)
end
repeat task.wait() until y == x
end
end)