Hi there,
I have a particular issue in my game by which player data (character skins) is able to be saved to the server, but this information has trouble being illustrated in a GUI (shop/inventory) in two noted situations. I will use a test user to illustrate this problem:
- When Player 2 enters the server, the datastore recalls that they had previously bought a skin
(“ZT-B”), as indicated in their SkinInventory folder. However, when Player 2 opens their inventory, the skin is not there. On the other hand, they are able to find their saved skin in the shop (intended feature, but the skin shows up in one place as opposed to both places simultaneously). See images below:
- For Player 2, shop skins appear as intended before the round starts. However, when the round ends, they cannot find any skins in the shop or their inventory. Again, Player 2 has the values in the SkinInventory folder. Keep in mind that there are team-changing activities in the background…
I do not understand what is going on. I have been trying to work around this issue for many months, and it’s doing my head in. If you have any insight, please share! From what I understand, my datastore works sufficiently, but there’s a communication issue between player data and the related gui.
There are two scripts involved in this process - one local and the other is server-sided.
Shop (Local Script):
local Shop = script.Parent
local HUD = Shop.Parent.Parent
local Inventory = HUD.Inventory.Inventory
local InventoryItemTemplate = Inventory.InventoryGUI:WaitForChild("Template")
local InventoryScrollingFrame = Inventory:WaitForChild("ScrollingSkinLayout")
local Home = Shop:WaitForChild("Home")
local Skins = Shop:WaitForChild("Skins")
local HomeButton = Shop:WaitForChild("Home Button")
local SkinsButton = Shop:WaitForChild("Skins Button")
local KillEffects = Shop:WaitForChild("Kill Effects Button")
local SpecialisationsButton = Shop:WaitForChild("Malware Specialisations Button")
local ItemTemplate = script:WaitForChild("Template") -- Skin template/frame is inside the script
local UIChangeSFX = script["UI Change"]
-- Inventory
HUD:WaitForChild("InventoryToggle").MouseButton1Click:Connect(function()
HUD:WaitForChild("Inventory").Inventory.Visible = not HUD:WaitForChild("Inventory").Inventory.Visible
UIChangeSFX:Play()
end)
function AddToFrame(v) -- We want to bring in the name of the Character into each frame, which is unique to that frame alone
local Frame = InventoryItemTemplate:Clone()
Frame.Name = v.Name
Frame.Title.Text = v.Name
Frame.Parent = InventoryScrollingFrame
Frame.Icon.Image = v.HumanoidRootPart.MALWAREGUI.MALWARE.Image
if game.Players.LocalPlayer.SkinInventory:FindFirstChild(v.Name) then
Frame.Cost.Text = "Owned"
end
if game.Players.LocalPlayer.EquippedSkin.Value == v.Name then
Frame.Cost.Text = "Equipped"
end
Frame.Cost.MouseButton1Click:Connect(function()
local Result = game.ReplicatedStorage.AddToInventory:InvokeServer(v.Name, "Skin")
if Result == "Bought" then
Frame.Cost.Text = "Equipped"
print(Result)
for _, Object in pairs(InventoryScrollingFrame:GetChildren()) do
if Object:IsA("Frame") and Object:FindFirstChild("Status") then
if game.Players.LocalPlayer.SkinInventory:FindFirstChild(Object.Name) then
Object.Cost.Text = "Owned"
end
end
end
Frame.Cost.Text = "Equipped"
end
end)
end
-- Shop
HUD:WaitForChild("ShopToggle").MouseButton1Click:Connect(function()
HUD:WaitForChild("Shop").Shop.Visible = not HUD:WaitForChild("Shop").Shop.Visible
UIChangeSFX:Play()
end)
HomeButton.MouseButton1Click:Connect(function()
Skins.Visible = false
UIChangeSFX:Play()
Home.Visible = true
end)
SkinsButton.MouseButton1Click:Connect(function()
Home.Visible = false
UIChangeSFX:Play()
Skins.Visible = true
end)
local SkinsData = game.ReplicatedStorage.Skins:GetChildren() -- Returns a table of all the skins in the game
function CreateFrame(Name, Cost, Object, Parent) -- Finding image within object itself to display
local Frame = ItemTemplate:Clone()
Frame.Name = Name
Frame.Title.Text = Name
Frame.Cost.Text = Cost
Frame.Icon.Image = Object.HumanoidRootPart.MALWAREGUI.MALWARE.Image
Frame.Parent = Parent
return Frame
end
function AddSkins(Data) -- Loops through all skins and creates individual cells for them
for i, v in pairs(Data) do
local Frame = CreateFrame(v.Name, v.Cost.Value, v, Skins.ScrollingSkinLayout.Folder) -- Adding criteria for the UIGridLayout
if game.Players.LocalPlayer.SkinInventory:FindFirstChild(v.Name) then
Frame.Cost.Text = "Owned"
end
if game.Players.LocalPlayer.EquippedSkin.Value == v.Name then
Frame.Cost.Text = "Equipped"
end
Frame.Cost.MouseButton1Click:Connect(function()
local Result = game.ReplicatedStorage.BuyItem:InvokeServer(v.Name, "Skin")
print(Result)
if Result == "Bought" then -- if Purchase was a Success
Frame.Cost.Text = "Owned"
AddToFrame(v)
elseif Result == "Equipped" then -- Skin is Equipped
print(Result)
for _, Object in pairs(Skins.ScrollingSkinLayout.Folder:GetChildren()) do
if Object:IsA("Frame") and Object:FindFirstChild("Cost") then
if game.Players.LocalPlayer.SkinInventory:FindFirstChild(Object.Name) then
Object.Cost.Text = "Owned"
end
end
end
Frame.Cost.Text = "Equipped"
end
end)
end
end
game.ReplicatedStorage.SendData.OnClientEvent:Connect(function()
AddSkins(SkinsData)
end)
Events (Server Script)
-- Buy from Shop
game.ReplicatedStorage.BuyItem.OnServerInvoke = function(Player, ItemName, ItemType)
local Item
local InInventory
if ItemType == "Skin" then
Item = game.ReplicatedStorage.Skins:FindFirstChild(ItemName)
if Player.SkinInventory:FindFirstChild(ItemName) then
InInventory = true
print("placed into inventory")
end
end
if Item then
if Item:FindFirstChild("Cost") then
if not InInventory then
if Item.Cost.Value <= Player.Credits.Value then
print("this can be bought")
Player.Credits.Value = Player.Credits.Value - Item.Cost.Value
local StringValue = Instance.new("StringValue")
StringValue.Name = Item.Name
if ItemType == "Skin" then
StringValue.Parent = Player.SkinInventory
end
return "Bought"
else
return "Failed"
end
else
-- Item is already owned
print("you already own this skin")
if ItemType == "Skin" then
Player.EquippedSkin.Value = ItemName
end
return "Equipped"
end
end
end
end
-- Make Inventory item equippable
game.ReplicatedStorage.AddToInventory.OnServerInvoke = function(Player, ItemName, ItemType)
local Item
local InInventory
if ItemType == "Skin" then
Item = game.ReplicatedStorage.Skins:FindFirstChild(ItemName)
if Player.SkinInventory:FindFirstChild(ItemName) then
InInventory = true
end
end
if Item then
if Item:FindFirstChild("Cost") then
if InInventory then
if ItemType == "Skin" then
Player.EquippedSkin.Value = ItemName
end
return "bought"
else
return "failed"
end
else
-- Equip it!
print("you already own this item")
if ItemType == "Skin" then
Player.EquippedSkin.Value = ItemName
end
return "equipped"
end
end
end