Inventory isn't saving to DataStore

  1. What do you want to achieve?
    I have a shop where a player can purchase an item. So when the player purchases an item from the shop, it fires to the server and then the server fires to the client again, allowing the item to be added to the backpack & the data is saved when the player leaves the game.

  2. What is the issue?
    What I think is happening… is when the shop fires to the server, it doesn’t fire the information to the client. I’m trying to save the information to the DataStore, but it doesn’t save when the player buys something from the shop!

  3. What solutions have you tried so far?
    I’ve tried re-working the serverscript that handles the RE that fires to the client, but it hasn’t been working.

I’ll insert a video showing the problem: inventory issue on Vimeo
Ignore the cake that is saved when the player rejoins — that is from a previous test! The player is supposed to have 2 cake in their inventory.

DataStore Script


local ds = game:GetService("DataStoreService")
local data = ds:GetDataStore("Tools")

local toolsFolder = game.ReplicatedStorage.Tools

local airDropInfo = require(game.ServerScriptService.AirDropInfo)

local rarities = airDropInfo["Rarities"]

local itmTemplate = game.ReplicatedStorage.ItemTemplate

game.Players.PlayerAdded:Connect(function(plr)

    --[[local coins = Instance.new("NumberValue")
    coins.Name = "Coins"
    coins.Parent = leader
 
    local savedCoins = data:GetAsync(plr.UserId.."-Coins")
 
    if savedCoins then
        coins.Value = savedCoins
    end]]

	local savedTools = data:GetAsync(plr.UserId.."-Tools")

	if savedTools then

		for i, item in pairs(savedTools) do

			for i, tool in pairs(toolsFolder:GetChildren()) do
				if item == tool.Name then

					local toolClone1 = tool:Clone()
					toolClone1.PickedUp.Disabled = true
					toolClone1.Parent = plr.Backpack

					local toolClone2 = tool:Clone()
					toolClone2.PickedUp.Disabled = true
					toolClone2.Parent = plr.StarterGear

					local rarity = rarities[tool.Values.Rarity.Value]

					local clonedTemplate = itmTemplate:Clone()
					clonedTemplate.name.Text = tool.Name
					clonedTemplate.image.Image = tool.TextureId
					clonedTemplate.name.TextColor3 = Color3.fromRGB(255, 255, 255)

					local pg = plr.PlayerGui
					local InventoryMain = pg:WaitForChild("Inventory"):WaitForChild("Main")
					local holder = InventoryMain:WaitForChild("Holder")

					clonedTemplate.Parent = holder


				end
			end 
		end
	end

end)

game.Players.PlayerRemoving:Connect(function(plr)

	plr.CharacterRemoving:Connect(function(char)
		local humanoid = char.Humanoid
		humanoid:UnequipTools()
	end)

	local suc, err = pcall(function()

		local savedTools = {}

		for i, item in pairs(plr.Backpack:GetChildren()) do
			--if item:IsA("Tool") then
			table.insert(savedTools, item.Name)
			end
			--end

		data:SetAsync(plr.UserId.."-Tools", savedTools)

	end)

	if err then
		warn(err)
	end

end)

Screenshot 2023-09-11 at 1.54.04 PM

Shop Button

-- Reference to the button
local button = script.Parent
-- Reference to the player
local player = game.Players.LocalPlayer

local tool = game.ReplicatedStorage.Tools.Popsicle 

-- Reference to the "CollectedItem" RemoteEvent
local remote = game.ReplicatedStorage.CollectedItem

local itmTemplate = game.ReplicatedStorage.ItemTemplate

function chooseReward(plr)
	local toolClone1 = tool:Clone()
	toolClone1.PickedUp.Disabled = true
	toolClone1.Parent = plr.Backpack

	local toolClone2 = tool:Clone()
	toolClone2.PickedUp.Disabled = true
	toolClone2.Parent = plr.StarterGear

	local clonedTemplate = itmTemplate:Clone()
	clonedTemplate.name.Text = tool.Name
	clonedTemplate.image.Image = tool.TextureId
	clonedTemplate.name.TextColor3 = Color3.fromRGB(241, 249, 240)

	local pg = plr.PlayerGui
	local InventoryMain = pg.Inventory.Main
	local holder = InventoryMain.Holder

	clonedTemplate.Parent = holder

	remote:FireServer(plr, "Tool", tool, Color3.fromRGB(241, 249, 240))
end

-- Listen for the button click event
button.MouseButton1Click:Connect(function()
	if player.leaderstats.Coins.Value >= 5 then
		player.leaderstats.Coins.Value -= 5
		script.Sound:Play()
	-- Call the chooseReward function for the player
	chooseReward(player)
	elseif player.leaderstats.Coins.Value <= 5 then
		script.Error:Play()
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(253, 161, 210)
		wait(.5)
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(253, 161, 210)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(255, 255, 255)
		wait(.5)
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(253, 161, 210)
		wait(.5)
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(253, 161, 210)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(255, 255, 255)

		end
end)

Screenshot 2023-09-11 at 1.54.13 PM

Backpack Script

local sg = script.Parent.Parent
local invGui = script.Parent

local mainFrame = invGui.Main
local holder = mainFrame.Holder
local itmTemplate = game.ReplicatedStorage.ItemTemplate

local dropInfo = require(script.AirDropInfo)
local rarities = dropInfo.Rarities

local plr = game.Players.LocalPlayer

local awardedFrame = script.Parent.Awarded
local awardedRemote = game.ReplicatedStorage.CollectedItem
local claim = awardedFrame.Claim

game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)

awardedFrame:TweenSizeAndPosition(UDim2.new(0.01,0,0.01,0), UDim2.new(0.4,0,0.35,0), "Out", "Sine", 0.4, false)
awardedFrame.Visible = false

awardedRemote.OnClientEvent:Connect(function(typ, awardedItem, rarityColor)
	
	local award = awardedFrame:Clone()

	award.Parent = awardedFrame.Parent
	
	-- if its a weapon
	if rarityColor then
		

		award.label.Text = awardedItem.Name
		award.label.TextColor3 = rarityColor
		award.image.Image = awardedItem.TextureId
		
	else
		
		award.image.Image = "rbxassetid://4602932763"
		award.label.Text = awardedItem
		
	end
	
	award.Visible = true
	award:TweenSizeAndPosition(UDim2.new(0.2,0,0.35,0), UDim2.new(0.4,0,0.275,0), "Out", "Sine", 0.4, false)
	invGui.Sound:Play()
	
	award.Claim.MouseButton1Click:Connect(function()

		award:TweenSizeAndPosition(UDim2.new(0.01,0,0.01,0), UDim2.new(0.4,0,0.35,0), "Out", "Sine", 0.4, false)
		wait(0.4)
		award:Destroy()

	end)
	
end)

ServerScript that is supposed to be connected to the Shop Button & then fire to the Backpack script


local plr = game.Players.LocalPlayer


local awardedRemote = game.ReplicatedStorage.CollectedItem


awardedRemote.OnServerEvent:Connect(function(plr, request, tool, rarity)
	if request == "Tool" then
	print("remote connected server")
	print(tool)
	print(rarity)
	local invGui = plr.PlayerGui.Inventory
	local mainFrame = invGui.Main
	local holder = mainFrame.Holder
	local itmTemplate = game.ReplicatedStorage.ItemTemplate

	local airDropInfo = require(game.ServerScriptService.AirDropInfo)
	local dropInfo = require(game.ServerScriptService.AirDropInfo)
	

	local rarities = airDropInfo["Rarities"]

	local itmTemplate = game.ReplicatedStorage.ItemTemplate

	local remote = game.ReplicatedStorage.CollectedItem


		local toolClone1 = tool:Clone()
		--toolClone1.PickedUp.Disabled = true
		toolClone1.Parent = plr.Backpack

		local toolClone2 = tool:Clone()
		--toolClone2.PickedUp.Disabled = true
		toolClone2.Parent = plr.StarterGear

		local rarity = rarities[tool.Values.Rarity.Value]

		local clonedTemplate = itmTemplate:Clone()
		clonedTemplate.name.Text = tool.Name
		clonedTemplate.image.Image = tool.TextureId
		clonedTemplate.name.TextColor3 = rarity.color

		local pg = plr.PlayerGui
		local InventoryMain = pg.Inventory.Main
		local holder = InventoryMain.Holder

		clonedTemplate.Parent = holder

		remote:FireClient(plr, "Tool", tool, rarity.color)
		print("remote connected client")
end
	end)

I’m more than happy to share more info if needed!

3 Likes

When you buy an item from the shop, you can see it in the backpack while using the server? If you’re using a Local Script to add the item this one is gonna be visible only for the client (this happens to prevent exploiters).

1 Like

Thank you SO much for the reply!! :smiling_face_with_three_hearts:

When I buy an item from the shop, it does not appear on the server within the player’s Backpack & StarterGear. I am using a local script within the shop to add the item to the player’s backpack via a gui button — when I’m on the client, it does appear in the player’s Backpack & StarterGear.

You are spot on!! I’m trying to make it so that information (aka when an item is purchased via the shop) is available/visible via the server; however, I’m running into a lot of challenges trying to do so.

If it would be helpful, I can also share the game with you via TeamCreate (or whatever it’s called now) so you can take a look!

The only way to do it is by adding the item to the ItemFolder by a Server Script. (I can’t tell you more bc I’m having some issues understanding a code not written by me :slight_smile: )

1 Like

No worries! I guess I’m just wondering how I could do this? I know I could have it happen via a remote event that then fires to the server… but that’s what I’ve been trying to do and it’s not working :sweat_smile:

1 Like

The Shop script is inside the client? Btw the script under: ServerScript that is supposed to be connected to the Shop Button & then fire to the Backpack script I don’t think is a server script, bc It’s impossible to get the LocalPlayer without an Event that gives the player to the server

1 Like

Yes! The Shop script is inside the client. Also, the script you’re referring to is actually a ServerScript within ServerScriptService — I just put the

local plr = game.Players.LocalPlayer

in cause I was trying to use one of my other scripts & then building upon it! In that script, I do get the player from the fired RE:

awardedRemote.OnServerEvent:Connect(function(plr, request, tool, rarity)

You should use a remote function for the shop and only display the result on the client

Then in the ServerScript add the code that gives you the item
For Example

local Item = ItemTemplate:FindFirstChild(Item.Name) -- idk where you have stored your items

if Item then
    local NewItem = Item:Clone()
    NewItem.Parent = ItemFolder  --idk if this is the player inventory

And in the backpack script add and event that fires when an Item gets added to the Inventory
Example:

local ItemFolder == player.ItemFolder
ItemFolder.ChildAdded:Connect(function()

-- the script that adds the gui
end)

By the way i think you are checking if player has enough money in the client, you should check the users money on the server to prevent hacking

I’ve solved the issue by doing this:

Server-script:

local awardedRemote = game.ReplicatedStorage.CollectedItem


awardedRemote.OnServerEvent:Connect(function(plr, request, tool, rarity)
	--if request == "Tool" then
	print("remote connected server")
	print(tool)
	print(plr.Name)
	--if request == "Tool" then
		-- Check if the player exists and the tool is valid
		if plr and tool and tool:IsA("Tool") then
			-- Clone the tool
			local toolClone = tool:Clone()

			-- Add the tool to the player's StarterGear and Backpack
			local backpack = plr.Backpack
			local starterGear = plr.StarterGear

			-- Check if the player has a StarterGear folder
			if not starterGear then
				starterGear = Instance.new("Folder")
				starterGear.Name = "StarterGear"
				starterGear.Parent = plr
			end

			-- Move the cloned tool to the appropriate location
			toolClone.Parent = starterGear
			toolClone.Parent = backpack

			-- Optionally, you can set the rarity of the cloned tool
			toolClone:SetAttribute("Rarity", rarity)

			-- Print a message to confirm
			print(plr.Name .. " received a " .. rarity .. " " .. tool.Name)
		end
	end)

Client-script (inside of shop gui button):

-- Reference to the button
local button = script.Parent
-- Reference to the player
local player = game.Players.LocalPlayer


local tool = game.ReplicatedStorage.Tools.Popsicle 


-- Reference to the "CollectedItem" RemoteEvent
local remote = game.ReplicatedStorage.CollectedItem

local itmTemplate = game.ReplicatedStorage.ItemTemplate

function chooseReward(plr)
	local toolClone1 = tool:Clone()
	toolClone1.PickedUp.Disabled = true
	toolClone1.Parent = plr.Backpack

	local toolClone2 = tool:Clone()
	toolClone2.PickedUp.Disabled = true
	toolClone2.Parent = plr.StarterGear

	local clonedTemplate = itmTemplate:Clone()
	clonedTemplate.name.Text = tool.Name
	clonedTemplate.image.Image = tool.TextureId
	--clonedTemplate.name.TextColor3 = Color3.fromRGB(241, 249, 240)
	local rarity = "Common"
	
	local pg = plr.PlayerGui
	local InventoryMain = pg.Inventory.Main
	local holder = InventoryMain.Holder

	--clonedTemplate.Parent = holder

	remote:FireServer(plr, tool, rarity)
end

-- Listen for the button click event
button.MouseButton1Click:Connect(function()
	if player.leaderstats.Coins.Value >= 5 then
		player.leaderstats.Coins.Value -= 5
		script.Sound:Play()
	-- Call the chooseReward function for the player
	chooseReward(player)
	elseif player.leaderstats.Coins.Value <= 5 then
		script.Error:Play()
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(253, 161, 210)
		wait(.5)
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(253, 161, 210)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(255, 255, 255)
		wait(.5)
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(253, 161, 210)
		wait(.5)
		script.Parent.Parent.Info.BackgroundColor3 = Color3.fromRGB(253, 161, 210)
		script.Parent.Parent.Info.TextColor3 = Color3.fromRGB(255, 255, 255)

		end
end)
1 Like

Nice :smile:
As the other guy said I advise you to check if the player has enough money even in the ServerScript because an Exploiter can create a Local Script that fires the Event even without enought money

1 Like