Save Inventory After Leaving

Hey! Im making an RNG game and followed an in depth tutorial. Although this tutorial was so “in-depth” they didn’t include inventory saving. So, as a not-so-great scripter, i would like to get some help on this.

I found the PlayerData was being stored in a folder, “PlayerDataFolder” in the Equip Script

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")

local EquipEffectEvent = ReplicatedStorage:WaitForChild("EquipEffect")
local GlobalData = ServerStorage:WaitForChild("PlayerData")
local Effects = ServerStorage:WaitForChild("Auras")

-- Define the unequip function
local function delete(player, selectedEffect, CurrentlyEquippedFolder)
	local head = player.Character:FindFirstChild("Head")
	local torso = player.Character:FindFirstChild("Torso")

	if head and torso and selectedEffect then
		for i, v in pairs(head:GetChildren()) do
			if v.Name == selectedEffect then
				v:Destroy()
				break
			end
		end

		for i, v in pairs(torso:GetChildren()) do
			if v.Name == selectedEffect then
				v:Destroy()
				break
			end
		end

		CurrentlyEquippedFolder:GetChildren()[1]:Destroy()
	end
end

-- Define the equip function
local function equip(player, selectedEffect, CurrentlyEquippedFolder)
	local effect = Effects:WaitForChild(selectedEffect)
	local title = effect:WaitForChild("Head"):WaitForChild(selectedEffect):Clone()
	local particles = effect:WaitForChild("Torso"):WaitForChild(selectedEffect):Clone()

	local character = player.Character or player.CharacterAdded:Wait()
	title.Parent = character.Head
	particles.Parent = character.Torso

	local stringVal = Instance.new("StringValue")
	stringVal.Name = selectedEffect
	stringVal.Parent = CurrentlyEquippedFolder
end

-- Define the main equipEffect function
local function equipEffect(player, operationType, selectedEffect)
	local PlayerDataFolder = GlobalData:WaitForChild(player.UserId)
	local InventoryFolder = PlayerDataFolder:WaitForChild("Inventory")
	local CurrentlyEquippedFolder = PlayerDataFolder:WaitForChild("CurrentlyEquipped")

	if operationType == "Equip" and selectedEffect then
		if InventoryFolder:FindFirstChild(selectedEffect) then
			if #CurrentlyEquippedFolder:GetChildren() ~= 0 and CurrentlyEquippedFolder:GetChildren()[1].Name ~= selectedEffect then
				delete(player, CurrentlyEquippedFolder:GetChildren()[1].Name, CurrentlyEquippedFolder)
			end

			if #CurrentlyEquippedFolder:GetChildren() == 0 or CurrentlyEquippedFolder:GetChildren()[1].Name ~= selectedEffect then
				equip(player, selectedEffect, CurrentlyEquippedFolder)
			end
		end
	elseif operationType == "delete" and selectedEffect and CurrentlyEquippedFolder:FindFirstChild(selectedEffect) then
		delete(player, selectedEffect, CurrentlyEquippedFolder)
	end
end

-- Connect equipEffect function to the event
EquipEffectEvent.OnServerEvent:Connect(equipEffect)


Although its in the script, i cant figure out a way to save the auras! Any help would be appreciated! Thank you so much and if you need any more information im here.

Antlers.

4 Likes

You’ll need to leverage DataStoreService to store and retrieve the player’s inventory and equipped items when they join and leave the game.

  • Initialize the DataStore: Create a DataStore to save the player’s inventory and currently equipped items.
  • Load Data on Player Join: Retrieve and set up the player’s inventory and equipped items from the DataStore when they join the game.
  • Save Data on Player Leave: Save the player’s inventory and equipped items to the DataStore when they leave the game.

You might need to mess around with the code, but this is a basic implementation.

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local PlayerDataStore = DataStoreService:GetDataStore("PlayerData")
local ServerStorage = game:GetService("ServerStorage")

local EquipEffectEvent = game:GetService("ReplicatedStorage"):WaitForChild("EquipEffect")
local GlobalData = ServerStorage:WaitForChild("PlayerData")
local Effects = ServerStorage:WaitForChild("Auras")

-- Function to load player data
local function loadPlayerData(player)
    local playerFolder = Instance.new("Folder")
    playerFolder.Name = player.UserId
    playerFolder.Parent = GlobalData

    local inventoryFolder = Instance.new("Folder")
    inventoryFolder.Name = "Inventory"
    inventoryFolder.Parent = playerFolder

    local equippedFolder = Instance.new("Folder")
    equippedFolder.Name = "CurrentlyEquipped"
    equippedFolder.Parent = playerFolder

    local success, data = pcall(function()
        return PlayerDataStore:GetAsync(player.UserId)
    end)

    if success and data then
        -- Load inventory
        for _, itemName in ipairs(data.Inventory or {}) do
            local item = Instance.new("StringValue")
            item.Name = itemName
            item.Parent = inventoryFolder
        end

        -- Load currently equipped items
        for _, equippedItem in ipairs(data.CurrentlyEquipped or {}) do
            local item = Instance.new("StringValue")
            item.Name = equippedItem
            item.Parent = equippedFolder
        end

        -- Equip the currently equipped items
        for _, item in pairs(equippedFolder:GetChildren()) do
            equip(player, item.Name, equippedFolder)
        end
    end
end

-- Function to save player data
local function savePlayerData(player)
    local playerFolder = GlobalData:FindFirstChild(player.UserId)
    if playerFolder then
        local inventory = {}
        local currentlyEquipped = {}

        for _, item in pairs(playerFolder.Inventory:GetChildren()) do
            table.insert(inventory, item.Name)
        end

        for _, item in pairs(playerFolder.CurrentlyEquipped:GetChildren()) do
            table.insert(currentlyEquipped, item.Name)
        end

        local data = {
            Inventory = inventory,
            CurrentlyEquipped = currentlyEquipped
        }

        pcall(function()
            PlayerDataStore:SetAsync(player.UserId, data)
        end)
    end
end

-- Equip and unequip functions
local function delete(player, selectedEffect, CurrentlyEquippedFolder)
    local head = player.Character:FindFirstChild("Head")
    local torso = player.Character:FindFirstChild("Torso")

    if head and torso and selectedEffect then
        for _, v in pairs(head:GetChildren()) do
            if v.Name == selectedEffect then
                v:Destroy()
                break
            end
        end

        for _, v in pairs(torso:GetChildren()) do
            if v.Name == selectedEffect then
                v:Destroy()
                break
            end
        end

        CurrentlyEquippedFolder:GetChildren()[1]:Destroy()
    end
end

local function equip(player, selectedEffect, CurrentlyEquippedFolder)
    local effect = Effects:WaitForChild(selectedEffect)
    local title = effect:WaitForChild("Head"):WaitForChild(selectedEffect):Clone()
    local particles = effect:WaitForChild("Torso"):WaitForChild(selectedEffect):Clone()

    local character = player.Character or player.CharacterAdded:Wait()
    title.Parent = character.Head
    particles.Parent = character.Torso

    local stringVal = Instance.new("StringValue")
    stringVal.Name = selectedEffect
    stringVal.Parent = CurrentlyEquippedFolder
end

-- Main equipEffect function
local function equipEffect(player, operationType, selectedEffect)
    local PlayerDataFolder = GlobalData:WaitForChild(player.UserId)
    local InventoryFolder = PlayerDataFolder:WaitForChild("Inventory")
    local CurrentlyEquippedFolder = PlayerDataFolder:WaitForChild("CurrentlyEquipped")

    if operationType == "Equip" and selectedEffect then
        if InventoryFolder:FindFirstChild(selectedEffect) then
            if #CurrentlyEquippedFolder:GetChildren() ~= 0 and CurrentlyEquippedFolder:GetChildren()[1].Name ~= selectedEffect then
                delete(player, CurrentlyEquippedFolder:GetChildren()[1].Name, CurrentlyEquippedFolder)
            end

            if #CurrentlyEquippedFolder:GetChildren() == 0 or CurrentlyEquippedFolder:GetChildren()[1].Name ~= selectedEffect then
                equip(player, selectedEffect, CurrentlyEquippedFolder)
            end
        end
    elseif operationType == "delete" and selectedEffect and CurrentlyEquippedFolder:FindFirstChild(selectedEffect) then
        delete(player, selectedEffect, CurrentlyEquippedFolder)
    end
end

-- Connect equipEffect function to the event
EquipEffectEvent.OnServerEvent:Connect(equipEffect)

-- Load data when player joins
Players.PlayerAdded:Connect(function(player)
    loadPlayerData(player)
end)

-- Save data when player leaves
Players.PlayerRemoving:Connect(function(player)
    savePlayerData(player)
end)
6 Likes

I’ve been playing around with it and im not sure what “equip” is supposed to be. Is it supposed to call for a remoteEvent?

	equip(player, item.Name, equippedFolder)

It always says “Unknown global “equip”” which i know means that its not able to find the right thing and the error is:

 ServerScriptService.Equip:45: attempt to call a nil value  -  Server - Equip:45
  20:07:22.730  Stack Begin  -  Studio
  20:07:22.730  Script 'ServerScriptService.Equip', Line 45 - function loadPlayerData  -  Studio - Equip:45
  20:07:22.731  Script 'ServerScriptService.Equip', Line 140  -  Studio - Equip:140
  20:07:22.731  Stack End  -  Studio

and thank you for your help so far, i finally got somewhere in this topic because of you, its just not quite done yet. @JamesBlossoms

1 Like

Remove the word ‘local’ from local function equip and try that? It’s calling your equip function.

2 Likes

I’m not getting an error anymore, but it just doesn’t save. Sorry for dragging this on.

1 Like

Try inserting print statements throughout the code to pinpoint where it’s stalling. Start with the playeradded and playerremoving events and their respective functions to see what’s going on.

2 Likes

It works! Now i just have to find a way to get the saved auras into the UI. Thank you so so much you saved me a lot of pain. have an amazing one :slight_smile:

2 Likes

Look up RemoteEvents. You’ll need to fire an event to your UI’s code with the aura data and go from there!

2 Likes

Sorry again, but how would I achieve that? @JamesBlossoms Because the way I store the auras in my inventory is like this:

Screenshot 2024-06-23 220302

I basically take a copy of one of those and then insert it into the PlayerGui. But I don’t know how I would save that for when they leave and rejoin?

Thank you so much again.

Antlers.

Edit: I basically need it to stay in the InventoryGui once you leave and rejoiin ahhh im going crazy please help me fix this ikjldguiskd

Edit 2: If you keep rejoining with a certain aura it stacks and stacks and stacks to the point where

this:

image

becomes this:

image

1 Like

Can you provide what your code looks right now for saving and retrieving player data?

1 Like

This is the DataStore in ServerScriptService

local DataStoreService = game:GetService("DataStoreService")
local mainDS = DataStoreService:GetDataStore("Rolls")

local function loadPlayerData(player)
	print("Loading data for player: " .. player.Name)

	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"

	local Rolls = Instance.new("IntValue", leaderstats)
	Rolls.Name = "Rolls"

	local success, data = pcall(function()
		return mainDS:GetAsync(player.UserId)
	end)

	if success then
		if data then
			Rolls.Value = data[1]
			print("Data loaded successfully for player " .. player.Name .. ". Rolls: " .. Rolls.Value)
		else
			Rolls.Value = 0 -- Default value if no data is found
			print("No data found for player " .. player.Name .. ". Setting Rolls to default: 0")
		end
	else
		warn("Failed to load data for player " .. player.Name)
		Rolls.Value = 0 -- Default value if loading fails
	end
end

local function savePlayerData(player)
	print("Saving data for player: " .. player.Name)

	local leaderstats = player:FindFirstChild("leaderstats")
	if leaderstats then
		local Rolls = leaderstats:FindFirstChild("Rolls")
		if Rolls then
			local success, err = pcall(function()
				mainDS:SetAsync(player.UserId, { Rolls.Value })
			end)

			if success then
				print("Data saved successfully for player " .. player.Name .. ". Rolls: " .. Rolls.Value)
			else
				warn("Failed to save data for player " .. player.Name .. ": " .. err)
			end
		else
			warn("Rolls not found for player " .. player.Name)
		end
	else
		warn("Leaderstats not found for player " .. player.Name)
	end
end

-- Connect player events
game.Players.PlayerAdded:Connect(loadPlayerData)
game.Players.PlayerRemoving:Connect(savePlayerData)

-- Throttled saving mechanism
local savingEnabled = true
local saveQueue = {}

local function processSaveQueue()
	savingEnabled = false
	for _, player in ipairs(saveQueue) do
		savePlayerData(player)
	end
	saveQueue = {}
	savingEnabled = true
end

local function addToSaveQueue(player)
	if savingEnabled then
		savePlayerData(player)
	else
		table.insert(saveQueue, player)
	end
end

while true do
	wait(30) -- Adjust the interval as per your needs
	processSaveQueue()
end

If you need the equip script which we’ve been working on in this forum i can provide that for you, too!

Can I see the code that does this? I don’t understand why more are being created every time you rejoin. From what I see all that’s being saved is the Rolls which is a number.

1 Like
local RS = game:GetService("ReplicatedStorage")
local updateInventoryEvent = RS:WaitForChild("UpdateInventory")

local ScrollingFrame = script.Parent.ScrollingFrame
local EffectTitles = ScrollingFrame:WaitForChild("EffectTitles")

local function addItem(effect)
	
	local clonedTitle = EffectTitles:WaitForChild(effect):Clone()
	clonedTitle.Parent = ScrollingFrame
	clonedTitle.Visible = true
	
end

updateInventoryEvent.OnClientEvent:Connect(addItem)

So basically i have a button for each aura in the inventory but its invisible and in the startergui. when the player obtains an aura, i clone the button from the inventory in the startergui and put it in the playergui and make it visible and so on.

so sorry but are you there?This text will be blurred

BUMPPPP This text will be blurred