Hi guys. I have game with multiple DataStores active. In my case, there’s 3: Inventory
, RoundIsland
, LobbyIsland
. Inventory uses 1 principle, Islands another one. There’s their saving code part:
Saving codes
--ISLAND SAVING
--TestInStudio is false for live game, used to load data on RobloxStudio
--LoadAsPlayer used only in RobloxStudio to inspect other people's saves
function ModuleMeta:Save(PlayerLeft, FastSave)
if TestInStudio or not RunService:IsStudio() then
local PlayerName = self.Player.Name
local PlayerId = self.Player.UserId
local DataStoreKey
if RunService:IsStudio() then
if LoadAsPlayer then
DataStoreKey = tostring(LoadAsPlayer) .. "/" .. tostring(self.SaveSlot) .. "/" .. tostring(self.PlotType) .. "/" .. tostring(self.ActiveIsland)
else
DataStoreKey = "Studio/" .. tostring(PlayerId) .. "/" .. tostring(self.SaveSlot) .. "/" .. tostring(self.PlotType) .. "/" .. tostring(self.ActiveIsland)
end
else
DataStoreKey = tostring(PlayerId) .. "/" .. tostring(self.SaveSlot) .. "/" .. tostring(self.PlotType) .. "/" .. tostring(self.ActiveIsland)
end
local Success
repeat
if not FastSave then
WaitForRequestBudget(Enum.DataStoreRequestType.SetIncrementAsync)
end
self:PrepareObjects()
local DataToSave = TableDeepclone(self.Data)
for Key, Data in pairs(DataToSave) do
if Data.ActivatedController then
if Data.ActivatedController.GetDataForSave then
Data.SavedData = Data.ActivatedController:GetDataForSave()
end
Data.ActivatedController = nil
end
end
local SerializedData = Serializator.Serealize(DataToSave, self.DataVersion)
Success = pcall(function()
DataStore:SetAsync(DataStoreKey, HttpService:JSONEncode({
Data = SerializedData,
Session = not PlayerLeft and os.time() or nil,
DataVersion = self.DataVersion,
}), {})
end)
until Success
else
warn("Testing data saving is not enabled.")
end
end
--Used to get data of various objects, like chests.
function ModuleMeta:PrepareObjects()
if self.PlotType == "Lobby" then
for Index, ObjectData in pairs(self.Data) do
if ObjectData.SavedData and ObjectData.ActivatedController and ObjectData.ActivatedController.GetDataForSave then
ObjectData.SavedData = ObjectData.ActivatedController:GetDataForSave()
end
end
end
end
Inventory saving is almost identical. Only diffirence is values saved:
repeat
if not FastSave then
WaitForRequestBudget(Enum.DataStoreRequestType.SetIncrementAsync)
end
Success = pcall(function()
return DataStore:SetAsync(DataStoreKey, HttpService:JSONEncode({
Data = Serializator.Serealize(self.Data, self.DataVersion),
Gamepasses = self.Gamepasses,
Pentons = self.Pentons,
Septons = self.Septons,
Session = not PlayerLeft and os.time() or nil,
DataVersion = self.DataVersion,
ActiveIsland = self.ActiveIsland,
Level = self.Level,
Experience = self.Experience,
Blueprints = self.Blueprints,
CraftingTool = self.CraftingTool,
ActiveQuests = CopiedQuests,
CompletedQuests = self.CompletedQuests,
IslandData = self.IslandData,
}))
end)
until Success
This 2 code pieces work well. They save all data I need. And they are called from another script, at this code piece:
Load and Save code
local PlayersData = {}
local function LoadData(Player)
local InventoryData = Modules.Inventory.Initialize(Player)
PlayersData[Player] = {
Inventory = InventoryData,
}
end
local function SaveData(Player, PlayerLeft, Immediate, Subject)
if string.match(Subject, "Inventory") then
PlayersData[Player].Inventory:Save(PlayerLeft, Immediate)
end
if string.match(Subject, "Island") then
for Key, Value in pairs(PlayersData[Player]) do
-- there's only DataStores and strings possible, I need to save DataStores only
if Key ~= "Inventory" and typeof(Value) ~= "string" then
Value:Save(PlayerLeft, Immediate)
end
end
end
end
for _, Player in ipairs(Players:GetPlayers()) do
coroutine.wrap(LoadData)(Player)
end
local function ServerShutdown()
if RunService:IsStudio() then
for _, Player in ipairs(Players:GetPlayers()) do
coroutine.wrap(SaveData)(Player, true, true, "InventoryIsland")
end
wait(5)
else
local MainThread = coroutine.running()
local ThreadsRunning = 0
for Player, Data in pairs(PlayersData) do
if Data == nil then continue end
ThreadsRunning += 1
coroutine.wrap(function()
SaveData(Player, true, true, "InventoryIsland")
PlayersData[Player] = nil
ThreadsRunning -= 1
if ThreadsRunning == 0 then
coroutine.resume(MainThread)
end
end)()
end
if ThreadsRunning > 0 then
coroutine.yield()
end
end
end
Players.PlayerAdded:Connect(LoadData)
Players.PlayerRemoving:Connect(function(Player)
coroutine.wrap(function()
SaveData(Player, true, false, "InventoryIsland")
PlayersData[Player] = nil
end)()
end)
game:BindToClose(ServerShutdown)
coroutine.wrap(function()
while true do
task.wait(180)
for _, Player in ipairs(Players:GetPlayers()) do
coroutine.wrap(SaveData)(Player, false, false, "InventoryIsland")
end
end
end)
But I have found problem - when I TELEPORT to round place, all data gets SessionLocked, what means that it has failed to save. If I leave game instead, then all data is saved correctly.
I have tried a lot of diffirent ways to fix that, but they all not helped, that’s why I now asking here.