.Changed function not firing upon joining

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)

ReplicatedFirst.GetInventory:FireServer(Player.UserId)
Thanks in advance

The solution to this is to use the RemoteEvent and not DataStore2.

No no It doesn’t work when the player joins but it works when the string value gets changed

Hi.

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.

1 Like

Thanks although this sounds confusing to do :confused:

Since Im still getting used to using parameters when using functions and remote events

Let me help you out then!

-- 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)

I did everything you said however I might’ve made a mistake in the server script as Im getting an error
image
Script:

Players.PlayerAdded:Connect(function(player)
	local InventoryStore = DataStore2("Inventory", player)
	
	local replicatedDataFolder = Instance.new("Folder")
	replicatedDataFolder.Parent = ReplicatedStorage.ReplicatedData
	replicatedDataFolder.Name = player.UserId
	
	local InventoryString = Instance.new("StringValue")
	InventoryString.Parent = replicatedDataFolder
	InventoryString.Name = "Inventory"
	
	local InventoryData = InventoryStore:Get({})
	InventoryString.Value = HttpService:JSONEncode(InventoryData)
	
	--[[
	InventoryStore:OnUpdate(function(decodedData)
		InventoryString.Value = HttpService:JSONEncode(decodedData)
	end)
	]]--
	
	SendData:FireClient(InventoryData)
end)

The error goes to the FireClient

Can you tell me which line is line 29?

Ops:

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.

SendData:FireClient(Player,InventoryData)

probably because the data is loaded before the client loads, so changed never fires

to fix that you would just duplicate the code and put it in the script normally

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 :confused:

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)

“Set amount” doesnt print

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.

It works, thank you very much for your help!-

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.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.