Shop, Coins and Inventory Failing to Load After Respawn

Hello, Im experiencing an issue in my game. When a player dies and respawns (or moves to a new round), their coins, inventory, and shop UI sometimes completely fail to load and the ui shows nothing. The only way to fix it is by rejoining the game.

Im not entirely sure what causes it as I dont script but I believe it may be something in the code below, which handles data loading and sending a remote to the client:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local MarketplaceService = game:GetService("MarketplaceService")
local ownershipDataStore = DataStoreService:GetDataStore("OwnershipDataStore56_TESTTT")
local OtherStuff = DataStoreService:GetDataStore("OtherStuffTEST")
local currencyName = "Coins"

local Remotes = ReplicatedStorage:WaitForChild("Remotes")

local BatonNames = {
	"Blue Baton",
	"Electric Baton",
	"Golden Baton",
	"Hammer Baton",
	"Lightsaber Baton",
	"Magic Baton",
	"Red Baton",
	"Scythe Baton",
	"Robux Baton",
	"White Baton",
	"Blade Baton",
}

local prices = {
	["Blue Baton"] = 100,
	["Electric Baton"] = 200,
	["Golden Baton"] = 300,
	["Hammer Baton"] = 400,
	["Lightsaber Baton"] = 500,
	["Magic Baton"] = 600,
	["Red Baton"] = 700,
	["Scythe Baton"] = 800,
	["Vip Baton"] = 900,
	["White Baton"] = 1000,
	["Blade Baton"] = 1100,
}

local toolsFolder = game:GetService("ServerStorage"):FindFirstChild("Baton")
local tools = {}

for _, batonName in ipairs(BatonNames) do
	tools[batonName] = toolsFolder and toolsFolder:FindFirstChild(batonName)
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Value = 10000 -- Default if no data
	coins.Parent = leaderstats

	local folder = Instance.new("Folder")
	folder.Name = "Ownership"
	folder.Parent = player

	local BatonSelected = Instance.new("StringValue")
	BatonSelected.Parent = player
	BatonSelected.Name = "BatonSelected"
	BatonSelected.Value = "Blue Baton"

	for _, batonName in ipairs(BatonNames) do
		local batonValue = Instance.new("BoolValue")
		batonValue.Name = batonName
		batonValue.Parent = folder
	end

	-- Load data
	local d
	local success, data = pcall(function()
		d = OtherStuff:GetAsync(player.UserId)
		return ownershipDataStore:GetAsync(player.UserId)
	end)

	if success and data then
		for _, batonName in ipairs(BatonNames) do
			local batonValue = folder:FindFirstChild(batonName)
			if batonValue then
				batonValue.Value = data[batonName] or false
			end
		end
		BatonSelected.Value = d and d["Selected"] or "Blue Baton"
	else
		for _, batonName in ipairs(BatonNames) do
			local batonValue = folder:FindFirstChild(batonName)
			if batonValue then
				batonValue.Value = false
			end
		end
		if not success then
			warn("Failed to load data for " .. player.Name)
		end
	end

	--// Load coin data
	local coinSuccess, coinData = pcall(function()
		return OtherStuff:GetAsync("Coins_" .. player.UserId)
	end)

	if coinSuccess and coinData then
		coins.Value = coinData
	else
		warn("Failed to load coins for " .. player.Name)
	end

	-- VIP bonus (500 coins every 30 days)
	local ownsVIP = false
	pcall(function()
		ownsVIP = MarketplaceService:UserOwnsGamePassAsync(player.UserId, 920470110)
	end)

	if ownsVIP then
		local now = os.time()
		local successVIP, lastBonusTime = pcall(function()
			return OtherStuff:GetAsync("VIP_" .. player.UserId)
		end)

		if not lastBonusTime or now - lastBonusTime >= 2592000 then
			coins.Value += 500
			pcall(function()
				OtherStuff:SetAsync("VIP_" .. player.UserId, now)
			end)
		end

		-- Grant Golden Baton if VIP
		local goldenBaton = folder:FindFirstChild("Golden Baton")
		if goldenBaton then
			goldenBaton.Value = true
			player.BatonSelected.Value = "Golden Baton"
			local tool = tools["Golden Baton"]
			if tool then
				local clonedTool = tool:Clone()
				clonedTool.Parent = player.Backpack
			end
		end
	end

	task.wait(5)
	Remotes.ShopReady:FireClient(player)
end)

game.Players.PlayerRemoving:Connect(function(player)
	local folder = player:FindFirstChild("Ownership")
	if folder then
		local data = {}
		for _, batonName in ipairs(BatonNames) do
			local batonValue = folder:FindFirstChild(batonName)
			if batonValue then
				data[batonName] = batonValue.Value
			end
		end

		local S = {
			["Selected"] = player.BatonSelected.Value
		}

		local success, err = pcall(function()
			OtherStuff:SetAsync(player.UserId, S)
			ownershipDataStore:SetAsync(player.UserId, data)
		end)

		if not success then
			warn("Failed to save data for " .. player.Name .. ": " .. err)
		end
	end

	--// Save coins
	local coinSuccess, coinErr = pcall(function()
		local coins = player:FindFirstChild("leaderstats") and player.leaderstats:FindFirstChild("Coins")
		if coins then
			OtherStuff:SetAsync("Coins_" .. player.UserId, coins.Value)
		end
	end)

	if not coinSuccess then
		warn("Failed to save coins for " .. player.Name .. ": " .. coinErr)
	end
end)

game.ReplicatedStorage.PurchaseEquip.OnServerEvent:Connect(function(player, batonName)
	local playerCoins = player:FindFirstChild("leaderstats"):FindFirstChild("Coins")
	local ownershipBaton = player:FindFirstChild("Ownership"):FindFirstChild(batonName)

	if ownershipBaton and ownershipBaton.Value then
		local char = player.Character
		local Hum: Humanoid = char.Humanoid

		Hum:UnequipTools()

		for _, v in player.Backpack:GetChildren() do
			v:Destroy()
		end

		local tool = tools[batonName]
		if tool then
			player.BatonSelected.Value = batonName
		end
	else
		if prices[batonName] then
			if playerCoins and playerCoins.Value >= prices[batonName] then
				playerCoins.Value -= prices[batonName]

				task.wait(0.5)

				local char = player.Character
				local Hum: Humanoid = char.Humanoid

				Hum:UnequipTools()
				for _, v in player.Backpack:GetChildren() do
					v:Destroy()
				end

				local tool = tools[batonName]
				if tool then
					local clonedTool = tool:Clone()
					clonedTool.Parent = player.Backpack
					ownershipBaton.Value = true
				end
			end
		end
	end
end)

game.ReplicatedStorage.Equip.OnServerEvent:Connect(function(ply, batonName)
	local char = ply.Character
	local Hum: Humanoid = char.Humanoid

	Hum:UnequipTools()

	for _, v in ply.Backpack:GetChildren() do
		v:Destroy()
	end

	local tool = ReplicatedStorage.Batons:FindFirstChild(batonName)
	if tool then
		ply.BatonSelected.Value = batonName
	else
		print("Tool not found: " .. batonName)
	end
end)

Any help will be appreciated thanks

1 Like

Do they appear but some information doesn’t update, or does the entire GUI not appear?

1 Like

image
If you have ResetOnSpawn enabled, you might want to disable it.

3 Likes

Yep, that’s exactly what I was thinking ^^

The gui appears but theres like no information for example on the inventory ui its supposed to show all ur items but it just doesn’t i turned off resetonspawn for coins but the setting for the others were already off

Could you show the client code?

Client - Shop Handler

--// Service
local ser_RS = game:GetService("ReplicatedStorage")

--// Vars
local shopConfig = {}

--# Shop configurator
-- Each table refers to its tab in the shop UI
shopConfig.featured = {
	Currency = "Coins",
	Items = {
		{Name = "Red Baton", Price = 100, Image = nil, Desc = "Test"}
	}
}

shopConfig.batons = {
	Currency = "Coins",
	Items = {
		{Name = "Blue Baton", Price = 100, Image = nil, Desc = "Test desc 1"},
		{Name = "Hammer Baton", Price = 200, Image = 133831802026508, Desc = "Be Careful With It"},
		{Name = "Blade Baton", Price = 350, Image = 101995995712011, Desc = "Who Approved This?!"},
		{Name = "Scythe Baton", Price = 400, Image = 78447037565687, Desc = "Takes Skill To Use"},
		{Name = "Lightsaber Baton", Price = 500, Image = nil, Desc = "Copyrighted Soon"},
		{Name = "Robux Baton", Price = 500, Image = 132081476022415, Desc = "Flaunt your wealth without the effects"},
		{Name = "Electric Baton", Price = 800, Image = nil, Desc = "Test desc 2"},
		{Name = "Magic Baton", Price = 1000, Image = nil, Desc = "Become A Magician"},
	}
}

shopConfig.coins = {
	Currency = "Robux",
	Items = {
		{Name = "100 Coins(20R$)", Price = 20, Coins = 100, Image = 133275044633160, Desc = "20 robux for 100 Coins", Id = 2363132444},
		{Name = "250 Coins(40R$)", Price = 40, Coins = 250, Image = nil, Desc = "Buy 250 coins for 30 Robux", Id = 2363145713},
		{Name = "500 Coins(55R$)", Price = 70, Coins = 500, Image = nil, Desc = "Buy 500 coins for 55 Robux", Id = 2363153768},
		{Name = "1,000 Coins(100R$)", Price = 120, Coins = 1000, Image = nil, Desc = "Buy 1,000 coins for 100 Robux", Id = 2363186510},
		{Name = "2,500 Coins(200R$)", Price = 250, Coins = 2500, Image = nil, Desc = "Buy 2,500 coins for 200 Robux", Id = 2363323247}
	}
}

shopConfig.passes = {
	Currency = "Robux",
	Items = {
		{Name = "VIP", Price = 1000, Image = nil, Desc = "Unlock exclusive benefits including a Golden Baton, 500 monthly coins, a special chat tag, and Name Tag", Id = 920470110},
		{Name = "2x Mega Pushes", Price = 500, Image = nil, Desc = "THE MEGA WUT?", Id = 951695721},
		{Name = "2x Pushes", Price = 250, Image = nil, Desc = "Just pushing, but twice", Id = 915955700}
	}
}

--// Module
local shopHandler = {}

--# Returns the config to load the shop on the client
function shopHandler.getConfig()
	return shopConfig
end

function shopHandler.isBaton(itemName)
	for _, batonData in ipairs(shopConfig.batons.Items) do
		if batonData.Name == itemName then
			return true
		end
	end
	return false
end


return shopHandler

Server - Shopsystem

--// Services
local ser_RS = game:GetService("ReplicatedStorage")

--// Modules
local mod_shopHandler = require(ser_RS.Modules:WaitForChild("Shop_Handler"))

--// Player
local player = game.Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local Ownership: Folder = player:WaitForChild("Ownership")

--// Events
local rev_buyItem = ser_RS.Events.Remote.Shop:WaitForChild("BuyItem")
local rev_Ready = ser_RS.Remotes:WaitForChild("ShopReady")
local db = false

--// UI
local screenGui = script.Parent
local f_holder = screenGui.Holder
local f_shop = f_holder.ShopFrame
local f_checkout = f_shop.CheckoutFrame
local f_navigation = f_shop.NavigationFrame
local f_tabs = f_shop.ShopTabs
local b_template = script:WaitForChild("BatonTemplate")
local vip_template = script:WaitForChild("VIPTemplate")
local b_buy = f_checkout.BuyButton

--// Vars
local selectedItem = ""
local selectedCurrency = nil
local selectedTab = nil

--// Functions
function fn_getTabFromKey(key: string): ScrollingFrame
	for _, frame in ipairs(f_tabs:GetChildren()) do
		if frame:IsA("ScrollingFrame") and frame.Name:lower():find(key:lower()) then 
			return frame 
		end
	end 
	return nil
end

function fn_loadShop()
	local shopConfig = mod_shopHandler.getConfig()

	for key, data in shopConfig do
		local uiTab = fn_getTabFromKey(key)

		if uiTab then
			local isGamepass = key:lower():find("gamepass") or key:lower():find("pass")

			if not uiTab:FindFirstChild("Layout") then
				local layout = Instance.new("UIListLayout")
				layout.Name = "Layout"
				layout.SortOrder = Enum.SortOrder.LayoutOrder
				if isGamepass then
					layout.Padding = UDim.new(0, 0)
				else
					layout.FillDirection = Enum.FillDirection.Horizontal
					layout.HorizontalAlignment = Enum.HorizontalAlignment.Left
					layout.VerticalAlignment = Enum.VerticalAlignment.Top
					layout.Wraps = true
					layout.Padding = UDim.new(0, 0)
				end
				layout.Parent = uiTab
			end

			for item, iData in data.Items do
				local Owner = Ownership:FindFirstChild(iData.Name)
				if Owner and Owner.Value == true then 
					continue 
				end

				local templateToUse = isGamepass and vip_template or b_template
				local newItem = templateToUse:Clone()

				if isGamepass then
					newItem.Size = UDim2.new(1, 0, 0, 120)
				end

				if newItem:FindFirstChild("Icon") and iData.Image and tonumber(iData.Image) then
					newItem.Icon.Image = "rbxassetid://" .. iData.Image
				elseif newItem:FindFirstChild("Icon") then
					newItem.Icon.Image = ""
				end

				if newItem:FindFirstChild("NameLabel") then
					newItem.NameLabel.Text = iData.Name
				end

				if newItem:FindFirstChild("PriceLabel") then
					newItem.PriceLabel.Text = tostring(iData.Price) .. " " .. data.Currency
				end

				if newItem:FindFirstChild("DescriptionLabel") and iData.Desc then
					newItem.DescriptionLabel.Text = iData.Desc
				end

				newItem.Parent = uiTab
				newItem.Visible = true

				newItem.MouseButton1Down:Connect(function()
					selectedItem = iData.Name
					selectedCurrency = data.Currency
					selectedTab = uiTab

					if iData.Image and tonumber(iData.Image) then
						f_checkout.ImageLabel.Image = "rbxassetid://" .. iData.Image
					else
						f_checkout.ImageLabel.Image = ""
					end

					f_checkout.Category.Text = key
					f_checkout.Description.Text = iData.Desc
					f_checkout.Price.Text = iData.Price .. " " .. data.Currency
				end)
			end
		end
	end

	-- Load only batons into inventory
	for _, v in ipairs(Ownership:GetChildren()) do
		if v:IsA("BoolValue") and v.Value == true and mod_shopHandler.isBaton(v.Name) then
			local item = b_template:Clone()
			item.Parent = script.Parent.Parent.InventoryGUI.InventoryHolder.ScrollingFrame
			item.NameLabel.Text = v.Name
			item.PriceLabel.Text = "Owned"
			item.Name = v.Name
			item.Visible = true
		end
	end
end

--// BuyButton - only connect ONCE
b_buy.MouseButton1Click:Connect(function()
	if Ownership:FindFirstChild(selectedItem) and Ownership[selectedItem].Value then return end

	if not db and selectedItem ~= "" and selectedCurrency ~= nil then
		db = true
		rev_buyItem:FireServer(selectedItem)

		task.wait(2)

		-- Remove item from shop UI (only for batons)
		if selectedTab and mod_shopHandler.isBaton(selectedItem) then
			for _, shopItem in ipairs(selectedTab:GetChildren()) do
				if shopItem:IsA("ImageButton") or shopItem:IsA("TextButton") then
					if shopItem:FindFirstChild("NameLabel") and shopItem.NameLabel.Text == selectedItem then
						shopItem:Destroy()
					end
				end
			end
		end

		-- Add to inventory UI (only for batons)
		if mod_shopHandler.isBaton(selectedItem) then
			local inventoryUI = script.Parent.Parent.InventoryGUI.InventoryHolder.ScrollingFrame
			local newInventoryItem = b_template:Clone()
			newInventoryItem.Parent = inventoryUI
			newInventoryItem.NameLabel.Text = selectedItem
			newInventoryItem.PriceLabel.Text = "Owned"
			newInventoryItem.Name = selectedItem
			newInventoryItem.Visible = true
		end

		db = false
	end
end)

--// Listeners
rev_Ready.OnClientEvent:Connect(fn_loadShop)

Wait are you handling UIs from the server?

Yes I didnt make it it was a scripter i hired

Oh no.

You might want to find someone else :sob:

Is it a bad thing I got that system done long ago I hope its not too bad

Usually you want to handle UI systems locally.

Wait I’m confused, are your scripts server scripts? They seem like client scripts.

I think I see the issue though, you need to call fn_loadShop I think?

Nevermind sorry its a client script I barely have any scripting experience and thought it was a server one

Nevermind sorry its a client script I barely have any scripting experience and thought it was a server one shophandler is a module

Could you send over the place file?

By the way, I really recommend you actually get a better Datastore system such as ProfileService or DataStore2. The thing is that it might be nice, but loading problems may just be slight flaws. In other words, these modules really help and take the HUGE load of DSS off your back.

They’ve mentioned they don’t have scripting experience, I think they’ll need to start with the basics first :sweat_smile:

1 Like

Ah ok thats understandable but once you get a basic idea, watch some tutorials. That script legit looks like enchantment table :speaking_head:

1 Like