Saving to Datastore upon player exit

I am building an Inventory system for my game. Currently, I have a ModuleScript in ReplicatedStorage which contains the player’s inventory data in a table.

When the player exits the game, the data from the player’s inventory table in the ModuleScript is saved to the datastore and cleared from the ModuleScript.

When the player rejoins the game, the inventory data is retrieved from the datastore and saved to the ModuleScript.

The only time data is read/saved to the Datastore is upon players joining/exiting the game. The inventory is managed in the game only by using the ModuleScript’s functions. I want to keep it this way to minimize API calls and simplify my code. Are there any issues that I could run into with this strategy?

-- Inventory Cache
local InventoryCache = require(ReplicatedStorage:WaitForChild("Cache"):WaitForChild("InventoryCache"))

-- When the player joins, get their inventory data from the datastore and add it to the PlayerInventoryData table.
-- Also get their inventory size from the datastore and add it to the PlayerInventoryMaxSize table.
Players.PlayerAdded:Connect(function(player)
	local success, inventory_data = pcall(function()
		return InventoryStore:GetAsync(("Inventory_"..(tostring(player.UserId))))
	end)
	if success then
		if inventory_data == nil then
			InventoryCache.SetPlayerInventory(player.Name, {})
		else
			InventoryCache.SetPlayerInventory(player.Name, inventory_data)
		end
	end
	
	local success, inventory_max_size = pcall(function()
		return InventorySizeStore:GetAsync(player.UserId)
	end)
	if success then
		if inventory_max_size == nil then
			InventoryCache.SetInventoryMaxSize(player.Name, 20)
		else
			InventoryCache.SetInventoryMaxSize(player.Name, inventory_max_size)
		end
	end
	
end)


-- When the player leaves, save their inventory and inventory size to the datastore.
Players.PlayerRemoving:Connect(function(player)
	local success, errorMessage = pcall(function()
		InventoryStore:SetAsync(("Inventory_"..(tostring(player.UserId))), InventoryCache.GetPlayerInventory(player.Name))
	end)
	if not success then
		print(errorMessage)
	end
	
	local success, errorMessage = pcall(function()
		InventoryStore:SetAsync(player.UserId, InventoryCache.GetInventoryMaxSize(player.Name))
	end)
	if not success then
		print(errorMessage)
	end
	
	-- Remove the player's cached data.
	InventoryCache.RemovePlayerDataFromCache(player.Name)
end)

Any feedback would be appreciated. I want to eventually make a guide that includes each part needed to build an inventory system.

2 Likes

I would recommend using BindToClose because

  • Sever being shutdown
  • server with a single player

sometime don’t fire PlayerRemoving
Therefore the data is not saved

1 Like

Didn’t know about this event. Here is my implementation for this as well:

-- If the server is closed, save all players' inventory to the datastore.
game:BindToClose(function()
	if RunService:IsStudio() then
		return
	end
	
	local players = Players:GetPlayers()
	for index, player in pairs(players) do
		local success, errorMessage = pcall(function()
			InventoryStore:SetAsync(("Inventory_"..(tostring(player.UserId))), InventoryCache.GetPlayerInventory(player.Name))
		end)
		if not success then
			print(errorMessage)
		end

		local success, errorMessage = pcall(function()
			InventoryStore:SetAsync(player.UserId, InventoryCache.GetInventoryMaxSize(player.Name))
		end)
		if not success then
			print(errorMessage)
		end
	end
	
end)
-- If the server is closed, save all players' inventory to the datastore.
game:BindToClose(function()
    -- Can happen in studio as well
	
	local players = Players:GetPlayers()
	for index, player in pairs(players) do
    -- Uses a Tries based system
		local maxTries = 2
    local currentTries = 0
    
    repeat
        currentTries += 1

        local success, errorMessage = xpcall(function()
			    InventoryStore:SetAsync(("Inventory_"..  (tostring(player.UserId))), InventoryCache.GetPlayerInventory(player.Name))
		    end, warn) --xpcall will warn the error
    until currentTries >= maxTries 
	end
	
end)

Sorry for late reponse, Here’s a better way to do this.

1 Like