Hello, Im using datastore2 to save my inventory in a table. This table is a string value inside a folder in ReplicatedStorage however when the player joins this .Changed function does not fire for some odd reason (I was debugging and put prints inside the function and they did not print)
Script:
local Player = game.Players.LocalPlayer
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local InventoryGui = script.Parent
local Container = InventoryGui:WaitForChild("InventoryStorage")
local ItemProps = require(ReplicatedStorage.Modules.ItemProperties)
local RarityColours = require(ReplicatedStorage.Modules.ItemProperties.RarityColours)
local DataFolder = ReplicatedStorage.ReplicatedData:WaitForChild(Player.UserId)
DataFolder.Inventory.Changed:Connect(function(encodedData)
local dataTable = HttpService:JSONDecode(encodedData)
for ItemName, amount in pairs(dataTable) do
local ItemFrame = Container:FindFirstChild(ItemName)
if (not ItemFrame) then
ItemFrame = ReplicatedStorage.ItemFrame:Clone()
ItemFrame.Parent = Container
ItemFrame.Name = ItemName
ItemFrame.Image = ItemProps[ItemName].ImageId
local ItemRarity = ItemProps[ItemName].Rarity
local RarityItem = RarityColours[ItemRarity]
ItemFrame.ColourRarity.BackgroundColor3 = RarityItem
end
ItemFrame.AmountLabel.Text = "x"..amount
if amount <= 0 then
ItemFrame:Destroy()
end
end
end)
I’ve recently changed from DataStore2 over to ProfileService. If you’re not worried about duplicate-items (by trading), then stick to DataStore2. Otherwise I would suggest ProfileService or create your own Session-locking system. When that is said.
When the player joins the game, instead of having all their items in a folder, you instead just fire the items-dictionary directly to the client.
Even if the client has not yet initialized the remote, the remote signal will wait until the client has loaded the signal, and is ready to do whatever you want to do with it on the client.
You then fire a signal to the client, each time you’ve removed or added items to their inventory. I would suggest a remote for both. The client then updates what items is visible in their inventory system themself.
Note: Just fire the AddItem remote to the client when they join (after you’ve loaded their inventory on the server). Also make sure that it’s a table/dictionary you send to the client each time, so you don’t send a remote for each item, since it will overload the remote if you add 20-50 items at once.
-- this is what the players inventory looks like in this case:
local Inv = {
["Carrots"] = {Quantity=4,Category="Vegestable"},
["Iron"] = {Quantity=2,Category="Mineral"},
}
-- Server Script
-- In your playerAdded function
local Inventory = dataStore:Get(default_data) -- Define which datastore is the players inventory yourself
AddItem:FireClient(Inventory)
-- Local Script
local InventoryFrame -- Frame you have your inventory items in
local function CreateNewItemFrame(ItemName, ItemData)
local NewItemFrame = ItemFrameTemplate:Clone()
NewItemFrame.Name = ItemName
NewItemFrame.QuantityTextLabel.Text = ItemData.Quantity
NewItemFrame.CategoryTextLabel.Text = ItemData.Category
NewItemFrame.Parent = InventoryFrame
end
local function UpdateItemFrame(ItemFrame)
ItemFrame.QuantityTextLabel.Text = ItemData.Quantity -- I suppose you only update quantity on already existing frames
end
AddItem.OnClientEvent:Connect(function(Inventory)
for ItemName, ItemData in Inventory do -- We do not need to define "pairs/ipairs" but if you want to, feel free to do so. New feature added.
local ItemFrame = InventoryFrame:FindFirstChild(ItemName)
if not ItemFrame then
CreateItemFrameFunction(ItemName, ItemData)
else
UpdateItemFrameFunction(ItemFrame)
end
end
end)
You forgot to add Player as the first argument in the remote on the server. (I also did in my sample)
The first argument on the server for FireClient, is the client it should send the remote signal to.
Yep that can be the case for the .Changed function for his original method. But right now I am trying to get him away from the method of having objects inside the player, to replicate the data.
Alright I fixxed it however Im confused on the client script now
SendData.OnClientEvent:Connect(function(encodedData)
print("a")
local dataTable = HttpService:JSONDecode(encodedData)
for ItemName, amount in pairs(dataTable) do
print("looping")
local ItemFrame = Container:FindFirstChild(ItemName)
if not ItemFrame then
CreateNewItemFrame(ItemName)
else
UpdateItemFrame(ItemFrame, amount)
end
--[[
if amount <= 0 then
ItemFrame:Destroy()
end
]]--
end
end)
For some reason it doesn’t loop however “a” prints
So, with my method you don’t have to pack/unpack the dataTable with JSONDecode & JSONEncode, so send the raw table to the client, and use the raw table in the for-loop.
alright it works!! however the amount is not being set to the text label, any solutions?
local function CreateNewItemFrame(ItemName)
local ItemFrame = ReplicatedStorage.ItemFrame:Clone()
ItemFrame.Parent = Container
ItemFrame.Name = ItemName
ItemFrame.Image = ItemProps[ItemName].ImageId
local ItemRarity = ItemProps[ItemName].Rarity
local RarityItem = RarityColours[ItemRarity]
ItemFrame.ColourRarity.BackgroundColor3 = RarityItem
end
local function UpdateItemFrame(ItemFrame, amount)
ItemFrame.AmountLabel.Text = "x"..amount
print("set amount")
end
SendData.OnClientEvent:Connect(function(Inventory)
for ItemName, amount in pairs(Inventory) do
local ItemFrame = Container:FindFirstChild(ItemName)
if not ItemFrame then
CreateNewItemFrame(ItemName)
else
UpdateItemFrame(ItemFrame, amount)
end
if amount <= 0 then
ItemFrame:Destroy()
end
end
end)
If the ItemFrame is not already found within the Container, then it creates a new ItemFrame. You should set the amount directly in the CreateNewFrame aswell, since you only want to use the UpdateItemFrame, when a ItemFrame within Container, has the same name as the Inventory Item you try to add to their Container-Inventory, and you only want to change the “Amount”.
Edit: Also when creating a new object, set all it’s properties first, before parenting it elsewhere.
No problem. If you want to use that remote for removing items aswell, check if the item should be removed, inside the UpdateItemFrame function. Also make sure that it does not create a frame, if you removed an item, and the ItemFrame wasn’t found. Personally I would create a seperate Remote for removing items.