The Goal
I want to achieve a simple saving system for DataStores. However, it does not save the data.
Possible Problem
The first issue is that, in the PlayerRemoving event, when calling dataStore:GetAsync(uniqueKey)
in the pcall
, it infinitely yields.
According to some documentation, GetAsync yields. From further testing, pcall
doesn’t create a new thread, meaning that if I yield in a pcall
, it would yield the current thread. This means that GetAsync
would yield the thread forever. It seems like it is a problem from GetAsync
.
I tried looking at the DevHub on DataStores (and saving PlayerData). I also tried integrating DataStore2, however, it was hard to put together with an already function Stats ModuleScript.
I do have Studio DataStore API enabled.
Code
ReplicatedStorage.Data.PlayerData
-- The PlayerData code is added to the problem for context.
-- This isn't actually the root of the problem
-- Creator: NilScripter_Alt
-- Description: A ModuleScript that creates stat tables for each player.
--Includes events
local statCreated = Instance.new("BindableEvent")
local statDeleted = Instance.new("BindableEvent")
local function isValidPlayer(player)
if not player then
return false
end
if not player:IsA("Player") then
return false
end
return true
end
local PlayerData = {}
PlayerData.StatCreated = statCreated.Event
PlayerData.StatDeleted = statDeleted.Event
local stats = {}
function PlayerData.getStats(player)
if not isValidPlayer(player) then
error("Cannot get stat of an invalid player", 2)
end
local stat = stats[player]
return stat
end
function PlayerData.createStats(player, overrideStats)
if not isValidPlayer(player) then
error("Cannot create stat of an invalid player", 2)
end
if PlayerData.getStats(player) then
error("Cannot create stat that has already been created", 2)
end
stats[player] = overrideStats or {}
statCreated:Fire(player, stats[player])
end
function PlayerData.deleteStats(player)
if not isValidPlayer(player) then
error("Cannot delete stats of invalid player", 2)
end
local stat = PlayerData.getStats(player)
if not stat then
error("Cannot delete stats that are already deleted", 2)
end
statDeleted:Fire(player, stat)
for key, value in pairs(stat) do
key = nil
value = nil
end
end
return PlayerData
ServerScriptService.PlayerDataManager
-- Scroll down to the onPlayerRemoving function.
-- There, you will find the problem
-- Creator: NilScripter_Alt
-- Description: A Script that puts the PlayerData module into
-- action and manages the loading and saving
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local data = ReplicatedStorage.Data
local playerData = require(data.PlayerData)
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("PLAYER_DATA")
local defaultData = {
coinsCollected = {
["workspace.Coins.DeleteRedCoin"] = true
};
money = 0;
experience = 0;
dataId = 0;
level = 1;
inBattle = false;
}
local function getUniqueKey(player)
return "PLAYER_DATA:" .. player.UserId
end
local function onPlayerAdded(player)
local uniqueKey = getUniqueKey(player)
local success, overrideData = pcall(function()
return dataStore:GetAsync(uniqueKey)
end)
if not success then
warn(player.Name, "'s data could not be found")
elseif not overrideData then
warn(player.Name, "'s does not have any DataStores yet")
overrideData = defaultData
pcall(function()
dataStore:SetAsync(uniqueKey, overrideData)
end)
end
print("COINS:", overrideData.money)
playerData.createStats(player, overrideData)
print("CREATED")
end
local function onPlayerRemoving(player)
print("is this even working")
local uniqueKey = getUniqueKey(player)
local stats = playerData.getStats(player)
print("did I get it?")
local s, overrideData = pcall(function()
print("pcall?")
return dataStore:GetAsync(uniqueKey)
end)
-- (PROBLEM HERE!)
-- after some debugging (using prints), it seems like dataStore:GetAsync()
-- yields forever, not allowing it to continue
print("Hello?") -- This doesn't print
print(s, ":", overrideData) -- This doesn't print
-- Everything after doesn't work
if not overrideData then
warn(player.Name, "does not have any data to save")
return
end
local success, err = pcall(function()
dataStore:UpdateAsync(uniqueKey, function(oldData)
if not oldData then
return nil
end
if playerData.dataId ~= oldData.dataId then
return nil
end
playerData.dataId = playerData.dataId + 1
return playerData
end)
end)
print(err)
playerData.deleteStats(player)
print("DELETE")
end
for _, player in ipairs(Players:GetPlayers()) do
spawn(function() onPlayerAdded(player) end)
end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
game:BindToClose(function()
for _, player in ipairs(Players:GetPlayers()) do
spawn(function() onPlayerRemoving(player) end)
end
end)
- Thank You!